mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-24 19:20:29 +02:00
Merge remote-tracking branch 'origin/master' into activity
# Conflicts: # note_kfet/urls.py # templates/base.html
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
{% load static i18n pretty_money static %}
|
||||
{% load static i18n pretty_money static getenv perms %}
|
||||
{% comment %}
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% endcomment %}
|
||||
@ -46,12 +46,20 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/turbolinks/5.2.0/turbolinks.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="/static/js/base.js"></script>
|
||||
|
||||
{# Si un formulaire requiert des données supplémentaires (notamment JS), les données sont chargées #}
|
||||
{% if form.media %}
|
||||
{{ form.media }}
|
||||
{% endif %}
|
||||
|
||||
<style>
|
||||
.validate:hover {
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% block extracss %}{% endblock %}
|
||||
</head>
|
||||
<body class="d-flex w-100 h-100 flex-column">
|
||||
@ -66,24 +74,36 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavDropdown">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'note:consos' %}"><i class="fa fa-coffee"></i> Consos</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'member:club_list' %}"><i class="fa fa-users"></i> Clubs</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'activity:activity_list' %}"><i class="fa fa-calendar"></i> Activités</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'note:template_list' %}"><i class="fa fa-coffee"></i> Bouton</a>
|
||||
</li>
|
||||
{% if "note.transactiontemplate"|not_empty_model_list %}
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'note:consos' %}"><i class="fa fa-coffee"></i> {% trans 'Consumptions' %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'note:transfer' %}"><i class="fa fa-exchange"></i>{% trans 'Transfer' %} </a>
|
||||
</li>
|
||||
{% if "member.club"|not_empty_model_list %}
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'member:club_list' %}"><i class="fa fa-users"></i> {% trans 'Clubs' %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "activity.activity"|not_empty_model_list %}
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'activity:activity_list' %}"><i class="fa fa-calendar"></i> {% trans 'Activities' %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if "treasury.invoice"|not_empty_model_change_list %}
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{% url 'treasury:invoice_list' %}"><i class="fa fa-money"></i>{% trans 'Treasury' %} </a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-user"></i> {{ user.username }} ({{ user.note.balance | pretty_money }})
|
||||
<i class="fa fa-user"></i>
|
||||
<span id="user_balance">{{ user.username }} ({{ user.note.balance | pretty_money }})</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right"
|
||||
aria-labelledby="navbarDropdownMenuLink">
|
||||
@ -112,6 +132,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</nav>
|
||||
<div class="container-fluid my-3" style="max-width: 1600px;">
|
||||
{% block contenttitle %}<h1>{{ title }}</h1>{% endblock %}
|
||||
<div id="messages"></div>
|
||||
{% block content %}
|
||||
<p>Default content...</p>
|
||||
{% endblock content %}
|
||||
@ -125,7 +146,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
class="form-inline">
|
||||
<span class="text-muted mr-1">
|
||||
NoteKfet2020 —
|
||||
<a href="mailto:tresorie.bde@lists.crans.org"
|
||||
<a href="mailto:{{ "CONTACT_EMAIL" | getenv }}"
|
||||
class="text-muted">Nous contacter</a> —
|
||||
</span>
|
||||
{% csrf_token %}
|
||||
@ -155,6 +176,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
CSRF_TOKEN = "{{ csrf_token }}";
|
||||
</script>
|
||||
|
||||
{% block extrajavascript %}
|
||||
{% endblock extrajavascript %}
|
||||
</body>
|
||||
|
99
templates/cas_server/base.html
Normal file
99
templates/cas_server/base.html
Normal file
@ -0,0 +1,99 @@
|
||||
{% load i18n %}{% load static %}{% get_current_language as LANGUAGE_CODE %}<!DOCTYPE html>
|
||||
<html{% if LANGUAGE_CODE %} lang="{{LANGUAGE_CODE}}"{% endif %}>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge" /><![endif]-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}{% trans "Central Authentication Service" %}{% endblock %}</title>
|
||||
<link href="{{settings.CAS_COMPONENT_URLS.bootstrap3_css}}" rel="stylesheet">
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.html5shiv}}"></script>
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.respond}}"></script>
|
||||
<![endif]-->
|
||||
{% if settings.CAS_FAVICON_URL %}<link rel="shortcut icon" href="{{settings.CAS_FAVICON_URL}}" />{% endif %}
|
||||
<link href="{% static "cas_server/styles.css" %}" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div class="container">
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<h1 id="app-name">
|
||||
{% if settings.CAS_LOGO_URL %}<img src="{{settings.CAS_LOGO_URL}}" alt="cas-logo" />{% endif %}
|
||||
Authentification Note Kfet 2020</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-12"></div>
|
||||
<div class="col-lg-6 col-md-6 col-sm-8 col-xs-12">
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
{% for msg in CAS_INFO_RENDER %}
|
||||
<div class="alert alert-{{msg.type}}{% if msg.discardable %} alert-dismissable{% endif %}">
|
||||
{% if msg.discardable %}<button type="button" class="close" data-dismiss="alert" aria-hidden="true" id="info-{{msg.name}}">×</button>{% endif %}
|
||||
<p>{{msg.message}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if settings.CAS_NEW_VERSION_HTML_WARNING and upgrade_available %}
|
||||
<div class="alert alert-info alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true" id="alert-version">×</button>
|
||||
<p>{% blocktrans %}A new version of the application is available. This instance runs {{VERSION}} and the last version is {{LAST_VERSION}}. Please consider upgrading.{% endblocktrans %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% block ante_messages %}{% endblock %}
|
||||
{% for message in messages %}
|
||||
<div {% spaceless %}
|
||||
{% if message.level == message_levels.DEBUG %}
|
||||
class="alert alert-warning"
|
||||
{% elif message.level == message_levels.INFO %}
|
||||
class="alert alert-info"
|
||||
{% elif message.level == message_levels.SUCCESS %}
|
||||
class="alert alert-success"
|
||||
{% elif message.level == message_levels.WARNING %}
|
||||
class="alert alert-warning"
|
||||
{% else %}
|
||||
class="alert alert-danger"
|
||||
{% endif %}
|
||||
{% endspaceless %}>
|
||||
<p>{{message}}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-3 col-sm-2 col-xs-0"></div>
|
||||
</div>
|
||||
</div> <!-- /container -->
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
{% if settings.CAS_SHOW_POWERED %}
|
||||
<div id="footer">
|
||||
<p><a class="text-muted" href="https://pypi.org/project/django-cas-server/">django-cas-server powered</a></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.jquery}}"></script>
|
||||
<script src="{{settings.CAS_COMPONENT_URLS.bootstrap3_js}}"></script>
|
||||
<script src="{% static "cas_server/functions.js" %}"></script>
|
||||
<script type="text/javascript">
|
||||
{% if settings.CAS_NEW_VERSION_HTML_WARNING and upgrade_available %}
|
||||
discard_and_remember("#alert-version", "cas-alert-version", "{{LAST_VERSION}}");
|
||||
{% endif %}
|
||||
{% for msg in CAS_INFO_RENDER %}
|
||||
{% if msg.discardable %}
|
||||
discard_and_remember("#info-{{msg.name}}", "cas-info-{{msg.name}}", "{{msg.hash}}");
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% block javascript_inline %}{% endblock %}
|
||||
</script>
|
||||
{% block javascript %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
<!--
|
||||
Powered by django-cas-server version {{VERSION}}
|
||||
|
||||
Pypi: https://pypi.org/project/django-cas-server/
|
||||
github: https://github.com/nitmir/django-cas-server
|
||||
-->
|
26
templates/cas_server/form.html
Normal file
26
templates/cas_server/form.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% load cas_server %}
|
||||
{% for error in form.non_field_errors %}
|
||||
<div class="alert alert-danger alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
{{error}}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% for field in form %}{% if not field|is_hidden %}
|
||||
<div class="form-group
|
||||
{% if not form.non_field_errors %}
|
||||
{% if field.errors %} has-error
|
||||
{% elif form.cleaned_data %} has-success
|
||||
{% endif %}
|
||||
{% endif %}"
|
||||
>{% spaceless %}
|
||||
{% if field|is_checkbox %}
|
||||
<div class="checkbox"><label for="{{field.auto_id}}">{{field}}{{field.label}}</label></div>
|
||||
{% else %}
|
||||
<label class="control-label" for="{{field.auto_id}}">{{field.label}}</label>
|
||||
{{field}}
|
||||
{% endif %}
|
||||
{% for error in field.errors %}
|
||||
<span class="help-block">{{error}}</span>
|
||||
{% endfor %}
|
||||
{% endspaceless %}</div>
|
||||
{% else %}{{field}}{% endif %}{% endfor %}
|
21
templates/cas_server/logged.html
Normal file
21
templates/cas_server/logged.html
Normal file
@ -0,0 +1,21 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
<div class="alert alert-success" role="alert">{% blocktrans %}<h3>Log In Successful</h3>You have successfully logged into the Central Authentication Service.<br/>For security reasons, please Log Out and Exit your web browser when you are done accessing services that require authentication!{% endblocktrans %}</div>
|
||||
<form class="form-signin" method="get" action="logout">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="all" value="1">{% trans "Log me out from all my sessions" %}
|
||||
</label>
|
||||
</div>
|
||||
{% if settings.CAS_FEDERATE and request.COOKIES.remember_provider %}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="forget_provider" value="1">{% trans "Forget the identity provider" %}
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<button class="btn btn-danger btn-block btn-lg" type="submit">{% trans "Logout" %}</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
33
templates/cas_server/login.html
Normal file
33
templates/cas_server/login.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block ante_messages %}
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<h2 class="form-signin-heading">{% trans "Please log in" %}</h2>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<div class="alert alert-warning">
|
||||
{% trans "If you don't have any Note Kfet account, please follow <a href='/accounts/signup'>this link to sign up</a>." %}
|
||||
</div>
|
||||
<form class="form-signin" method="post" id="login_form"{% if post_url %} action="{{post_url}}"{% endif %}>
|
||||
{% csrf_token %}
|
||||
{% include "cas_server/form.html" %}
|
||||
{% if auto_submit %}<noscript>{% endif %}
|
||||
<button class="btn btn-primary btn-block btn-lg" type="submit">{% trans "Login" %}</button>
|
||||
{% if auto_submit %}</noscript>{% endif %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% block javascript_inline %}
|
||||
jQuery(function( $ ){
|
||||
$("#id_warn").click(function(e){
|
||||
if($("#id_warn").is(':checked')){
|
||||
createCookie("warn", "on", 10 * 365);
|
||||
} else {
|
||||
eraseCookie("warn");
|
||||
}
|
||||
});
|
||||
});{% if auto_submit %}
|
||||
document.getElementById('login_form').submit(); // SUBMIT FORM{% endif %}
|
||||
{% endblock %}
|
||||
|
7
templates/cas_server/logout.html
Normal file
7
templates/cas_server/logout.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
<div class="alert alert-success" role="alert">{{logout_msg}}</div>
|
||||
{% endblock %}
|
||||
|
5
templates/cas_server/proxy.xml
Normal file
5
templates/cas_server/proxy.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
|
||||
<cas:proxySuccess>
|
||||
<cas:proxyTicket>{{ticket}}</cas:proxyTicket>
|
||||
</cas:proxySuccess>
|
||||
</cas:serviceResponse>
|
59
templates/cas_server/samlValidate.xml
Normal file
59
templates/cas_server/samlValidate.xml
Normal file
@ -0,0 +1,59 @@
|
||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Header />
|
||||
<SOAP-ENV:Body>
|
||||
<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol"
|
||||
xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"
|
||||
IssueInstant="{{ IssueInstant }}"
|
||||
MajorVersion="1" MinorVersion="1" Recipient="{{ Recipient }}"
|
||||
ResponseID="{{ ResponseID }}">
|
||||
<Status>
|
||||
<StatusCode Value="samlp:Success">
|
||||
</StatusCode>
|
||||
</Status>
|
||||
<Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="{{ResponseID}}"
|
||||
IssueInstant="{{IssueInstant}}" Issuer="localhost" MajorVersion="1"
|
||||
MinorVersion="1">
|
||||
<Conditions NotBefore="{{IssueInstant}}" NotOnOrAfter="{{expireInstant}}">
|
||||
<AudienceRestrictionCondition>
|
||||
<Audience>
|
||||
{{Recipient}}
|
||||
</Audience>
|
||||
</AudienceRestrictionCondition>
|
||||
</Conditions>
|
||||
<AttributeStatement>
|
||||
<Subject>
|
||||
<NameIdentifier>{{username}}</NameIdentifier>
|
||||
<SubjectConfirmation>
|
||||
<ConfirmationMethod>
|
||||
urn:oasis:names:tc:SAML:1.0:cm:artifact
|
||||
</ConfirmationMethod>
|
||||
</SubjectConfirmation>
|
||||
</Subject>
|
||||
<Attribute AttributeName="authenticationDate" AttributeNamespace="http://www.ja-sig.org/products/cas/">
|
||||
<AttributeValue>{{auth_date}}</AttributeValue>
|
||||
</Attribute>
|
||||
<Attribute AttributeName="longTermAuthenticationRequestTokenUsed" AttributeNamespace="http://www.ja-sig.org/products/cas/">
|
||||
<AttributeValue>false</AttributeValue>{# we do not support long-term (Remember-Me) auth #}
|
||||
</Attribute>
|
||||
<Attribute AttributeName="isFromNewLogin" AttributeNamespace="http://www.ja-sig.org/products/cas/">
|
||||
<AttributeValue>{{is_new_login}}</AttributeValue>
|
||||
</Attribute>
|
||||
{% for name, value in attributes %} <Attribute AttributeName="{{name}}" AttributeNamespace="http://www.ja-sig.org/products/cas/">
|
||||
<AttributeValue>{{value}}</AttributeValue>
|
||||
</Attribute>
|
||||
{% endfor %} </AttributeStatement>
|
||||
<AuthenticationStatement AuthenticationInstant="{{IssueInstant}}"
|
||||
AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password">
|
||||
<Subject>
|
||||
<NameIdentifier>{{username}}</NameIdentifier>
|
||||
<SubjectConfirmation>
|
||||
<ConfirmationMethod>
|
||||
urn:oasis:names:tc:SAML:1.0:cm:artifact
|
||||
</ConfirmationMethod>
|
||||
</SubjectConfirmation>
|
||||
</Subject>
|
||||
</AuthenticationStatement>
|
||||
</Assertion>
|
||||
</Response>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
14
templates/cas_server/samlValidateError.xml
Normal file
14
templates/cas_server/samlValidateError.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<SOAP-ENV:Header />
|
||||
<SOAP-ENV:Body>
|
||||
<Response xmlns="urn:oasis:names:tc:SAML:1.0:protocol"
|
||||
xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"
|
||||
IssueInstant="{{ IssueInstant }}"
|
||||
MajorVersion="1" MinorVersion="1" Recipient="{{ Recipient }}"
|
||||
ResponseID="{{ ResponseID }}">
|
||||
<Status>
|
||||
<StatusCode Value="samlp:{{code}}">{{msg}}</StatusCode>
|
||||
</Status>
|
||||
</Response>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>
|
19
templates/cas_server/serviceValidate.xml
Normal file
19
templates/cas_server/serviceValidate.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
|
||||
<cas:authenticationSuccess>
|
||||
<cas:user>{{username}}</cas:user>
|
||||
<cas:attributes>
|
||||
<cas:authenticationDate>{{auth_date}}</cas:authenticationDate>
|
||||
<cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>{# we do not support long-term (Remember-Me) auth #}
|
||||
<cas:isFromNewLogin>{{is_new_login}}</cas:isFromNewLogin>
|
||||
{% for key, value in attributes %} <cas:{{key}}>{{value}}</cas:{{key}}>
|
||||
{% endfor %} </cas:attributes>
|
||||
<cas:attribute name="authenticationDate" value="{{auth_date}}"/>
|
||||
<cas:attribute name="longTermAuthenticationRequestTokenUsed" value="false"/>
|
||||
<cas:attribute name="isFromNewLogin" value="{{is_new_login}}"/>
|
||||
{% for key, value in attributes %} <cas:attribute name="{{key}}" value="{{value}}"/>
|
||||
{% endfor %}{% if proxyGrantingTicket %} <cas:proxyGrantingTicket>{{proxyGrantingTicket}}</cas:proxyGrantingTicket>
|
||||
{% endif %}{% if proxies %} <cas:proxies>
|
||||
{% for proxy in proxies %} <cas:proxy>{{proxy}}</cas:proxy>
|
||||
{% endfor %} </cas:proxies>
|
||||
{% endif %} </cas:authenticationSuccess>
|
||||
</cas:serviceResponse>
|
3
templates/cas_server/serviceValidateError.xml
Normal file
3
templates/cas_server/serviceValidateError.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
|
||||
<cas:authenticationFailure code="{{code}}">{{msg}}</cas:authenticationFailure>
|
||||
</cas:serviceResponse>
|
11
templates/cas_server/warn.html
Normal file
11
templates/cas_server/warn.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% extends "cas_server/base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<form class="form-signin" method="post">
|
||||
{% csrf_token %}
|
||||
{% include "cas_server/form.html" %}
|
||||
<button class="btn btn-primary btn-block btn-lg" type="submit">{% trans "Connect to the service" %}</button>
|
||||
</form>
|
||||
{% endblock %}
|
5
templates/django_filters/rest_framework/crispy_form.html
Normal file
5
templates/django_filters/rest_framework/crispy_form.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
|
||||
<h2>{% trans "Field filters" %}</h2>
|
||||
{% crispy filter.form %}
|
6
templates/django_filters/rest_framework/form.html
Normal file
6
templates/django_filters/rest_framework/form.html
Normal file
@ -0,0 +1,6 @@
|
||||
{% load i18n %}
|
||||
<h2>{% trans "Field filters" %}</h2>
|
||||
<form class="form" action="" method="get">
|
||||
{{ filter.form.as_p }}
|
||||
<button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
|
||||
</form>
|
1
templates/django_filters/widgets/multiwidget.html
Normal file
1
templates/django_filters/widgets/multiwidget.html
Normal file
@ -0,0 +1 @@
|
||||
{% for widget in widget.subwidgets %}{% include widget.template_name %}{% if forloop.first %}-{% endif %}{% endfor %}
|
@ -1,62 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load pretty_money %}
|
||||
{% block content %}
|
||||
<p><a class="btn btn-primary" href="{% url 'member:club_list' %}">Clubs</a></p>
|
||||
<h3 class="text-center"> Club {{ object.name }}</h3>
|
||||
<dl>
|
||||
<dt>{% trans 'Membership starts on' %}</dt>
|
||||
<dd>{{ club.membership_start }}</dd>
|
||||
<dt>{% trans 'Membership ends on' %}</dt>
|
||||
<dd>{{ club.membership_end }}</dd>
|
||||
<dt>{% trans 'Membership duration' %}</dt>
|
||||
<dd>{{ club.membership_duration }}</dd>
|
||||
<dt> Aliases </dt>
|
||||
<dd>{{ club.note.aliases_set.all }}</dd>
|
||||
<dt>{% trans 'balance' %}</dt>
|
||||
<dd>{{ club.note.balance | pretty_money }}</dd>
|
||||
{% extends "member/noteowner_detail.html" %}
|
||||
|
||||
</dl>
|
||||
{% block profile_info %}
|
||||
{% include "member/club_info.html" %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
<div class="btn-group" role="group">
|
||||
<a class="btn btn-primary" href="{% url 'member:club_add_member' pk=object.pk %}"> Ajouter des membres </a>
|
||||
<a class="btn btn-primary" href="{% url 'member:club_add_member' pk=object.pk %}"> Modifier les informations </a>
|
||||
<a class="btn btn-primary" href="{% url 'member:club_add_member' pk=object.pk %}"> Ajouter des roles </a>
|
||||
</div>
|
||||
|
||||
<div class="accordion" id="accordionExample">
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingOne">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
<i class="fa fa-users"></i> Membres du club
|
||||
</button>
|
||||
</h5>
|
||||
</div>
|
||||
|
||||
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
|
||||
<div class="card-body">
|
||||
|
||||
{% render_table member_list %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingTwo">
|
||||
<h5 class="mb-0">
|
||||
<button class="btn btn-link collapsed" type="button" data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
</button>
|
||||
</h5>
|
||||
</div>
|
||||
<div id="collapseTwo" class="collapse" aria-labelledby="headingTwo" data-parent="#accordionExample">
|
||||
<div class="card-body">
|
||||
{% render_table history_list %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block profile_content %}
|
||||
{% include "member/club_tables.html" %}
|
||||
{% endblock %}
|
||||
|
@ -1,11 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% block content %}
|
||||
<p><a class="btn btn-default" href="{% url 'note:template_list' %}">Template Listing</a></p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
<button class="btn btn-primary" type="submit">Submit</button>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
32
templates/member/club_info.html
Normal file
32
templates/member/club_info.html
Normal file
@ -0,0 +1,32 @@
|
||||
{% load i18n static pretty_money %}
|
||||
<div class="card bg-light shadow">
|
||||
<div class="card-top text-center">
|
||||
<a href="{% url 'member:club_update_pic' club.pk %}">
|
||||
<img src="{{ club.note.display_image.url }}" class="img-thumbnail mt-2" >
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body" id="profile_infos">
|
||||
<dl class="row">
|
||||
<dt class="col-xl-6">{% trans 'name'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ club.name}}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'membership start'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ club.membership_start }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'membership end'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ club.membership_end }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'membership duration'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ club.membership_duration }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'membership fee'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ club.membership_fee|pretty_money }}</dd>
|
||||
|
||||
<dt class="col-xl-6"><a href="{% url 'member:user_alias' club.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
|
||||
<dd class="col-xl-6 text-truncate">{{ object.note.alias_set.all|join:", " }}</dd>
|
||||
|
||||
<dt class="col-xl-3">{% trans 'email'|capfirst %}</dt>
|
||||
<dd class="col-xl-9"><a href="mailto:{{ club.email }}">{{ club.email}}</a></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
@ -1,15 +1,66 @@
|
||||
{% extends "base.html" %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
<a class="btn btn-primary" href="{% url 'member:club_create' %}">New Club</a>
|
||||
<div class="row justify-content-center mb-4">
|
||||
<div class="col-md-10 text-center">
|
||||
<h4>
|
||||
{% trans "search clubs" %}
|
||||
</h4>
|
||||
<input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved();return(false);" id="search_field"/>
|
||||
<hr>
|
||||
<a class="btn btn-primary text-center my-4" href="{% url 'member:club_create' %}">{% trans "Créer un club" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-10">
|
||||
<div class="card card-border shadow">
|
||||
<div class="card-header text-center">
|
||||
<h5> {% trans "club listing "%}</h5>
|
||||
</div>
|
||||
<div class="card-body px-0 py-0" id="club_table">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block extrajavascript %}
|
||||
<script type="text/javascript">
|
||||
|
||||
function getInfo() {
|
||||
var asked = $("#search_field").val();
|
||||
/* on ne fait la requête que si on a au moins un caractère pour chercher */
|
||||
var sel = $(".table-row");
|
||||
if (asked.length >= 1) {
|
||||
$.getJSON("/api/members/club/?format=json&search="+asked, function(buttons){
|
||||
let selected_id = buttons.results.map((a => "#row-"+a.id));
|
||||
console.log(selected_id.join());
|
||||
$(".table-row,"+selected_id.join()).show();
|
||||
$(".table-row").not(selected_id.join()).hide();
|
||||
|
||||
});
|
||||
}else{
|
||||
// show everything
|
||||
$('table tr').show();
|
||||
}
|
||||
}
|
||||
var timer;
|
||||
var timer_on;
|
||||
/* Fontion appelée quand le texte change (délenche le timer) */
|
||||
function search_field_moved(secondfield) {
|
||||
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout("getInfo(" + secondfield + ")", 300);
|
||||
}
|
||||
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
|
||||
timer = setTimeout("getInfo(" + secondfield + ")", 300);
|
||||
timer_on = true;
|
||||
}
|
||||
}
|
||||
|
||||
// clickable row
|
||||
$(document).ready(function($) {
|
||||
$(".table-row").click(function() {
|
||||
window.document.location = $(this).data("href");
|
||||
|
10
templates/member/club_picture_update.html
Normal file
10
templates/member/club_picture_update.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% extends "member/club_detail.html" %}
|
||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
|
||||
|
||||
{% block profile_info %}
|
||||
{% include "member/club_info.html" %}
|
||||
{% endblock%}
|
||||
|
||||
{% block profile_content%}
|
||||
{% include "member/picture_update.html" %}
|
||||
{% endblock%}
|
31
templates/member/club_tables.html
Normal file
31
templates/member/club_tables.html
Normal file
@ -0,0 +1,31 @@
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
<div class="accordion shadow" id="accordionProfile">
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="btn btn-link stretched-link font-weight-bold"
|
||||
data-toggle="collapse" data-target="#clubListCollapse"
|
||||
aria-expanded="true" aria-controls="clubListCollapse">
|
||||
<i class="fa fa-users"></i> {% trans "Member of the Club" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="clubListCollapse" class="collapse show" style="overflow:auto hidden" aria-labelledby="clubListHeading" data-parent="#accordionProfile">
|
||||
{% render_table member_list %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="historyListHeading">
|
||||
<a class="btn btn-link stretched-link collapsed font-weight-bold"
|
||||
data-toggle="collapse" data-target="#historyListCollapse"
|
||||
aria-expanded="false" aria-controls="historyListCollapse">
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="historyListCollapse" class="collapse" style="overflow:auto hidden" aria-labelledby="historyListHeading" data-parent="#accordionProfile">
|
||||
<div id="history_list">
|
||||
{% render_table history_list %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
27
templates/member/noteowner_detail.html
Normal file
27
templates/member/noteowner_detail.html
Normal file
@ -0,0 +1,27 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load pretty_money %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3 mb-4">
|
||||
{% block profile_info %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
{% block profile_content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script>
|
||||
function refreshhistory() {
|
||||
$("#history_list").load("{% url 'member:user_detail' pk=object.pk %} #history_list");
|
||||
$("#profile_infos").load("{% url 'member:user_detail' pk=object.pk %} #profile_infos");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
95
templates/member/picture_update.html
Normal file
95
templates/member/picture_update.html
Normal file
@ -0,0 +1,95 @@
|
||||
{% load i18n crispy_forms_tags %}
|
||||
{% block profile_content %}
|
||||
<div class="text-center">
|
||||
<form method="post" enctype="multipart/form-data" id="formUpload">
|
||||
{% csrf_token %}
|
||||
{{ form |crispy }}
|
||||
</form>
|
||||
</div>
|
||||
<!-- MODAL TO CROP THE IMAGE -->
|
||||
<div class="modal fade" id="modalCrop">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<img src="" id="modal-image" style="max-width: 100%;">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="btn-group pull-left" role="group">
|
||||
<button type="button" class="btn btn-default" id="js-zoom-in">
|
||||
<span class="glyphicon glyphicon-zoom-in"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default js-zoom-out">
|
||||
<span class="glyphicon glyphicon-zoom-out"></span>
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Nevermind</button>
|
||||
<button type="button" class="btn btn-primary js-crop-and-upload">Crop and upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extracss %}
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.css" rel="stylesheet">
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript%}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery-cropper@1.0.1/dist/jquery-cropper.min.js"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
/* SCRIPT TO OPEN THE MODAL WITH THE PREVIEW */
|
||||
$("#id_image").change(function (e) {
|
||||
if (this.files && this.files[0]) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
$("#modal-image").attr("src", e.target.result);
|
||||
$("#modalCrop").modal("show");
|
||||
}
|
||||
reader.readAsDataURL(this.files[0]);
|
||||
}
|
||||
});
|
||||
|
||||
/* SCRIPTS TO HANDLE THE CROPPER BOX */
|
||||
var $image = $("#modal-image");
|
||||
var cropBoxData;
|
||||
var canvasData;
|
||||
$("#modalCrop").on("shown.bs.modal", function () {
|
||||
$image.cropper({
|
||||
viewMode: 1,
|
||||
aspectRatio: 1/1,
|
||||
minCropBoxWidth: 200,
|
||||
minCropBoxHeight: 200,
|
||||
ready: function () {
|
||||
$image.cropper("setCanvasData", canvasData);
|
||||
$image.cropper("setCropBoxData", cropBoxData);
|
||||
}
|
||||
});
|
||||
}).on("hidden.bs.modal", function () {
|
||||
cropBoxData = $image.cropper("getCropBoxData");
|
||||
canvasData = $image.cropper("getCanvasData");
|
||||
$image.cropper("destroy");
|
||||
});
|
||||
|
||||
$(".js-zoom-in").click(function () {
|
||||
$image.cropper("zoom", 0.1);
|
||||
});
|
||||
|
||||
$(".js-zoom-out").click(function () {
|
||||
$image.cropper("zoom", -0.1);
|
||||
});
|
||||
|
||||
/* SCRIPT TO COLLECT THE DATA AND POST TO THE SERVER */
|
||||
$(".js-crop-and-upload").click(function () {
|
||||
var cropData = $image.cropper("getData");
|
||||
$("#id_x").val(cropData["x"]);
|
||||
$("#id_y").val(cropData["y"]);
|
||||
$("#id_height").val(cropData["height"]);
|
||||
$("#id_width").val(cropData["width"]);
|
||||
$("#formUpload").submit();
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
19
templates/member/profile_alias.html
Normal file
19
templates/member/profile_alias.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends "member/profile_detail.html" %}
|
||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
|
||||
|
||||
{% block profile_content %}
|
||||
<div class="d-flex justify-content-center">
|
||||
<form class=" text-center form my-2" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form |crispy }}
|
||||
<button class="btn btn-primary mx-2" type="submit">
|
||||
{% trans "Add alias" %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card bg-light shadow">
|
||||
<div class="card-body">
|
||||
{% render_table aliases %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -1,77 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% load i18n static pretty_money django_tables2 %}
|
||||
{% extends "member/noteowner_detail.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3 mb-4">
|
||||
<div class="card bg-light shadow">
|
||||
<img src="{{ object.note.display_image }}" class="card-img-top" alt="">
|
||||
<div class="card-body">
|
||||
<dl class="row">
|
||||
<dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt>
|
||||
<dd class="col-xl-6">{{ object.last_name }} {{ object.first_name }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'username'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.username }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">
|
||||
<a class="small" href="{% url 'password_change' %}">
|
||||
{% trans 'Change password' %}
|
||||
</a>
|
||||
</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.profile.section }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.profile.address }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.note.balance | pretty_money }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'aliases'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.note.alias_set.all|join:", " }}</dd>
|
||||
</dl>
|
||||
|
||||
{% if object.pk == user.pk %}
|
||||
<a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div class="accordion shadow" id="accordionProfile">
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="btn btn-link stretched-link font-weight-bold"
|
||||
data-toggle="collapse" data-target="#clubListCollapse"
|
||||
aria-expanded="true" aria-controls="clubListCollapse">
|
||||
<i class="fa fa-users"></i> {% trans "View my memberships" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="clubListCollapse" class="collapse show" style="overflow:auto hidden" aria-labelledby="clubListHeading" data-parent="#accordionProfile">
|
||||
{% render_table club_list %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="historyListHeading">
|
||||
<a class="btn btn-link stretched-link collapsed font-weight-bold"
|
||||
data-toggle="collapse" data-target="#historyListCollapse"
|
||||
aria-expanded="false" aria-controls="historyListCollapse">
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="historyListCollapse" class="collapse" style="overflow:auto hidden" aria-labelledby="historyListHeading" data-parent="#accordionProfile">
|
||||
{% render_table history_list %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% block profile_info %}
|
||||
{% include "member/profile_info.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block profile_content %}
|
||||
{% include "member/profile_tables.html" %}
|
||||
{% endblock %}
|
||||
|
48
templates/member/profile_info.html
Normal file
48
templates/member/profile_info.html
Normal file
@ -0,0 +1,48 @@
|
||||
{% load i18n static pretty_money %}
|
||||
|
||||
<div class="card bg-light shadow">
|
||||
<div class="card-top text-center">
|
||||
<a href="{% url 'member:user_update_pic' object.pk %}">
|
||||
<img src="{{ object.note.display_image.url }}" class="img-thumbnail mt-2" >
|
||||
</a>
|
||||
</div>
|
||||
<div class="card-body" id="profile_infos">
|
||||
<dl class="row">
|
||||
<dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt>
|
||||
<dd class="col-xl-6">{{ object.last_name }} {{ object.first_name }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'username'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.username }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">
|
||||
<a class="small" href="{% url 'password_change' %}">
|
||||
{% trans 'Change password' %}
|
||||
</a>
|
||||
</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.profile.section }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.profile.address }}</dd>
|
||||
|
||||
<dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
|
||||
<dd class="col-xl-6">{{ object.note.balance | pretty_money }}</dd>
|
||||
|
||||
<dt class="col-xl-6"> <a href="{% url 'member:user_alias' object.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
|
||||
<dd class="col-xl-6 text-truncate">{{ object.note.alias_set.all|join:", " }}</dd>
|
||||
</dl>
|
||||
|
||||
{% if object.pk == user.pk %}
|
||||
<a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-center">
|
||||
<a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a>
|
||||
{% url 'member:user_detail' object.pk as user_profile_url %}
|
||||
{%if request.get_full_path != user_profile_url %}
|
||||
<a class="btn btn-primary btn-sm" href="{{ user_profile_url }}">{% trans 'View Profile' %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
10
templates/member/profile_picture_update.html
Normal file
10
templates/member/profile_picture_update.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% extends "member/noteowner_detail.html" %}
|
||||
{% load i18n static pretty_money django_tables2 crispy_forms_tags %}
|
||||
|
||||
{% block profile_info %}
|
||||
{% include "member/profile_info.html" %}
|
||||
{% endblock%}
|
||||
|
||||
{% block profile_content%}
|
||||
{% include "member/picture_update.html" %}
|
||||
{% endblock%}
|
31
templates/member/profile_tables.html
Normal file
31
templates/member/profile_tables.html
Normal file
@ -0,0 +1,31 @@
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
<div class="accordion shadow" id="accordionProfile">
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="clubListHeading">
|
||||
<a class="btn btn-link stretched-link font-weight-bold"
|
||||
data-toggle="collapse" data-target="#clubListCollapse"
|
||||
aria-expanded="true" aria-controls="clubListCollapse">
|
||||
<i class="fa fa-users"></i> {% trans "View my memberships" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="clubListCollapse" class="collapse show" style="overflow:auto hidden" aria-labelledby="clubListHeading" data-parent="#accordionProfile">
|
||||
{% render_table club_list %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header position-relative" id="historyListHeading">
|
||||
<a class="btn btn-link stretched-link collapsed font-weight-bold"
|
||||
data-toggle="collapse" data-target="#historyListCollapse"
|
||||
aria-expanded="false" aria-controls="historyListCollapse">
|
||||
<i class="fa fa-euro"></i> {% trans "Transaction history" %}
|
||||
</a>
|
||||
</div>
|
||||
<div id="historyListCollapse" class="collapse" style="overflow:auto hidden" aria-labelledby="historyListHeading" data-parent="#accordionProfile">
|
||||
<div id="history_list">
|
||||
{% render_table history_list %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -2,16 +2,16 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% load i18n %}
|
||||
{% block title %}Sign Up{% endblock %}
|
||||
{% block title %}{% trans "Sign up" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Sign up</h2>
|
||||
<h2>{% trans "Sign up" %}</h2>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
{{ profile_form|crispy }}
|
||||
<button class="btn btn-success" type="submit">
|
||||
{% trans "Sign Up" %}
|
||||
{% trans "Sign up" %}
|
||||
</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
@ -1,97 +1,171 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load i18n static pretty_money %}
|
||||
{% load i18n static pretty_money django_tables2 %}
|
||||
|
||||
{# Remove page title #}
|
||||
{% block contenttitle %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{# Regroup buttons under categories #}
|
||||
{% regroup transaction_templates by category as categories %}
|
||||
|
||||
<form method="post" onsubmit="window.onbeforeunload=null">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-5 mb-4">
|
||||
{% if form.non_field_errors %}
|
||||
<p class="errornote">
|
||||
{% for error in form.non_field_errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% for field in form %}
|
||||
<div class="form-row{% if field.errors %} errors{% endif %}">
|
||||
{{ field.errors }}
|
||||
<div>
|
||||
{{ field.label_tag }}
|
||||
{% if field.is_readonly %}
|
||||
<div class="readonly">{{ field.contents }}</div>
|
||||
{% else %}
|
||||
{{ field }}
|
||||
{% endif %}
|
||||
{% if field.field.help_text %}
|
||||
<div class="help">{{ field.field.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
<div class="row mt-4">
|
||||
<div class="col-sm-5 col-md-4" id="infos_div">
|
||||
<div class="row">
|
||||
{# User details column #}
|
||||
<div class="col-xl-5" id="note_infos_div">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<img src="/media/pic/default.png"
|
||||
id="profile_pic" alt="" class="img-fluid rounded mx-auto d-block">
|
||||
<div class="card-body text-center">
|
||||
<span id="user_note"></span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-7">
|
||||
<div class="card text-center shadow">
|
||||
{# Tabs for button categories #}
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs nav-fill card-header-tabs">
|
||||
{% for category in categories %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#{{ category.grouper|slugify }}">
|
||||
{{ category.grouper }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{# User selection column #}
|
||||
<div class="col-xl-7" id="user_select_div">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Select emitters" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="note_list">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Tabs content #}
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
{% for category in categories %}
|
||||
<div class="tab-pane" id="{{ category.grouper|slugify }}">
|
||||
<div class="d-inline-flex flex-wrap justify-content-center">
|
||||
{% for button in category.list %}
|
||||
<button class="btn btn-outline-dark rounded-0 flex-fill"
|
||||
name="button" value="{{ button.name }}">
|
||||
{{ button.name }} ({{ button.amount | pretty_money }})
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="note" />
|
||||
<ul class="list-group list-group-flush" id="alias_matched">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-5" id="consos_list_div">
|
||||
<div class="card border-info shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Select consumptions" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="consos_list">
|
||||
</ul>
|
||||
<button id="consume_all" class="form-control btn btn-primary">
|
||||
{% trans "Consume!" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{# Buttons column #}
|
||||
<div class="col-sm-7 col-md-8" id="buttons_div">
|
||||
{# Show last used buttons #}
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Most used buttons" %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="card-body text-nowrap" style="overflow:auto hidden">
|
||||
<div class="d-inline-flex flex-wrap justify-content-center" id="most_used">
|
||||
{% for button in most_used %}
|
||||
{% if button.display %}
|
||||
<button class="btn btn-outline-dark rounded-0 flex-fill"
|
||||
id="most_used_button{{ button.id }}" name="button" value="{{ button.name }}">
|
||||
{{ button.name }} ({{ button.amount | pretty_money }})
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Regroup buttons under categories #}
|
||||
{% regroup transaction_templates by category as categories %}
|
||||
|
||||
<div class="card border-primary text-center shadow mb-4">
|
||||
{# Tabs for button categories #}
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs nav-fill card-header-tabs">
|
||||
{% for category in categories %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link font-weight-bold" data-toggle="tab" href="#{{ category.grouper|slugify }}">
|
||||
{{ category.grouper }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{# Tabs content #}
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
{% for category in categories %}
|
||||
<div class="tab-pane" id="{{ category.grouper|slugify }}">
|
||||
<div class="d-inline-flex flex-wrap justify-content-center">
|
||||
{% for button in category.list %}
|
||||
{% if button.display %}
|
||||
<button class="btn btn-outline-dark rounded-0 flex-fill"
|
||||
id="button{{ button.id }}" name="button" value="{{ button.name }}">
|
||||
{{ button.name }} ({{ button.amount | pretty_money }})
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Mode switch #}
|
||||
<div class="card-footer border-primary">
|
||||
<a class="btn btn-sm btn-secondary float-left" href="{% url 'note:template_list' %}">
|
||||
<i class="fa fa-edit"></i> {% trans "Edit" %}
|
||||
</a>
|
||||
<div class="btn-group btn-group-toggle float-right" data-toggle="buttons">
|
||||
<label for="single_conso" class="btn btn-sm btn-outline-primary active">
|
||||
<input type="radio" name="conso_type" id="single_conso" checked>
|
||||
{% trans "Single consumptions" %}
|
||||
</label>
|
||||
<label for="double_conso" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="conso_type" id="double_conso">
|
||||
{% trans "Double consumptions" %}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow mb-4" id="history">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Recent transactions history" %}
|
||||
</p>
|
||||
</div>
|
||||
{% render_table table %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script type="text/javascript" src="/static/js/consos.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// If hash of a category in the URL, then select this category
|
||||
// else select the first one
|
||||
if (location.hash) {
|
||||
$("a[href='" + location.hash + "']").tab("show");
|
||||
} else {
|
||||
$("a[data-toggle='tab']").first().tab("show");
|
||||
}
|
||||
{% for button in most_used %}
|
||||
{% if button.display %}
|
||||
$("#most_used_button{{ button.id }}").click(function() {
|
||||
addConso({{ button.destination.id }}, {{ button.amount }},
|
||||
{{ polymorphic_ctype }}, {{ button.category.id }}, "{{ button.category.name }}",
|
||||
{{ button.id }}, "{{ button.name }}");
|
||||
});
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
// When selecting a category, change URL
|
||||
$(document.body).on("click", "a[data-toggle='tab']", function(event) {
|
||||
location.hash = this.getAttribute("href");
|
||||
});
|
||||
});
|
||||
{% for button in transaction_templates %}
|
||||
{% if button.display %}
|
||||
$("#button{{ button.id }}").click(function() {
|
||||
addConso({{ button.destination.id }}, {{ button.amount }},
|
||||
{{ polymorphic_ctype }}, {{ button.category.id }}, "{{ button.category.name }}",
|
||||
{{ button.id }}, "{{ button.name }}");
|
||||
});
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -3,35 +3,192 @@
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
{% endcomment %}
|
||||
|
||||
{% load i18n static %}
|
||||
{% load i18n static django_tables2 perms %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post" onsubmit="window.onbeforeunload=null">{% csrf_token %}
|
||||
{% if form.non_field_errors %}
|
||||
<p class="errornote">
|
||||
{% for error in form.non_field_errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</p>
|
||||
{% endif %}
|
||||
<fieldset class="module aligned">
|
||||
{% for field in form %}
|
||||
<div class="form-row{% if field.errors %} errors{% endif %}">
|
||||
{{ field.errors }}
|
||||
<div>
|
||||
{{ field.label_tag }}
|
||||
{% if field.is_readonly %}
|
||||
<div class="readonly">{{ field.contents }}</div>
|
||||
{% else %}
|
||||
{{ field }}
|
||||
{% endif %}
|
||||
{% if field.field.help_text %}
|
||||
<div class="help">{{ field.field.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="btn-group btn-group-toggle" style="width: 100%; padding: 0 0 2em 0" data-toggle="buttons">
|
||||
<label for="type_gift" class="btn btn-sm btn-outline-primary active">
|
||||
<input type="radio" name="transaction_type" id="type_gift" checked>
|
||||
{% trans "Gift" %}
|
||||
</label>
|
||||
<label for="type_transfer" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_transfer">
|
||||
{% trans "Transfer" %}
|
||||
</label>
|
||||
{% if "note.notespecial"|not_empty_model_list %}
|
||||
<label for="type_credit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_credit">
|
||||
{% trans "Credit" %}
|
||||
</label>
|
||||
<label type="type_debit" class="btn btn-sm btn-outline-primary">
|
||||
<input type="radio" name="transaction_type" id="type_debit">
|
||||
{% trans "Debit" %}
|
||||
</label>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xl-4" id="note_infos_div">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<img src="/media/pic/default.png"
|
||||
id="profile_pic" alt="" class="img-fluid rounded mx-auto d-block">
|
||||
<div class="card-body text-center">
|
||||
<span id="user_note"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4" id="emitters_div" style="display: none;">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Select emitters" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="source_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="source_note" />
|
||||
<ul class="list-group list-group-flush" id="source_alias_matched">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if "note.notespecial"|not_empty_model_list %}
|
||||
<div class="col-md-4" id="external_div" style="display: none;">
|
||||
<div class="card border-success shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "External payment" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="source_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="credit_type">{% trans "Transfer type" %} :</label>
|
||||
<select id="credit_type" class="custom-select">
|
||||
{% for special_type in special_types %}
|
||||
<option value="{{ special_type.id }}">{{ special_type.special_type }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="last_name">{% trans "Name" %} :</label>
|
||||
<input type="text" id="last_name" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="first_name">{% trans "First name" %} :</label>
|
||||
<input type="text" id="first_name" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<label for="bank">{% trans "Bank" %} :</label>
|
||||
<input type="text" id="bank" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
<input type="submit" value="{% trans 'Transfer' %}">
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="col-md-8" id="dests_div">
|
||||
<div class="card border-info shadow mb-4">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold" id="dest_title">
|
||||
{% trans "Select receivers" %}
|
||||
</p>
|
||||
</div>
|
||||
<ul class="list-group list-group-flush" id="dest_note_list">
|
||||
</ul>
|
||||
<div class="card-body">
|
||||
<input class="form-control mx-auto d-block" type="text" id="dest_note" />
|
||||
<ul class="list-group list-group-flush" id="dest_alias_matched">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="amount">{% trans "Amount" %} :</label>
|
||||
<div class="input-group">
|
||||
<input class="form-control mx-auto d-block" type="number" min="0" step="0.01" id="amount" />
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">€</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-6">
|
||||
<label for="reason">{% trans "Reason" %} :</label>
|
||||
<input class="form-control mx-auto d-block" type="text" id="reason" required />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="col-md-12">
|
||||
<button id="transfer" class="form-control btn btn-primary">{% trans 'Transfer' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow mb-4" id="history">
|
||||
<div class="card-header">
|
||||
<p class="card-text font-weight-bold">
|
||||
{% trans "Recent transactions history" %}
|
||||
</p>
|
||||
</div>
|
||||
{% render_table table %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script>
|
||||
TRANSFER_POLYMORPHIC_CTYPE = {{ polymorphic_ctype }};
|
||||
SPECIAL_TRANSFER_POLYMORPHIC_CTYPE = {{ special_polymorphic_ctype }};
|
||||
user_id = {{ user.note.pk }};
|
||||
|
||||
$("#type_gift").click(function() {
|
||||
$("#emitters_div").hide();
|
||||
$("#external_div").hide();
|
||||
$("#dests_div").attr('class', 'col-md-8');
|
||||
$("#dest_title").text("{% trans "Select receivers" %}");
|
||||
});
|
||||
|
||||
$("#type_transfer").click(function() {
|
||||
$("#external_div").hide();
|
||||
$("#emitters_div").show();
|
||||
$("#dests_div").attr('class', 'col-md-4');
|
||||
$("#dest_title").text("{% trans "Select receivers" %}");
|
||||
});
|
||||
|
||||
$("#type_credit").click(function() {
|
||||
$("#emitters_div").hide();
|
||||
$("#external_div").show();
|
||||
$("#dests_div").attr('class', 'col-md-4');
|
||||
$("#dest_title").text("{% trans "Credit note" %}");
|
||||
});
|
||||
|
||||
$("#type_debit").click(function() {
|
||||
$("#emitters_div").hide();
|
||||
$("#external_div").show();
|
||||
$("#dests_div").attr('class', 'col-md-4');
|
||||
$("#dest_title").text("{% trans "Debit note" %}");
|
||||
});
|
||||
</script>
|
||||
<script src="/static/js/transfer.js"></script>
|
||||
{% endblock %}
|
||||
|
@ -1,8 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags %}
|
||||
{% block content %}
|
||||
<p><a class="btn btn-default" href="{% url 'note:template_list' %}">Template Listing</a></p>
|
||||
<p><a class="btn btn-default" href="{% url 'note:template_list' %}">{% trans "Buttons list" %}</a></p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{form|crispy}}
|
||||
|
@ -1,23 +1,79 @@
|
||||
{% extends "base.html" %}
|
||||
{% load pretty_money %}
|
||||
{% load i18n %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% block content %}
|
||||
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td>ID</td><td>Nom</td>
|
||||
<td>Destinataire</td>
|
||||
<td>Montant</td>
|
||||
<td>Catégorie</td>
|
||||
</tr>
|
||||
{% for object in object_list %}
|
||||
<tr>
|
||||
<td>{{object.pk}}</td>
|
||||
<td><a href="{{object.get_absolute_url}}">{{ object.name }}</a></td>
|
||||
<td>{{ object.destination }}</td>
|
||||
<td>{{ object.amount | pretty_money }}</td>
|
||||
<td>{{ object.template_type }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<a class="btn btn-primary" href="{% url 'note:template_create' %}">Créer un bouton</a>
|
||||
<div class="row justify-content-center mb-4">
|
||||
<div class="col-md-10 text-center">
|
||||
<h4>
|
||||
{% trans "search button" %}
|
||||
</h4>
|
||||
<input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved();return(false);" id="search_field"/>
|
||||
<hr>
|
||||
<a class="btn btn-primary text-center my-4" href="{% url 'note:template_create' %}">Créer un bouton</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-10">
|
||||
<div class="card card-border shadow">
|
||||
<div class="card-header text-center">
|
||||
<h5> {% trans "buttons listing "%}</h5>
|
||||
</div>
|
||||
<div class="card-body px-0 py-0" id="buttons_table">
|
||||
{% render_table table %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script>
|
||||
/* fonction appelée à la fin du timer */
|
||||
function getInfo() {
|
||||
var asked = $("#search_field").val();
|
||||
/* on ne fait la requête que si on a au moins un caractère pour chercher */
|
||||
var sel = $(".table-row");
|
||||
if (asked.length >= 1) {
|
||||
$.getJSON("/api/note/transaction/template/?format=json&search="+asked, function(buttons){
|
||||
let selected_id = buttons.results.map((a => "#row-"+a.id));
|
||||
console.log(selected_id.join());
|
||||
$(".table-row,"+selected_id.join()).show();
|
||||
$(".table-row").not(selected_id.join()).hide();
|
||||
|
||||
});
|
||||
}else{
|
||||
// show everything
|
||||
$('table tr').show();
|
||||
}
|
||||
}
|
||||
var timer;
|
||||
var timer_on;
|
||||
/* Fontion appelée quand le texte change (délenche le timer) */
|
||||
function search_field_moved(secondfield) {
|
||||
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout("getInfo(" + secondfield + ")", 300);
|
||||
}
|
||||
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
|
||||
timer = setTimeout("getInfo(" + secondfield + ")", 300);
|
||||
timer_on = true;
|
||||
}
|
||||
}
|
||||
// on click of button "delete" , call the API
|
||||
function delete_button(button_id){
|
||||
$.ajax({
|
||||
url:"/api/note/transaction/template/"+button_id+"/",
|
||||
method:"DELETE",
|
||||
headers: {"X-CSRFTOKEN": CSRF_TOKEN}
|
||||
})
|
||||
.done(function(){
|
||||
addMsg('{% trans "button successfully deleted "%}','success');
|
||||
$("#buttons_table").load("{% url 'note:template_list' %} #buttons_table");
|
||||
})
|
||||
.fail(function(){
|
||||
addMsg(' {% trans "Unable to delete button "%} #' + button_id,'danger' )
|
||||
});
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -16,7 +16,13 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{%url 'cas_login' as cas_url %}
|
||||
{% if cas_url %}
|
||||
<div class="alert alert-info">
|
||||
{% trans "You can also register via the central authentification server " %}
|
||||
<a href="{{ cas_url }}"> {% trans "using this link "%}</a>
|
||||
</div>
|
||||
{%endif%}
|
||||
<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
|
||||
{{ form | crispy }}
|
||||
<input type="submit" value="{% trans 'Log in' %}" class="btn btn-primary">
|
||||
|
107
templates/treasury/invoice_form.html
Normal file
107
templates/treasury/invoice_form.html
Normal file
@ -0,0 +1,107 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags pretty_money %}
|
||||
{% block content %}
|
||||
<p><a class="btn btn-default" href="{% url 'treasury:invoice_list' %}">{% trans "Invoices list" %}</a></p>
|
||||
<form method="post" action="">
|
||||
{% csrf_token %}
|
||||
{# Render the invoice form #}
|
||||
{% crispy form %}
|
||||
{# The next part concerns the product formset #}
|
||||
{# Generate some hidden fields that manage the number of products, and make easier the parsing #}
|
||||
{{ formset.management_form }}
|
||||
<table class="table table-condensed table-striped">
|
||||
{# Fill initial data #}
|
||||
{% for form in formset %}
|
||||
{% if forloop.first %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ form.designation.label }}<span class="asteriskField">*</span></th>
|
||||
<th>{{ form.quantity.label }}<span class="asteriskField">*</span></th>
|
||||
<th>{{ form.amount.label }}<span class="asteriskField">*</span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="form_body">
|
||||
{% endif %}
|
||||
<tr class="row-formset">
|
||||
<td>{{ form.designation }}</td>
|
||||
<td>{{ form.quantity }} </td>
|
||||
<td>
|
||||
{# Use custom input for amount, with the € symbol #}
|
||||
<div class="input-group">
|
||||
<input type="number" name="product_set-{{ forloop.counter0 }}-amount" step="0.01"
|
||||
id="id_product_set-{{ forloop.counter0 }}-amount"
|
||||
value="{{ form.instance.amount|cents_to_euros }}">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">€</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{# These fields are hidden but handled by the formset to link the id and the invoice id #}
|
||||
{{ form.invoice }}
|
||||
{{ form.id }}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{# Display buttons to add and remove products #}
|
||||
<div class="btn-group btn-block" role="group">
|
||||
<button type="button" id="add_more" class="btn btn-primary">{% trans "Add product" %}</button>
|
||||
<button type="button" id="remove_one" class="btn btn-danger">{% trans "Remove product" %}</button>
|
||||
</div>
|
||||
|
||||
<div class="btn-block">
|
||||
<button type="submit" class="btn btn-block btn-primary">{% trans "Submit" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="empty_form" style="display: none;">
|
||||
{# Hidden div that store an empty product form, to be copied into new forms #}
|
||||
<table class='no_error'>
|
||||
<tbody id="for_real">
|
||||
<tr class="row-formset">
|
||||
<td>{{ formset.empty_form.designation }}</td>
|
||||
<td>{{ formset.empty_form.quantity }} </td>
|
||||
<td>
|
||||
<div class="input-group">
|
||||
<input type="number" name="product_set-__prefix__-amount" step="0.01"
|
||||
id="id_product_set-__prefix__-amount">
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">€</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
{{ formset.empty_form.invoice }}
|
||||
{{ formset.empty_form.id }}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script>
|
||||
{# Script that handles add and remove lines #}
|
||||
IDS = {};
|
||||
|
||||
$("#id_product_set-TOTAL_FORMS").val($(".row-formset").length - 1);
|
||||
|
||||
$('#add_more').click(function () {
|
||||
var form_idx = $('#id_product_set-TOTAL_FORMS').val();
|
||||
$('#form_body').append($('#for_real').html().replace(/__prefix__/g, form_idx));
|
||||
$('#id_product_set-TOTAL_FORMS').val(parseInt(form_idx) + 1);
|
||||
$('#id_product_set-' + parseInt(form_idx) + '-id').val(IDS[parseInt(form_idx)]);
|
||||
});
|
||||
|
||||
$('#remove_one').click(function () {
|
||||
let form_idx = $('#id_product_set-TOTAL_FORMS').val();
|
||||
if (form_idx > 0) {
|
||||
IDS[parseInt(form_idx) - 1] = $('#id_product_set-' + (parseInt(form_idx) - 1) + '-id').val();
|
||||
$('#form_body tr:last-child').remove();
|
||||
$('#id_product_set-TOTAL_FORMS').val(parseInt(form_idx) - 1);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
23
templates/treasury/invoice_list.html
Normal file
23
templates/treasury/invoice_list.html
Normal file
@ -0,0 +1,23 @@
|
||||
{% extends "base.html" %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="btn-group btn-group-toggle" style="width: 100%; padding: 0 0 2em 0" data-toggle="buttons">
|
||||
<a href="#" class="btn btn-sm btn-outline-primary active">
|
||||
{% trans "Invoice" %}s
|
||||
</a>
|
||||
<a href="{% url "treasury:remittance_list" %}" class="btn btn-sm btn-outline-primary">
|
||||
{% trans "Remittance" %}s
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% render_table table %}
|
||||
|
||||
<a class="btn btn-primary" href="{% url 'treasury:invoice_create' %}">{% trans "New invoice" %}</a>
|
||||
|
||||
{% endblock %}
|
186
templates/treasury/invoice_sample.tex
Normal file
186
templates/treasury/invoice_sample.tex
Normal file
@ -0,0 +1,186 @@
|
||||
\nonstopmode
|
||||
\documentclass[11pt]{article}
|
||||
|
||||
\usepackage[french]{babel}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[a4paper]{geometry}
|
||||
\usepackage{units}
|
||||
\usepackage{bera}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{fancyhdr}
|
||||
\usepackage{fp}
|
||||
\usepackage{transparent}
|
||||
\usepackage{eso-pic}
|
||||
|
||||
\def\TVA{0} % Taux de la TVA
|
||||
|
||||
\def\TotalHT{0}
|
||||
\def\TotalTVA{0}
|
||||
|
||||
\newcommand{\AjouterProduit}[4]{% Arguments : Désignation, quantité, prix unitaire HT, prix total HT
|
||||
\FPround{\prix}{#3}{2}
|
||||
\FPround{\montant}{#4}{2}
|
||||
\FPadd{\TotalHT}{\TotalHT}{\montant}
|
||||
|
||||
\eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr}
|
||||
}
|
||||
|
||||
\newcommand{\AfficheResultat}{%
|
||||
\ListeProduits
|
||||
|
||||
\FPeval{\TotalTVA}{\TotalHT * \TVA / 100}
|
||||
\FPadd{\TotalTTC}{\TotalHT}{\TotalTVA}
|
||||
\FPround{\TotalHT}{\TotalHT}{2}
|
||||
\FPround{\TotalTVA}{\TotalTVA}{2}
|
||||
\FPround{\TotalTTC}{\TotalTTC}{2}
|
||||
\global\let\TotalHT\TotalHT
|
||||
\global\let\TotalTVA\TotalTVA
|
||||
\global\let\TotalTTC\TotalTTC
|
||||
|
||||
\cr \hline
|
||||
Total HT & & & \TotalHT \cr
|
||||
TVA \TVA~\% & & & \TotalTVA \cr
|
||||
\hline \hline
|
||||
\textbf{Total TTC} & & & \TotalTTC
|
||||
}
|
||||
|
||||
\newcommand*\eaddto[2]{% version développée de \addto
|
||||
\edef\tmp{#2}%
|
||||
\expandafter\addto
|
||||
\expandafter#1%
|
||||
\expandafter{\tmp}%
|
||||
}
|
||||
|
||||
\newcommand {\ListeProduits}{}
|
||||
|
||||
% Logo du BDE
|
||||
\AddToShipoutPicture*{
|
||||
\put(0,0){
|
||||
\parbox[b][\paperheight]{\paperwidth}{%
|
||||
\vfill
|
||||
\centering
|
||||
{\transparent{0.1}\includegraphics[width=\textwidth]{../../static/img/{{ obj.bde }}}}%
|
||||
\vfill
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%%
|
||||
% Infos Association
|
||||
\def\MonNom{{"{"}}{{ obj.my_name }}} % Nom de l'association
|
||||
\def\MonAdresseRue{{"{"}}{{ obj.my_address_street }}} % Adresse de l'association
|
||||
\def\MonAdresseVille{{"{"}}{{ obj.my_city }}}
|
||||
|
||||
% Informations bancaires de l'association
|
||||
\def\CodeBanque{{"{"}}{{ obj.bank_code|stringformat:".05d" }}}
|
||||
\def\CodeGuichet{{"{"}}{{ obj.desk_code|stringformat:".05d" }}}
|
||||
\def\NCompte{{"{"}}{{ obj.account_number|stringformat:".011d" }}}
|
||||
\def\CleRib{{"{"}}{{ obj.rib_key|stringformat:".02d" }}}
|
||||
\def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib}
|
||||
\def\CodeBic{{"{"}}{{ obj.bic }}}
|
||||
|
||||
\def\FactureNum {{"{"}}{{obj.id}}} % Numéro de facture
|
||||
\def\FactureAcquittee {% if obj.acquitted %} {oui} {% else %} {non} {% endif %} % Facture acquittée : oui/non
|
||||
\def\FactureLieu {{"{"}}{{ obj.place }}} % Lieu de l'édition de la facture
|
||||
\def\FactureDate {{"{"}}{{ obj.date }}} % Date de l'édition de la facture
|
||||
\def\FactureObjet {{"{"}}{{ obj.object|safe }} } % Objet du document
|
||||
% Description de la facture
|
||||
\def\FactureDescr {{"{"}}{{ obj.description|safe }}}
|
||||
|
||||
% Infos Client
|
||||
\def\ClientNom{{"{"}}{{obj.name|safe}}} % Nom du client
|
||||
\def\ClientAdresse{{"{"}}{{ obj.address|safe }}} % Adresse du client
|
||||
|
||||
% Liste des produits facturés : Désignation, quantité, prix unitaire HT
|
||||
|
||||
{% for product in products %}
|
||||
\AjouterProduit{ {{product.designation|safe}}} { {{product.quantity|safe}}} { {{product.amount_euros|safe}}} { {{product.total_euros|safe}}}
|
||||
{% endfor %}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em}
|
||||
\setlength{\parindent}{1pt}
|
||||
\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
|
||||
|
||||
\thispagestyle{fancy}
|
||||
\pagestyle{fancy}
|
||||
\setlength{\parindent}{0pt}
|
||||
|
||||
\renewcommand{\headrulewidth}{0pt}
|
||||
\cfoot{
|
||||
\small{\MonNom ~--~ \MonAdresseRue ~ \MonAdresseVille ~--~ Téléphone : +33(0)6 89 88 56 50\newline
|
||||
Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00011
|
||||
}
|
||||
}
|
||||
|
||||
\begin{document}
|
||||
|
||||
% Logo de la société
|
||||
% \includegraphics{logo.jpg}
|
||||
|
||||
% Nom et adresse de la société
|
||||
\MonNom \\
|
||||
\MonAdresseRue \\
|
||||
\MonAdresseVille
|
||||
|
||||
Facture n°\FactureNum
|
||||
|
||||
|
||||
{\addtolength{\leftskip}{10.5cm} %in ERT
|
||||
\ClientNom \\
|
||||
\ClientAdresse \\
|
||||
|
||||
} %in ERT
|
||||
|
||||
|
||||
\hspace*{10.5cm}
|
||||
\FactureLieu, le \FactureDate
|
||||
|
||||
~\\~\\
|
||||
|
||||
\textbf{Objet : \FactureObjet \\}
|
||||
|
||||
\textnormal{\FactureDescr}
|
||||
|
||||
~\\
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{lrrr}
|
||||
\textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\
|
||||
\hline
|
||||
\AfficheResultat{}
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
~\\
|
||||
|
||||
\ifthenelse{\equal{\FactureAcquittee}{oui}}{
|
||||
Facture acquittée.
|
||||
}{
|
||||
|
||||
À régler par chèque ou par virement bancaire :
|
||||
|
||||
\begin{center}
|
||||
\begin{tabular}{|c c c c|}
|
||||
\hline
|
||||
\textbf{Code banque} & \textbf{Code guichet} & \textbf{N° de Compte} & \textbf{Clé RIB}\\
|
||||
\CodeBanque & \CodeGuichet & \NCompte & \CleRib \\
|
||||
\hline
|
||||
\textbf{IBAN N°} & \multicolumn{3}{|l|} \IBAN \\
|
||||
\hline
|
||||
\textbf{Code BIC} & \multicolumn{3}{|l|}\CodeBic \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
}
|
||||
|
||||
\begin{center}
|
||||
TVA non applicable, article 293 B du CGI.
|
||||
\end{center}
|
||||
|
||||
\end{document}
|
37
templates/treasury/remittance_form.html
Normal file
37
templates/treasury/remittance_form.html
Normal file
@ -0,0 +1,37 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags pretty_money %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% block content %}
|
||||
<h1>{% trans "Remittance #" %}{{ object.pk }}</h1>
|
||||
|
||||
<p><a class="btn btn-default" href="{% url 'treasury:remittance_list' %}">{% trans "Remittances list" %}</a></p>
|
||||
|
||||
{% if object.pk %}
|
||||
<div id="div_id_type" class="form-group"><label for="id_count" class="col-form-label">{% trans "Count" %}</label>
|
||||
<div class="">
|
||||
<input type="text" name="count" value="{{ object.count }}" class="textinput textInput form-control" id="id_count" disabled>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="div_id_type" class="form-group"><label for="id_amount" class="col-form-label">{% trans "Amount" %}</label>
|
||||
<div class="">
|
||||
<input class="textinput textInput form-control" type="text" value="{{ object.amount|pretty_money }}" id="id_amount" disabled>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% crispy form %}
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>{% trans "Linked transactions" %}</h2>
|
||||
{% if special_transactions.data %}
|
||||
{% render_table special_transactions %}
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
{% trans "There is no transaction linked with this remittance." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
56
templates/treasury/remittance_list.html
Normal file
56
templates/treasury/remittance_list.html
Normal file
@ -0,0 +1,56 @@
|
||||
{% extends "base.html" %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="btn-group btn-group-toggle" style="width: 100%; padding: 0 0 2em 0" data-toggle="buttons">
|
||||
<a href="{% url "treasury:invoice_list" %}" class="btn btn-sm btn-outline-primary">
|
||||
{% trans "Invoice" %}s
|
||||
</a>
|
||||
<a href="#" class="btn btn-sm btn-outline-primary active">
|
||||
{% trans "Remittance" %}s
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>{% trans "Opened remittances" %}</h2>
|
||||
{% if opened_remittances.data %}
|
||||
{% render_table opened_remittances %}
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
{% trans "There is no opened remittance." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<a class="btn btn-primary" href="{% url 'treasury:remittance_create' %}">{% trans "New remittance" %}</a>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>{% trans "Transfers without remittances" %}</h2>
|
||||
{% if special_transactions_no_remittance.data %}
|
||||
{% render_table special_transactions_no_remittance %}
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
{% trans "There is no transaction without any linked remittance." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>{% trans "Transfers with opened remittances" %}</h2>
|
||||
{% if special_transactions_with_remittance.data %}
|
||||
{% render_table special_transactions_with_remittance %}
|
||||
{% else %}
|
||||
<div class="alert alert-warning">
|
||||
{% trans "There is no transaction with an opened linked remittance." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>{% trans "Closed remittances" %}</h2>
|
||||
{% render_table closed_remittances %}
|
||||
{% endblock %}
|
9
templates/treasury/specialtransactionproxy_form.html
Normal file
9
templates/treasury/specialtransactionproxy_form.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load crispy_forms_tags pretty_money %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% block content %}
|
||||
<p><a class="btn btn-default" href="{% url 'treasury:remittance_list' %}">{% trans "Remittances list" %}</a></p>
|
||||
{% crispy form %}
|
||||
{% endblock %}
|
Reference in New Issue
Block a user