mirror of https://github.com/nanoy42/coope
committed by
GitHub
68 changed files with 1745 additions and 238 deletions
@ -1,21 +0,0 @@ |
|||||
MIT License |
|
||||
|
|
||||
Copyright (c) 2017 Martin Bierbaum |
|
||||
|
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
||||
of this software and associated documentation files (the "Software"), to deal |
|
||||
in the Software without restriction, including without limitation the rights |
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
||||
copies of the Software, and to permit persons to whom the Software is |
|
||||
furnished to do so, subject to the following conditions: |
|
||||
|
|
||||
The above copyright notice and this permission notice shall be included in all |
|
||||
copies or substantial portions of the Software. |
|
||||
|
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
||||
SOFTWARE. |
|
||||
@ -1,50 +0,0 @@ |
|||||
|
|
||||
import os |
|
||||
from subprocess import PIPE, run |
|
||||
import tempfile |
|
||||
|
|
||||
from django.template.loader import get_template |
|
||||
|
|
||||
from django_tex.exceptions import TexError |
|
||||
from django.conf import settings |
|
||||
|
|
||||
DEFAULT_INTERPRETER = 'pdflatex' |
|
||||
|
|
||||
def run_tex(source): |
|
||||
""" |
|
||||
Copy the source to temp dict and run latex. |
|
||||
""" |
|
||||
with tempfile.TemporaryDirectory() as tempdir: |
|
||||
filename = os.path.join(tempdir, 'texput.tex') |
|
||||
with open(filename, 'x', encoding='utf-8') as f: |
|
||||
f.write(source) |
|
||||
print(source) |
|
||||
latex_interpreter = getattr(settings, 'LATEX_INTERPRETER', DEFAULT_INTERPRETER) |
|
||||
latex_command = 'cd "{tempdir}" && {latex_interpreter} -interaction=batchmode {path}'.format(tempdir=tempdir, latex_interpreter=latex_interpreter, path=os.path.basename(filename)) |
|
||||
process = run(latex_command, shell=True, stdout=PIPE, stderr=PIPE) |
|
||||
try: |
|
||||
if process.returncode == 1: |
|
||||
with open(os.path.join(tempdir, 'texput.log'), encoding='utf8') as f: |
|
||||
log = f.read() |
|
||||
raise TexError(log=log, source=source) |
|
||||
with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as pdf_file: |
|
||||
pdf = pdf_file.read() |
|
||||
except FileNotFoundError: |
|
||||
if process.stderr: |
|
||||
raise Exception(process.stderr.decode('utf-8')) |
|
||||
raise |
|
||||
return pdf |
|
||||
|
|
||||
def compile_template_to_pdf(template_name, context): |
|
||||
""" |
|
||||
Compile the source with :func:`~django_tex.core.render_template_with_context` and :func:`~django_tex.core.run_tex`. |
|
||||
""" |
|
||||
source = render_template_with_context(template_name, context) |
|
||||
return run_tex(source) |
|
||||
|
|
||||
def render_template_with_context(template_name, context): |
|
||||
""" |
|
||||
Render the template |
|
||||
""" |
|
||||
template = get_template(template_name, using='tex') |
|
||||
return template.render(context) |
|
||||
@ -1,11 +0,0 @@ |
|||||
|
|
||||
from django.template.backends.jinja2 import Jinja2 |
|
||||
|
|
||||
class TeXEngine(Jinja2): |
|
||||
app_dirname = 'templates' |
|
||||
|
|
||||
def __init__(self, params): |
|
||||
default_environment = 'django_tex.environment.environment' |
|
||||
if 'environment' not in params['OPTIONS'] or not params['OPTIONS']['environment']: |
|
||||
params['OPTIONS']['environment'] = default_environment |
|
||||
super().__init__(params) |
|
||||
@ -1,16 +0,0 @@ |
|||||
|
|
||||
from jinja2 import Environment |
|
||||
|
|
||||
from django.template.defaultfilters import register |
|
||||
|
|
||||
from django_tex.filters import FILTERS as tex_specific_filters |
|
||||
|
|
||||
# Django's built-in filters ... |
|
||||
filters = register.filters |
|
||||
# ... updated with tex specific filters |
|
||||
filters.update(tex_specific_filters) |
|
||||
|
|
||||
def environment(**options): |
|
||||
env = Environment(**options) |
|
||||
env.filters = filters |
|
||||
return env |
|
||||
@ -1,40 +0,0 @@ |
|||||
|
|
||||
import re |
|
||||
|
|
||||
def prettify_message(message): |
|
||||
''' |
|
||||
Helper methods that removes consecutive whitespaces and newline characters |
|
||||
''' |
|
||||
# Replace consecutive whitespaces with a single whitespace |
|
||||
message = re.sub(r'[ ]{2,}', ' ', message) |
|
||||
# Replace consecutive newline characters, optionally separated by whitespace, with a single newline |
|
||||
message = re.sub(r'([\r\n][ \t]*)+', '\n', message) |
|
||||
return message |
|
||||
|
|
||||
def tokenizer(code): |
|
||||
token_specification = [ |
|
||||
('ERROR', r'\! (?:.+[\r\n])+[\r\n]+'), |
|
||||
('WARNING', r'latex warning.*'), |
|
||||
('NOFILE', r'no file.*') |
|
||||
] |
|
||||
token_regex = '|'.join('(?P<{}>{})'.format(label, regex) for label, regex in token_specification) |
|
||||
for m in re.finditer(token_regex, code, re.IGNORECASE): |
|
||||
token_dict = dict(type=m.lastgroup, message=prettify_message(m.group())) |
|
||||
yield token_dict |
|
||||
|
|
||||
class TexError(Exception): |
|
||||
|
|
||||
def __init__(self, log, source): |
|
||||
self.log = log |
|
||||
self.source = source |
|
||||
self.tokens = list(tokenizer(self.log)) |
|
||||
self.message = self.get_message() |
|
||||
|
|
||||
def get_message(self): |
|
||||
for token in self.tokens: |
|
||||
if token['type'] == 'ERROR': |
|
||||
return token['message'] |
|
||||
return 'No error message found in log' |
|
||||
|
|
||||
def __str__(self): |
|
||||
return self.message |
|
||||
@ -1,9 +0,0 @@ |
|||||
from django.utils.formats import localize_input |
|
||||
|
|
||||
def do_linebreaks(value): |
|
||||
return value.replace('\n', '\\\\\n') |
|
||||
|
|
||||
FILTERS = { |
|
||||
'localize': localize_input, |
|
||||
'linebreaks': do_linebreaks |
|
||||
} |
|
||||
@ -1,19 +0,0 @@ |
|||||
from django.db import models |
|
||||
from django.core.exceptions import ValidationError |
|
||||
from django.template import TemplateDoesNotExist |
|
||||
from django.utils.translation import ugettext_lazy as _ |
|
||||
from django.template.loader import get_template |
|
||||
|
|
||||
def validate_template_path(name): |
|
||||
try: |
|
||||
get_template(name, using='tex') |
|
||||
except TemplateDoesNotExist: |
|
||||
raise ValidationError(_('Template not found.')) |
|
||||
|
|
||||
class TeXTemplateFile(models.Model): |
|
||||
|
|
||||
title = models.CharField(max_length=255) |
|
||||
name = models.CharField(max_length=255, validators=[validate_template_path,]) |
|
||||
|
|
||||
class Meta: |
|
||||
abstract = True |
|
||||
@ -1,17 +0,0 @@ |
|||||
|
|
||||
from django.http import HttpResponse |
|
||||
|
|
||||
from django_tex.core import compile_template_to_pdf |
|
||||
|
|
||||
class PDFResponse(HttpResponse): |
|
||||
|
|
||||
def __init__(self, content, filename=None): |
|
||||
super(PDFResponse, self).__init__(content_type='application/pdf') |
|
||||
self['Content-Disposition'] = 'filename="{}"'.format(filename) |
|
||||
self.write(content) |
|
||||
|
|
||||
|
|
||||
def render_to_pdf(request, template_name, context=None, filename=None): |
|
||||
# Request is not needed and only included to make the signature conform to django's render function |
|
||||
pdf = compile_template_to_pdf(template_name, context) |
|
||||
return PDFResponse(pdf, filename=filename) |
|
||||
@ -0,0 +1,33 @@ |
|||||
|
# Generated by Django 2.1 on 2019-09-12 07:51 |
||||
|
|
||||
|
import django.core.validators |
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
def update(apps, schema_editor): |
||||
|
Keg = apps.get_model('gestion', 'Keg') |
||||
|
for keg in Keg.objects.all(): |
||||
|
keg.deg = keg.pinte.deg |
||||
|
keg.save() |
||||
|
|
||||
|
def reverse(apps, schema_editor): |
||||
|
pass |
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('gestion', '0013_auto_20190829_1219'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='historicalkeg', |
||||
|
name='deg', |
||||
|
field=models.DecimalField(decimal_places=2, default=0, max_digits=5, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Degré'), |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='keg', |
||||
|
name='deg', |
||||
|
field=models.DecimalField(decimal_places=2, default=0, max_digits=5, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Degré'), |
||||
|
), |
||||
|
migrations.RunPython(update, reverse) |
||||
|
] |
||||
@ -0,0 +1,31 @@ |
|||||
|
# Generated by Django 2.1 on 2019-09-08 09:59 |
||||
|
|
||||
|
from django.conf import settings |
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
||||
|
('preferences', '0018_auto_20190627_2302'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name='Improvement', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('title', models.CharField(max_length=255)), |
||||
|
('mode', models.IntegerField(choices=[(0, 'Bug'), (1, 'Amélioration'), (2, 'Nouvelle fonctionnalité')])), |
||||
|
('description', models.TextField()), |
||||
|
('seen', models.BooleanField(default=False)), |
||||
|
('done', models.BooleanField(default=False)), |
||||
|
('coopeman', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='improvement_submitted', to=settings.AUTH_USER_MODEL)), |
||||
|
], |
||||
|
options={ |
||||
|
'verbose_name': 'Amélioration', |
||||
|
}, |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,39 @@ |
|||||
|
# Generated by Django 2.1 on 2019-09-08 10:17 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('preferences', '0019_improvement'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='improvement', |
||||
|
name='date', |
||||
|
field=models.DateTimeField(auto_now_add=True, default='2019-09-08 00:00'), |
||||
|
preserve_default=False, |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='improvement', |
||||
|
name='done', |
||||
|
field=models.BooleanField(default=False, verbose_name='Fait ?'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='improvement', |
||||
|
name='mode', |
||||
|
field=models.IntegerField(choices=[(0, 'Bug'), (1, 'Amélioration'), (2, 'Nouvelle fonctionnalité')], verbose_name='Type'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='improvement', |
||||
|
name='seen', |
||||
|
field=models.BooleanField(default=False, verbose_name='Vu ?'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='improvement', |
||||
|
name='title', |
||||
|
field=models.CharField(max_length=255, verbose_name='Titre'), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,21 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block entete %}Amélioration {{improvement.title}}{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">{{improvement.title}}</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>{{improvement.title}}</h2> |
||||
|
</header> |
||||
|
<a href="{% url 'preferences:improvementsIndex' %}" class="button">Retour à la liste des améliorations</a><br><br> |
||||
|
<strong>Titre : </strong> {{improvement.title}}<br> |
||||
|
<strong>Type : </strong> {{improvement.get_mode_display}}<br> |
||||
|
<strong>Date : </strong> {{improvement.date}}<br> |
||||
|
<strong>Fait : </strong> {{improvement.done|yesno:"Oui,Non"}}<br> |
||||
|
<strong>Coopeman : </strong> {{improvement.coopeman}}<br> |
||||
|
<strong>Description : </strong> {{improvement.description}}<br> |
||||
|
</section> |
||||
|
{% endblock %} |
||||
@ -0,0 +1,68 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% block entete %}Améliorations{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">Liste des améliorations à faire</a></li> |
||||
|
<li><a href="#seconde">Liste des améliorations faîtes</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Liste des améliorations à faire</h2> |
||||
|
</header> |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Titre</th> |
||||
|
<th>Type</th> |
||||
|
<th>Vu ?</th> |
||||
|
<th>Date</th> |
||||
|
<th>Administration</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for improvement in todo_improvements %} |
||||
|
<tr> |
||||
|
<td>{{improvement.title}}</td> |
||||
|
<td>{{improvement.get_mode_display}}</td> |
||||
|
<td><i class="fa fa-{{improvement.seen|yesno:'check,times'}}"></i></td> |
||||
|
<td>{{improvement.date}}</td> |
||||
|
<td><a href="{% url 'preferences:improvementProfile' improvement.pk %}" class="button small"><i class="fa fa-eye"></i> Voir</a> <a href="{% url 'preferences:changeImprovementState' improvement.pk %}" class="button small"><i class="fa fa-check"></i> Passer en fait</a> <a href="{% url 'preferences:deleteImprovement' improvement.pk %}" class="button small"><i class="fa fa-trash"></i> Supprimer</a></td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</section> |
||||
|
<section id="second" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Liste des améliorations faîtes</h2> |
||||
|
</header> |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Titre</th> |
||||
|
<th>Type</th> |
||||
|
<th>Vu ?</th> |
||||
|
<th>Date</th> |
||||
|
<th>Administration</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for improvement in done_improvements %} |
||||
|
<tr> |
||||
|
<td>{{improvement.title}}</td> |
||||
|
<td>{{improvement.get_mode_display}}</td> |
||||
|
<td><i class="fa fa-{{improvement.seen|yesno:'check,times'}}"></i></td> |
||||
|
<td>{{improvement.date}}</td> |
||||
|
<td><a href="{% url 'preferences:improvementProfile' improvement.pk %}" class="button small"><i class="fa fa-eye"></i> Voir</a> <a href="{% url 'preferences:changeImprovementState' improvement.pk %}" class="button small"><i class="fa fa-check"></i> Passer en non fait</a> <a href="{% url 'preferences:deleteImprovement' improvement.pk %}" class="button small"><i class="fa fa-trash"></i> Supprimer</a></td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</section> |
||||
|
{% endblock %} |
||||
@ -0,0 +1,3 @@ |
|||||
|
from django.contrib import admin |
||||
|
|
||||
|
# Register your models here. |
||||
@ -0,0 +1,5 @@ |
|||||
|
from django.apps import AppConfig |
||||
|
|
||||
|
|
||||
|
class SearchConfig(AppConfig): |
||||
|
name = 'search' |
||||
@ -0,0 +1,3 @@ |
|||||
|
from django.db import models |
||||
|
|
||||
|
# Create your models here. |
||||
@ -0,0 +1,224 @@ |
|||||
|
{% extends 'base.html' %} |
||||
|
{% block entete %}Recherche{% endblock %} |
||||
|
{% block navbar%} |
||||
|
<ul> |
||||
|
{% if perms.auth.view_user %} |
||||
|
<li><a href="#first">Utilisateurs ({{users.count}})</a></li> |
||||
|
{% endif %} |
||||
|
{% if perms.gestion.view_product %} |
||||
|
<li><a href="#second">Produits ({{products.count}})</a></li> |
||||
|
{% endif %} |
||||
|
{% if perms.gestion.view_keg %} |
||||
|
<li><a href="#third">Fûts ({{kegs.count}})</a></li> |
||||
|
{% endif %} |
||||
|
{% if perms.gestion.view_menu %} |
||||
|
<li><a href="#fourth">Menus ({{menus.count}})</a></li> |
||||
|
{% endif %} |
||||
|
{% if perms.auth.view_group %} |
||||
|
<li><a href="#fifth">Groupes ({{groups.count}})</a></li> |
||||
|
{% endif %} |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
{% if perms.auth.view_user %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Résultats dans les utilisateurs ({{users.count}} résultat{% if users.count != 1 %}s{% endif %})</h2> |
||||
|
</header> |
||||
|
<section> |
||||
|
{% if users.count %} |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Nom d'utilisateur</th> |
||||
|
<th>Prénom Nom</th> |
||||
|
<th>Solde</th> |
||||
|
<th>Fin d'adhésion</th> |
||||
|
<th>Staff</th> |
||||
|
<th>Profil</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for user in users %} |
||||
|
<tr> |
||||
|
<td>{{user.username}}</td> |
||||
|
<td>{{user.first_name}} {{user.last_name}}</td> |
||||
|
<td>{{user.profile.balance}} €</td> |
||||
|
<td>{% if user.profile.is_adherent %}{{user.profile.cotisationEnd}}{% else %}Non adhérent{% endif%}</td> |
||||
|
<td><i class="fa fa-{{user.is_staff|yesno:'check,times'}}"></i></td> |
||||
|
<td><a class="button small" href="{% url 'users:profile' user.pk %}"><i class="fa fa-user"></i> Profil</a></td> |
||||
|
</tr> |
||||
|
{%endfor%} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
{% else %} |
||||
|
Aucun résultat n'a pu être trouvé. |
||||
|
{% endif %} |
||||
|
</section> |
||||
|
</section> |
||||
|
{% endif %} |
||||
|
{% if perms.gestion.view_product %} |
||||
|
<section id="second" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Résultats dans les produits ({{products.count}} résultat{% if products.count != 1 %}s{% endif %})</h2> |
||||
|
</header> |
||||
|
<section> |
||||
|
{% if products.count %} |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Nom</th> |
||||
|
<th>Prix</th> |
||||
|
<th>Actif</th> |
||||
|
<th>Catégorie</th> |
||||
|
<th>Adhérent</th> |
||||
|
<th>Stock</th> |
||||
|
<th>Volume</th> |
||||
|
<th>Degré</th> |
||||
|
<th>Administration</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for product in products %} |
||||
|
<tr> |
||||
|
<td>{{product.name}}</td> |
||||
|
<td>{{product.amount}} €</td> |
||||
|
<td><i class="fa fa-{{product.is_active|yesno:'check,times'}}"></i></td> |
||||
|
<td>{{product.category}}</td> |
||||
|
<td><i class="fa fa-{{product.adherentRequired|yesno:'check,times'}}"></i></td> |
||||
|
<td>{{product.stock}}</td> |
||||
|
<td>{{product.volume}} cl</td> |
||||
|
<td>{{product.deg}}</td> |
||||
|
<td>{% if perms.gestion.change_product %}<a class="button small" href="{% url 'gestion:switchActivate' product.pk %}"><i class="fa fa-check-circle"></i> {{product.is_active|yesno:"Désa,A"}}ctiver</a> <a class="button small" href="{% url 'gestion:editProduct' product.pk %}"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td> |
||||
|
</tr> |
||||
|
{%endfor%} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
{% else %} |
||||
|
Aucun résultat n'a pu être trouvé. |
||||
|
{% endif %} |
||||
|
</section> |
||||
|
</section> |
||||
|
{% endif %} |
||||
|
{% if perms.gestion.view_keg %} |
||||
|
<section id="third" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Résultats dans les fûts ({{kegs.count}} résultat{% if kegs.count != 1 %}s{% endif %})</h2> |
||||
|
</header> |
||||
|
<section> |
||||
|
{% if kegs.count %} |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Nom</th> |
||||
|
<th>Stock</th> |
||||
|
<th>Capacité</th> |
||||
|
<th>Actif</th> |
||||
|
<th>Prix du fût</th> |
||||
|
<th>Degré</th> |
||||
|
<th>Historique</th> |
||||
|
<th>Administration</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for keg in kegs %} |
||||
|
<tr> |
||||
|
<td>{{keg.name}}</td> |
||||
|
<td>{{keg.stockHold}}</td> |
||||
|
<td>{{keg.capacity}} L</td> |
||||
|
<td><i class="fa fa-{{keg.is_active|yesno:'check,times'}}"></i></td> |
||||
|
<td>{{keg.amount}} €</td> |
||||
|
<td>{{keg.deg}}°</td> |
||||
|
<td><a href="{% url 'gestion:kegH' keg.pk %}" class="button small"><i class="fa fa-history"></i> Voir</a></td> |
||||
|
<td>{% if perms.gestion.change_keg %}<a class="button small" href="{% url 'gestion:editKeg' keg.pk %}"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td> |
||||
|
</tr> |
||||
|
{%endfor%} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
{% else %} |
||||
|
Aucun résultat n'a pu être trouvé. |
||||
|
{% endif %} |
||||
|
</section> |
||||
|
</section> |
||||
|
{% endif %} |
||||
|
{% if perms.gestion.view_menu %} |
||||
|
<section id="fourth" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Résultats dans les menus ({{menus.count}} résultat{% if menus.count != 1 %}s{% endif %})</h2> |
||||
|
</header> |
||||
|
<section> |
||||
|
{% if menus.count %} |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Nom</th> |
||||
|
<th>Prix</th> |
||||
|
<th>Actif</th> |
||||
|
<th>Adhérent</th> |
||||
|
<th>Nombre de produit</th> |
||||
|
<th>Administration</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for menu in menus %} |
||||
|
<tr> |
||||
|
<td>{{menu.name}}</td> |
||||
|
<td>{{menu.amount}} €</td> |
||||
|
<td><i class="fa fa-{{menu.is_active|yesno:'check,times'}}"></i></td> |
||||
|
<td><i class="fa fa-{{menu.adherentRequired|yesno:'check,times'}}"></i></td> |
||||
|
<td>{{menu.articles.count}}</td> |
||||
|
<td>{% if perms.gestion.change_menu %}<a class="button small" href="{% url 'gestion:switchActivateMenu' menu.pk %}"><i class="fa fa-check-circle"></i> {{menu_is_active|yesno:"Désa,A"}}ctiver</a> <a class="button small" href="{% url 'gestion:editMenu' menu.pk %}"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td> |
||||
|
</tr> |
||||
|
{%endfor%} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
{% else %} |
||||
|
Aucun résultat n'a pu être trouvé. |
||||
|
{% endif %} |
||||
|
</section> |
||||
|
</section> |
||||
|
{% endif %} |
||||
|
{% if perms.auth.view_group %} |
||||
|
<section id="fifth" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Résultats dans les groupes ({{groups.count}} résultat{% if groups.count != 1 %}s{% endif %})</h2> |
||||
|
</header> |
||||
|
<section> |
||||
|
{% if groups.count %} |
||||
|
<div class="table-wrapper"> |
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Nom</th> |
||||
|
<th>Nombre de droits</th> |
||||
|
<th>Nombre d'utilisateurs</th> |
||||
|
<th>Administrer</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for group in groups %} |
||||
|
<tr> |
||||
|
<td>{{group.name}}</td> |
||||
|
<td>{{group.permissions.count}}</td> |
||||
|
<td>{{group.user_set.count}}</td> |
||||
|
<td><a href="{% url 'users:groupProfile' group.pk %}" class="button small"><i class="fa fa-eye"></i> Voir</a>{% if perms.auth.change_group %}<a href="{% url 'users:editGroup' group.pk %}" class="button small"><i class="fa fa-pencil-alt"></i> Modifier</a>{% endif %}</td> |
||||
|
</tr> |
||||
|
{%endfor%} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
{% else %} |
||||
|
Aucun résultat n'a pu être trouvé. |
||||
|
{% endif %} |
||||
|
</section> |
||||
|
</section> |
||||
|
{% endif %} |
||||
|
{% endblock %} |
||||
@ -0,0 +1,3 @@ |
|||||
|
from django.test import TestCase |
||||
|
|
||||
|
# Create your tests here. |
||||
@ -0,0 +1,8 @@ |
|||||
|
from django.urls import path |
||||
|
|
||||
|
from . import views |
||||
|
|
||||
|
app_name="search" |
||||
|
urlpatterns = [ |
||||
|
path('search', views.search, name="search"), |
||||
|
] |
||||
@ -0,0 +1,25 @@ |
|||||
|
from django.shortcuts import render |
||||
|
from django.db.models import Q |
||||
|
from django.contrib.auth.models import User, Group |
||||
|
from django.contrib.auth.decorators import login_required |
||||
|
|
||||
|
from coopeV3.acl import active_required |
||||
|
from gestion.models import Product, Menu, Keg |
||||
|
|
||||
|
@active_required |
||||
|
@login_required |
||||
|
def search(request): |
||||
|
q = request.GET.get("q") |
||||
|
if q: |
||||
|
users = User.objects.filter(Q(username__icontains=q) | Q(first_name__icontains=q) | Q(last_name__icontains=q)) |
||||
|
products = Product.objects.filter(name__icontains=q) |
||||
|
kegs = Keg.objects.filter(name__icontains=q) |
||||
|
menus = Menu.objects.filter(name__icontains=q) |
||||
|
groups = Group.objects.filter(name__icontains=q) |
||||
|
else: |
||||
|
users = User.objects.none() |
||||
|
products = Product.objects.none() |
||||
|
kegs = Keg.objects.none() |
||||
|
menus = Menu.objects.none() |
||||
|
groups = Group.objects.none() |
||||
|
return render(request, "search/search.html", {"q": q, "users": users, "products": products, "kegs": kegs, "menus": menus, "groups": groups}) |
||||
@ -0,0 +1,28 @@ |
|||||
|
/* The container <div> - needed to position the dropdown content */ |
||||
|
.dropdown { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
} |
||||
|
|
||||
|
/* Dropdown Content (Hidden by Default) */ |
||||
|
.dropdown-content { |
||||
|
display: none; |
||||
|
position: absolute; |
||||
|
background-color: #f1f1f1; |
||||
|
min-width: 160px; |
||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); |
||||
|
z-index: 1; |
||||
|
} |
||||
|
|
||||
|
/* Links inside the dropdown */ |
||||
|
.dropdown-content a { |
||||
|
color: black; |
||||
|
padding: 12px 16px; |
||||
|
text-decoration: none; |
||||
|
display: block; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
/* Show the dropdown menu (use JS to add this class to the .dropdown-content container when the user clicks on the dropdown button) */ |
||||
|
.show { |
||||
|
display:block; |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
/* When the user clicks on the button, |
||||
|
toggle between hiding and showing the dropdown content */ |
||||
|
function dropdown(target) { |
||||
|
var dropdowns = document.getElementsByClassName("dropdown-content"); |
||||
|
var i; |
||||
|
for (i = 0; i < dropdowns.length; i++) { |
||||
|
var openDropdown = dropdowns[i]; |
||||
|
if (openDropdown.classList.contains('show')) { |
||||
|
openDropdown.classList.remove('show'); |
||||
|
} |
||||
|
} |
||||
|
document.getElementById(target).classList.toggle("show"); |
||||
|
} |
||||
|
|
||||
|
// Close the dropdown menu if the user clicks outside of it
|
||||
|
window.onclick = function(event) { |
||||
|
if (!event.target.matches('.dropbtn')) { |
||||
|
var dropdowns = document.getElementsByClassName("dropdown-content"); |
||||
|
var i; |
||||
|
for (i = 0; i < dropdowns.length; i++) { |
||||
|
var openDropdown = dropdowns[i]; |
||||
|
if (openDropdown.classList.contains('show')) { |
||||
|
openDropdown.classList.remove('show'); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
/* breakpoints.js v1.0 | @ajlkn | MIT licensed */ |
||||
|
var breakpoints=function(){"use strict";function e(e){t.init(e)}var t={list:null,media:{},events:[],init:function(e){t.list=e,window.addEventListener("resize",t.poll),window.addEventListener("orientationchange",t.poll),window.addEventListener("load",t.poll),window.addEventListener("fullscreenchange",t.poll)},active:function(e){var n,a,s,i,r,d,c;if(!(e in t.media)){if(">="==e.substr(0,2)?(a="gte",n=e.substr(2)):"<="==e.substr(0,2)?(a="lte",n=e.substr(2)):">"==e.substr(0,1)?(a="gt",n=e.substr(1)):"<"==e.substr(0,1)?(a="lt",n=e.substr(1)):"!"==e.substr(0,1)?(a="not",n=e.substr(1)):(a="eq",n=e),n&&n in t.list)if(i=t.list[n],Array.isArray(i)){if(r=parseInt(i[0]),d=parseInt(i[1]),isNaN(r)){if(isNaN(d))return;c=i[1].substr(String(d).length)}else c=i[0].substr(String(r).length);if(isNaN(r))switch(a){case"gte":s="screen";break;case"lte":s="screen and (max-width: "+d+c+")";break;case"gt":s="screen and (min-width: "+(d+1)+c+")";break;case"lt":s="screen and (max-width: -1px)";break;case"not":s="screen and (min-width: "+(d+1)+c+")";break;default:s="screen and (max-width: "+d+c+")"}else if(isNaN(d))switch(a){case"gte":s="screen and (min-width: "+r+c+")";break;case"lte":s="screen";break;case"gt":s="screen and (max-width: -1px)";break;case"lt":s="screen and (max-width: "+(r-1)+c+")";break;case"not":s="screen and (max-width: "+(r-1)+c+")";break;default:s="screen and (min-width: "+r+c+")"}else switch(a){case"gte":s="screen and (min-width: "+r+c+")";break;case"lte":s="screen and (max-width: "+d+c+")";break;case"gt":s="screen and (min-width: "+(d+1)+c+")";break;case"lt":s="screen and (max-width: "+(r-1)+c+")";break;case"not":s="screen and (max-width: "+(r-1)+c+"), screen and (min-width: "+(d+1)+c+")";break;default:s="screen and (min-width: "+r+c+") and (max-width: "+d+c+")"}}else s="("==i.charAt(0)?"screen and "+i:i;t.media[e]=!!s&&s}return t.media[e]!==!1&&window.matchMedia(t.media[e]).matches},on:function(e,n){t.events.push({query:e,handler:n,state:!1}),t.active(e)&&n()},poll:function(){var e,n;for(e=0;e<t.events.length;e++)n=t.events[e],t.active(n.query)?n.state||(n.state=!0,n.handler()):n.state&&(n.state=!1)}};return e._=t,e.on=function(e,n){t.on(e,n)},e.active=function(e){return t.active(e)},e}();!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?module.exports=t():e.breakpoints=t()}(this,function(){return breakpoints}); |
||||
@ -0,0 +1,2 @@ |
|||||
|
/* browser.js v1.0 | @ajlkn | MIT licensed */ |
||||
|
var browser=function(){"use strict";var e={name:null,version:null,os:null,osVersion:null,touch:null,mobile:null,_canUse:null,canUse:function(n){e._canUse||(e._canUse=document.createElement("div"));var o=e._canUse.style,r=n.charAt(0).toUpperCase()+n.slice(1);return n in o||"Moz"+r in o||"Webkit"+r in o||"O"+r in o||"ms"+r in o},init:function(){var n,o,r,i,t=navigator.userAgent;for(n="other",o=0,r=[["firefox",/Firefox\/([0-9\.]+)/],["bb",/BlackBerry.+Version\/([0-9\.]+)/],["bb",/BB[0-9]+.+Version\/([0-9\.]+)/],["opera",/OPR\/([0-9\.]+)/],["opera",/Opera\/([0-9\.]+)/],["edge",/Edge\/([0-9\.]+)/],["safari",/Version\/([0-9\.]+).+Safari/],["chrome",/Chrome\/([0-9\.]+)/],["ie",/MSIE ([0-9]+)/],["ie",/Trident\/.+rv:([0-9]+)/]],i=0;i<r.length;i++)if(t.match(r[i][1])){n=r[i][0],o=parseFloat(RegExp.$1);break}for(e.name=n,e.version=o,n="other",o=0,r=[["ios",/([0-9_]+) like Mac OS X/,function(e){return e.replace("_",".").replace("_","")}],["ios",/CPU like Mac OS X/,function(e){return 0}],["wp",/Windows Phone ([0-9\.]+)/,null],["android",/Android ([0-9\.]+)/,null],["mac",/Macintosh.+Mac OS X ([0-9_]+)/,function(e){return e.replace("_",".").replace("_","")}],["windows",/Windows NT ([0-9\.]+)/,null],["bb",/BlackBerry.+Version\/([0-9\.]+)/,null],["bb",/BB[0-9]+.+Version\/([0-9\.]+)/,null],["linux",/Linux/,null],["bsd",/BSD/,null],["unix",/X11/,null]],i=0;i<r.length;i++)if(t.match(r[i][1])){n=r[i][0],o=parseFloat(r[i][2]?r[i][2](RegExp.$1):RegExp.$1);break}e.os=n,e.osVersion=o,e.touch="wp"==e.os?navigator.msMaxTouchPoints>0:!!("ontouchstart"in window),e.mobile="wp"==e.os||"android"==e.os||"ios"==e.os||"bb"==e.os}};return e.init(),e}();!function(e,n){"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?module.exports=n():e.browser=n()}(this,function(){return browser}); |
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@ |
|||||
|
/* jquery.scrollex v0.2.1 | (c) @ajlkn | github.com/ajlkn/jquery.scrollex | MIT licensed */ |
||||
|
!function(t){function e(t,e,n){return"string"==typeof t&&("%"==t.slice(-1)?t=parseInt(t.substring(0,t.length-1))/100*e:"vh"==t.slice(-2)?t=parseInt(t.substring(0,t.length-2))/100*n:"px"==t.slice(-2)&&(t=parseInt(t.substring(0,t.length-2)))),t}var n=t(window),i=1,o={};n.on("scroll",function(){var e=n.scrollTop();t.map(o,function(t){window.clearTimeout(t.timeoutId),t.timeoutId=window.setTimeout(function(){t.handler(e)},t.options.delay)})}).on("load",function(){n.trigger("scroll")}),jQuery.fn.scrollex=function(l){var s=t(this);if(0==this.length)return s;if(this.length>1){for(var r=0;r<this.length;r++)t(this[r]).scrollex(l);return s}if(s.data("_scrollexId"))return s;var a,u,h,c,p;switch(a=i++,u=jQuery.extend({top:0,bottom:0,delay:0,mode:"default",enter:null,leave:null,initialize:null,terminate:null,scroll:null},l),u.mode){case"top":h=function(t,e,n,i,o){return t>=i&&o>=t};break;case"bottom":h=function(t,e,n,i,o){return n>=i&&o>=n};break;case"middle":h=function(t,e,n,i,o){return e>=i&&o>=e};break;case"top-only":h=function(t,e,n,i,o){return i>=t&&n>=i};break;case"bottom-only":h=function(t,e,n,i,o){return n>=o&&o>=t};break;default:case"default":h=function(t,e,n,i,o){return n>=i&&o>=t}}return c=function(t){var i,o,l,s,r,a,u=this.state,h=!1,c=this.$element.offset();i=n.height(),o=t+i/2,l=t+i,s=this.$element.outerHeight(),r=c.top+e(this.options.top,s,i),a=c.top+s-e(this.options.bottom,s,i),h=this.test(t,o,l,r,a),h!=u&&(this.state=h,h?this.options.enter&&this.options.enter.apply(this.element):this.options.leave&&this.options.leave.apply(this.element)),this.options.scroll&&this.options.scroll.apply(this.element,[(o-r)/(a-r)])},p={id:a,options:u,test:h,handler:c,state:null,element:this,$element:s,timeoutId:null},o[a]=p,s.data("_scrollexId",p.id),p.options.initialize&&p.options.initialize.apply(this),s},jQuery.fn.unscrollex=function(){var e=t(this);if(0==this.length)return e;if(this.length>1){for(var n=0;n<this.length;n++)t(this[n]).unscrollex();return e}var i,l;return(i=e.data("_scrollexId"))?(l=o[i],window.clearTimeout(l.timeoutId),delete o[i],e.removeData("_scrollexId"),l.options.terminate&&l.options.terminate.apply(this),e):e}}(jQuery); |
||||
@ -0,0 +1,2 @@ |
|||||
|
/* jquery.scrolly v1.0.0-dev | (c) @ajlkn | MIT licensed */ |
||||
|
(function(e){function u(s,o){var u,a,f;if((u=e(s))[t]==0)return n;a=u[i]()[r];switch(o.anchor){case"middle":f=a-(e(window).height()-u.outerHeight())/2;break;default:case r:f=Math.max(a,0)}return typeof o[i]=="function"?f-=o[i]():f-=o[i],f}var t="length",n=null,r="top",i="offset",s="click.scrolly",o=e(window);e.fn.scrolly=function(i){var o,a,f,l,c=e(this);if(this[t]==0)return c;if(this[t]>1){for(o=0;o<this[t];o++)e(this[o]).scrolly(i);return c}l=n,f=c.attr("href");if(f.charAt(0)!="#"||f[t]<2)return c;a=jQuery.extend({anchor:r,easing:"swing",offset:0,parent:e("body,html"),pollOnce:!1,speed:1e3},i),a.pollOnce&&(l=u(f,a)),c.off(s).on(s,function(e){var t=l!==n?l:u(f,a);t!==n&&(e.preventDefault(),a.parent.stop().animate({scrollTop:t},a.speed,a.easing))})}})(jQuery); |
||||
@ -0,0 +1,123 @@ |
|||||
|
/* |
||||
|
Stellar by HTML5 UP |
||||
|
html5up.net | @ajlkn |
||||
|
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license) |
||||
|
*/ |
||||
|
|
||||
|
(function($) { |
||||
|
|
||||
|
var $window = $(window), |
||||
|
$body = $('body'), |
||||
|
$main = $('#main'); |
||||
|
|
||||
|
// Breakpoints.
|
||||
|
breakpoints({ |
||||
|
xlarge: [ '1281px', '1680px' ], |
||||
|
large: [ '981px', '1280px' ], |
||||
|
medium: [ '737px', '980px' ], |
||||
|
small: [ '481px', '736px' ], |
||||
|
xsmall: [ '361px', '480px' ], |
||||
|
xxsmall: [ null, '360px' ] |
||||
|
}); |
||||
|
|
||||
|
// Play initial animations on page load.
|
||||
|
$window.on('load', function() { |
||||
|
window.setTimeout(function() { |
||||
|
$body.removeClass('is-preload'); |
||||
|
}, 100); |
||||
|
}); |
||||
|
|
||||
|
// Nav.
|
||||
|
var $nav = $('#nav'); |
||||
|
|
||||
|
if ($nav.length > 0) { |
||||
|
|
||||
|
// Shrink effect.
|
||||
|
$main |
||||
|
.scrollex({ |
||||
|
mode: 'top', |
||||
|
enter: function() { |
||||
|
$nav.addClass('alt'); |
||||
|
}, |
||||
|
leave: function() { |
||||
|
$nav.removeClass('alt'); |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
// Links.
|
||||
|
var $nav_a = $nav.find('a'); |
||||
|
|
||||
|
$nav_a |
||||
|
.scrolly({ |
||||
|
speed: 1000, |
||||
|
offset: function() { return $nav.height(); } |
||||
|
}) |
||||
|
.on('click', function() { |
||||
|
|
||||
|
var $this = $(this); |
||||
|
|
||||
|
// External link? Bail.
|
||||
|
if ($this.attr('href').charAt(0) != '#') |
||||
|
return; |
||||
|
|
||||
|
// Deactivate all links.
|
||||
|
$nav_a |
||||
|
.removeClass('active') |
||||
|
.removeClass('active-locked'); |
||||
|
|
||||
|
// Activate link *and* lock it (so Scrollex doesn't try to activate other links as we're scrolling to this one's section).
|
||||
|
$this |
||||
|
.addClass('active') |
||||
|
.addClass('active-locked'); |
||||
|
|
||||
|
}) |
||||
|
.each(function() { |
||||
|
|
||||
|
var $this = $(this), |
||||
|
id = $this.attr('href'), |
||||
|
$section = $(id); |
||||
|
|
||||
|
// No section for this link? Bail.
|
||||
|
if ($section.length < 1) |
||||
|
return; |
||||
|
|
||||
|
// Scrollex.
|
||||
|
$section.scrollex({ |
||||
|
mode: 'middle', |
||||
|
initialize: function() { |
||||
|
|
||||
|
// Deactivate section.
|
||||
|
if (browser.canUse('transition')) |
||||
|
$section.addClass('inactive'); |
||||
|
|
||||
|
}, |
||||
|
enter: function() { |
||||
|
|
||||
|
// Activate section.
|
||||
|
$section.removeClass('inactive'); |
||||
|
|
||||
|
// No locked links? Deactivate all links and activate this section's one.
|
||||
|
if ($nav_a.filter('.active-locked').length == 0) { |
||||
|
|
||||
|
$nav_a.removeClass('active'); |
||||
|
$this.addClass('active'); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Otherwise, if this section's link is the one that's locked, unlock it.
|
||||
|
else if ($this.hasClass('active-locked')) |
||||
|
$this.removeClass('active-locked'); |
||||
|
|
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Scrolly.
|
||||
|
$('.scrolly').scrolly({ |
||||
|
speed: 1000 |
||||
|
}); |
||||
|
|
||||
|
})(jQuery); |
||||
@ -0,0 +1,587 @@ |
|||||
|
(function($) { |
||||
|
|
||||
|
/** |
||||
|
* Generate an indented list of links from a nav. Meant for use with panel(). |
||||
|
* @return {jQuery} jQuery object. |
||||
|
*/ |
||||
|
$.fn.navList = function() { |
||||
|
|
||||
|
var $this = $(this); |
||||
|
$a = $this.find('a'), |
||||
|
b = []; |
||||
|
|
||||
|
$a.each(function() { |
||||
|
|
||||
|
var $this = $(this), |
||||
|
indent = Math.max(0, $this.parents('li').length - 1), |
||||
|
href = $this.attr('href'), |
||||
|
target = $this.attr('target'); |
||||
|
|
||||
|
b.push( |
||||
|
'<a ' + |
||||
|
'class="link depth-' + indent + '"' + |
||||
|
( (typeof target !== 'undefined' && target != '') ? ' target="' + target + '"' : '') + |
||||
|
( (typeof href !== 'undefined' && href != '') ? ' href="' + href + '"' : '') + |
||||
|
'>' + |
||||
|
'<span class="indent-' + indent + '"></span>' + |
||||
|
$this.text() + |
||||
|
'</a>' |
||||
|
); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
return b.join(''); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Panel-ify an element. |
||||
|
* @param {object} userConfig User config. |
||||
|
* @return {jQuery} jQuery object. |
||||
|
*/ |
||||
|
$.fn.panel = function(userConfig) { |
||||
|
|
||||
|
// No elements?
|
||||
|
if (this.length == 0) |
||||
|
return $this; |
||||
|
|
||||
|
// Multiple elements?
|
||||
|
if (this.length > 1) { |
||||
|
|
||||
|
for (var i=0; i < this.length; i++) |
||||
|
$(this[i]).panel(userConfig); |
||||
|
|
||||
|
return $this; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Vars.
|
||||
|
var $this = $(this), |
||||
|
$body = $('body'), |
||||
|
$window = $(window), |
||||
|
id = $this.attr('id'), |
||||
|
config; |
||||
|
|
||||
|
// Config.
|
||||
|
config = $.extend({ |
||||
|
|
||||
|
// Delay.
|
||||
|
delay: 0, |
||||
|
|
||||
|
// Hide panel on link click.
|
||||
|
hideOnClick: false, |
||||
|
|
||||
|
// Hide panel on escape keypress.
|
||||
|
hideOnEscape: false, |
||||
|
|
||||
|
// Hide panel on swipe.
|
||||
|
hideOnSwipe: false, |
||||
|
|
||||
|
// Reset scroll position on hide.
|
||||
|
resetScroll: false, |
||||
|
|
||||
|
// Reset forms on hide.
|
||||
|
resetForms: false, |
||||
|
|
||||
|
// Side of viewport the panel will appear.
|
||||
|
side: null, |
||||
|
|
||||
|
// Target element for "class".
|
||||
|
target: $this, |
||||
|
|
||||
|
// Class to toggle.
|
||||
|
visibleClass: 'visible' |
||||
|
|
||||
|
}, userConfig); |
||||
|
|
||||
|
// Expand "target" if it's not a jQuery object already.
|
||||
|
if (typeof config.target != 'jQuery') |
||||
|
config.target = $(config.target); |
||||
|
|
||||
|
// Panel.
|
||||
|
|
||||
|
// Methods.
|
||||
|
$this._hide = function(event) { |
||||
|
|
||||
|
// Already hidden? Bail.
|
||||
|
if (!config.target.hasClass(config.visibleClass)) |
||||
|
return; |
||||
|
|
||||
|
// If an event was provided, cancel it.
|
||||
|
if (event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
event.stopPropagation(); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Hide.
|
||||
|
config.target.removeClass(config.visibleClass); |
||||
|
|
||||
|
// Post-hide stuff.
|
||||
|
window.setTimeout(function() { |
||||
|
|
||||
|
// Reset scroll position.
|
||||
|
if (config.resetScroll) |
||||
|
$this.scrollTop(0); |
||||
|
|
||||
|
// Reset forms.
|
||||
|
if (config.resetForms) |
||||
|
$this.find('form').each(function() { |
||||
|
this.reset(); |
||||
|
}); |
||||
|
|
||||
|
}, config.delay); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
// Vendor fixes.
|
||||
|
$this |
||||
|
.css('-ms-overflow-style', '-ms-autohiding-scrollbar') |
||||
|
.css('-webkit-overflow-scrolling', 'touch'); |
||||
|
|
||||
|
// Hide on click.
|
||||
|
if (config.hideOnClick) { |
||||
|
|
||||
|
$this.find('a') |
||||
|
.css('-webkit-tap-highlight-color', 'rgba(0,0,0,0)'); |
||||
|
|
||||
|
$this |
||||
|
.on('click', 'a', function(event) { |
||||
|
|
||||
|
var $a = $(this), |
||||
|
href = $a.attr('href'), |
||||
|
target = $a.attr('target'); |
||||
|
|
||||
|
if (!href || href == '#' || href == '' || href == '#' + id) |
||||
|
return; |
||||
|
|
||||
|
// Cancel original event.
|
||||
|
event.preventDefault(); |
||||
|
event.stopPropagation(); |
||||
|
|
||||
|
// Hide panel.
|
||||
|
$this._hide(); |
||||
|
|
||||
|
// Redirect to href.
|
||||
|
window.setTimeout(function() { |
||||
|
|
||||
|
if (target == '_blank') |
||||
|
window.open(href); |
||||
|
else |
||||
|
window.location.href = href; |
||||
|
|
||||
|
}, config.delay + 10); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Event: Touch stuff.
|
||||
|
$this.on('touchstart', function(event) { |
||||
|
|
||||
|
$this.touchPosX = event.originalEvent.touches[0].pageX; |
||||
|
$this.touchPosY = event.originalEvent.touches[0].pageY; |
||||
|
|
||||
|
}) |
||||
|
|
||||
|
$this.on('touchmove', function(event) { |
||||
|
|
||||
|
if ($this.touchPosX === null |
||||
|
|| $this.touchPosY === null) |
||||
|
return; |
||||
|
|
||||
|
var diffX = $this.touchPosX - event.originalEvent.touches[0].pageX, |
||||
|
diffY = $this.touchPosY - event.originalEvent.touches[0].pageY, |
||||
|
th = $this.outerHeight(), |
||||
|
ts = ($this.get(0).scrollHeight - $this.scrollTop()); |
||||
|
|
||||
|
// Hide on swipe?
|
||||
|
if (config.hideOnSwipe) { |
||||
|
|
||||
|
var result = false, |
||||
|
boundary = 20, |
||||
|
delta = 50; |
||||
|
|
||||
|
switch (config.side) { |
||||
|
|
||||
|
case 'left': |
||||
|
result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX > delta); |
||||
|
break; |
||||
|
|
||||
|
case 'right': |
||||
|
result = (diffY < boundary && diffY > (-1 * boundary)) && (diffX < (-1 * delta)); |
||||
|
break; |
||||
|
|
||||
|
case 'top': |
||||
|
result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY > delta); |
||||
|
break; |
||||
|
|
||||
|
case 'bottom': |
||||
|
result = (diffX < boundary && diffX > (-1 * boundary)) && (diffY < (-1 * delta)); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
if (result) { |
||||
|
|
||||
|
$this.touchPosX = null; |
||||
|
$this.touchPosY = null; |
||||
|
$this._hide(); |
||||
|
|
||||
|
return false; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Prevent vertical scrolling past the top or bottom.
|
||||
|
if (($this.scrollTop() < 0 && diffY < 0) |
||||
|
|| (ts > (th - 2) && ts < (th + 2) && diffY > 0)) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
event.stopPropagation(); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
// Event: Prevent certain events inside the panel from bubbling.
|
||||
|
$this.on('click touchend touchstart touchmove', function(event) { |
||||
|
event.stopPropagation(); |
||||
|
}); |
||||
|
|
||||
|
// Event: Hide panel if a child anchor tag pointing to its ID is clicked.
|
||||
|
$this.on('click', 'a[href="#' + id + '"]', function(event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
event.stopPropagation(); |
||||
|
|
||||
|
config.target.removeClass(config.visibleClass); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
// Body.
|
||||
|
|
||||
|
// Event: Hide panel on body click/tap.
|
||||
|
$body.on('click touchend', function(event) { |
||||
|
$this._hide(event); |
||||
|
}); |
||||
|
|
||||
|
// Event: Toggle.
|
||||
|
$body.on('click', 'a[href="#' + id + '"]', function(event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
event.stopPropagation(); |
||||
|
|
||||
|
config.target.toggleClass(config.visibleClass); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
// Window.
|
||||
|
|
||||
|
// Event: Hide on ESC.
|
||||
|
if (config.hideOnEscape) |
||||
|
$window.on('keydown', function(event) { |
||||
|
|
||||
|
if (event.keyCode == 27) |
||||
|
$this._hide(event); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
return $this; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Apply "placeholder" attribute polyfill to one or more forms. |
||||
|
* @return {jQuery} jQuery object. |
||||
|
*/ |
||||
|
$.fn.placeholder = function() { |
||||
|
|
||||
|
// Browser natively supports placeholders? Bail.
|
||||
|
if (typeof (document.createElement('input')).placeholder != 'undefined') |
||||
|
return $(this); |
||||
|
|
||||
|
// No elements?
|
||||
|
if (this.length == 0) |
||||
|
return $this; |
||||
|
|
||||
|
// Multiple elements?
|
||||
|
if (this.length > 1) { |
||||
|
|
||||
|
for (var i=0; i < this.length; i++) |
||||
|
$(this[i]).placeholder(); |
||||
|
|
||||
|
return $this; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Vars.
|
||||
|
var $this = $(this); |
||||
|
|
||||
|
// Text, TextArea.
|
||||
|
$this.find('input[type=text],textarea') |
||||
|
.each(function() { |
||||
|
|
||||
|
var i = $(this); |
||||
|
|
||||
|
if (i.val() == '' |
||||
|
|| i.val() == i.attr('placeholder')) |
||||
|
i |
||||
|
.addClass('polyfill-placeholder') |
||||
|
.val(i.attr('placeholder')); |
||||
|
|
||||
|
}) |
||||
|
.on('blur', function() { |
||||
|
|
||||
|
var i = $(this); |
||||
|
|
||||
|
if (i.attr('name').match(/-polyfill-field$/)) |
||||
|
return; |
||||
|
|
||||
|
if (i.val() == '') |
||||
|
i |
||||
|
.addClass('polyfill-placeholder') |
||||
|
.val(i.attr('placeholder')); |
||||
|
|
||||
|
}) |
||||
|
.on('focus', function() { |
||||
|
|
||||
|
var i = $(this); |
||||
|
|
||||
|
if (i.attr('name').match(/-polyfill-field$/)) |
||||
|
return; |
||||
|
|
||||
|
if (i.val() == i.attr('placeholder')) |
||||
|
i |
||||
|
.removeClass('polyfill-placeholder') |
||||
|
.val(''); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
// Password.
|
||||
|
$this.find('input[type=password]') |
||||
|
.each(function() { |
||||
|
|
||||
|
var i = $(this); |
||||
|
var x = $( |
||||
|
$('<div>') |
||||
|
.append(i.clone()) |
||||
|
.remove() |
||||
|
.html() |
||||
|
.replace(/type="password"/i, 'type="text"') |
||||
|
.replace(/type=password/i, 'type=text') |
||||
|
); |
||||
|
|
||||
|
if (i.attr('id') != '') |
||||
|
x.attr('id', i.attr('id') + '-polyfill-field'); |
||||
|
|
||||
|
if (i.attr('name') != '') |
||||
|
x.attr('name', i.attr('name') + '-polyfill-field'); |
||||
|
|
||||
|
x.addClass('polyfill-placeholder') |
||||
|
.val(x.attr('placeholder')).insertAfter(i); |
||||
|
|
||||
|
if (i.val() == '') |
||||
|
i.hide(); |
||||
|
else |
||||
|
x.hide(); |
||||
|
|
||||
|
i |
||||
|
.on('blur', function(event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
|
||||
|
var x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]'); |
||||
|
|
||||
|
if (i.val() == '') { |
||||
|
|
||||
|
i.hide(); |
||||
|
x.show(); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
x |
||||
|
.on('focus', function(event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
|
||||
|
var i = x.parent().find('input[name=' + x.attr('name').replace('-polyfill-field', '') + ']'); |
||||
|
|
||||
|
x.hide(); |
||||
|
|
||||
|
i |
||||
|
.show() |
||||
|
.focus(); |
||||
|
|
||||
|
}) |
||||
|
.on('keypress', function(event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
x.val(''); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
// Events.
|
||||
|
$this |
||||
|
.on('submit', function() { |
||||
|
|
||||
|
$this.find('input[type=text],input[type=password],textarea') |
||||
|
.each(function(event) { |
||||
|
|
||||
|
var i = $(this); |
||||
|
|
||||
|
if (i.attr('name').match(/-polyfill-field$/)) |
||||
|
i.attr('name', ''); |
||||
|
|
||||
|
if (i.val() == i.attr('placeholder')) { |
||||
|
|
||||
|
i.removeClass('polyfill-placeholder'); |
||||
|
i.val(''); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
}) |
||||
|
.on('reset', function(event) { |
||||
|
|
||||
|
event.preventDefault(); |
||||
|
|
||||
|
$this.find('select') |
||||
|
.val($('option:first').val()); |
||||
|
|
||||
|
$this.find('input,textarea') |
||||
|
.each(function() { |
||||
|
|
||||
|
var i = $(this), |
||||
|
x; |
||||
|
|
||||
|
i.removeClass('polyfill-placeholder'); |
||||
|
|
||||
|
switch (this.type) { |
||||
|
|
||||
|
case 'submit': |
||||
|
case 'reset': |
||||
|
break; |
||||
|
|
||||
|
case 'password': |
||||
|
i.val(i.attr('defaultValue')); |
||||
|
|
||||
|
x = i.parent().find('input[name=' + i.attr('name') + '-polyfill-field]'); |
||||
|
|
||||
|
if (i.val() == '') { |
||||
|
i.hide(); |
||||
|
x.show(); |
||||
|
} |
||||
|
else { |
||||
|
i.show(); |
||||
|
x.hide(); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
case 'checkbox': |
||||
|
case 'radio': |
||||
|
i.attr('checked', i.attr('defaultValue')); |
||||
|
break; |
||||
|
|
||||
|
case 'text': |
||||
|
case 'textarea': |
||||
|
i.val(i.attr('defaultValue')); |
||||
|
|
||||
|
if (i.val() == '') { |
||||
|
i.addClass('polyfill-placeholder'); |
||||
|
i.val(i.attr('placeholder')); |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
i.val(i.attr('defaultValue')); |
||||
|
break; |
||||
|
|
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
return $this; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* Moves elements to/from the first positions of their respective parents. |
||||
|
* @param {jQuery} $elements Elements (or selector) to move. |
||||
|
* @param {bool} condition If true, moves elements to the top. Otherwise, moves elements back to their original locations. |
||||
|
*/ |
||||
|
$.prioritize = function($elements, condition) { |
||||
|
|
||||
|
var key = '__prioritize'; |
||||
|
|
||||
|
// Expand $elements if it's not already a jQuery object.
|
||||
|
if (typeof $elements != 'jQuery') |
||||
|
$elements = $($elements); |
||||
|
|
||||
|
// Step through elements.
|
||||
|
$elements.each(function() { |
||||
|
|
||||
|
var $e = $(this), $p, |
||||
|
$parent = $e.parent(); |
||||
|
|
||||
|
// No parent? Bail.
|
||||
|
if ($parent.length == 0) |
||||
|
return; |
||||
|
|
||||
|
// Not moved? Move it.
|
||||
|
if (!$e.data(key)) { |
||||
|
|
||||
|
// Condition is false? Bail.
|
||||
|
if (!condition) |
||||
|
return; |
||||
|
|
||||
|
// Get placeholder (which will serve as our point of reference for when this element needs to move back).
|
||||
|
$p = $e.prev(); |
||||
|
|
||||
|
// Couldn't find anything? Means this element's already at the top, so bail.
|
||||
|
if ($p.length == 0) |
||||
|
return; |
||||
|
|
||||
|
// Move element to top of parent.
|
||||
|
$e.prependTo($parent); |
||||
|
|
||||
|
// Mark element as moved.
|
||||
|
$e.data(key, $p); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Moved already?
|
||||
|
else { |
||||
|
|
||||
|
// Condition is true? Bail.
|
||||
|
if (condition) |
||||
|
return; |
||||
|
|
||||
|
$p = $e.data(key); |
||||
|
|
||||
|
// Move element back to its original location (using our placeholder).
|
||||
|
$e.insertAfter($p); |
||||
|
|
||||
|
// Unmark element as moved.
|
||||
|
$e.removeData(key); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
}); |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
})(jQuery); |
||||
@ -0,0 +1,17 @@ |
|||||
|
{% extends 'base.html' %} |
||||
|
{% block entete %}Réinitilisation du mot de passe{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">Réinitialisation du mot de passe</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Réinitialisation du mot de passe</h2> |
||||
|
<p>Mot de passe réinitialisé.</p> |
||||
|
</header> |
||||
|
Vous pouvez vous connecter en vous rendant sur la <a href="{% url 'users:login' %}">page de connexion</a>. |
||||
|
</section> |
||||
|
{{form.media}} |
||||
|
{% endblock %} |
||||
@ -0,0 +1,23 @@ |
|||||
|
{% extends 'base.html' %} |
||||
|
{% block entete %}Réinitilisation du mot de passe{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">Réinitialisation du mot de passe</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Réinitialisation du mot de passe</h2> |
||||
|
</header> |
||||
|
<section> |
||||
|
<form method="post"> |
||||
|
{% csrf_token %} |
||||
|
{{ form }} |
||||
|
<br> |
||||
|
<button type="submit"><i class="fa fa-lock"></i> Changer le mot de passe</button> |
||||
|
</form> |
||||
|
</section> |
||||
|
</section> |
||||
|
{{form.media}} |
||||
|
{% endblock %} |
||||
@ -0,0 +1,16 @@ |
|||||
|
{% extends 'base.html' %} |
||||
|
{% block entete %}Réinitilisation du mot de passe{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">Réinitialisation du mot de passe</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Réinitialisation du mot de passe</h2> |
||||
|
<p>Un mail vous a été envoyé avec un lien pour réinitialiser le mot de passe.</p> |
||||
|
</header> |
||||
|
</section> |
||||
|
{{form.media}} |
||||
|
{% endblock %} |
||||
@ -0,0 +1,11 @@ |
|||||
|
{% autoescape off %} |
||||
|
Bonjour {{user.username}}, |
||||
|
|
||||
|
Vous avez demandé une réinitalisation de votre mot de passe sur le site de gestion de la Coopé Technopôle Metz, vous pouvez le faire en cliquant sur le lien ci dessous: |
||||
|
|
||||
|
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} |
||||
|
|
||||
|
Si le lien ne fonctionne pas en cliquant, vous pouvez le copier-coller dans votre navigateur, |
||||
|
|
||||
|
Le staff Coopé Technopôle Metz |
||||
|
{% endautoescape %} |
||||
@ -0,0 +1,24 @@ |
|||||
|
{% extends 'base.html' %} |
||||
|
{% block entete %}Réinitilisation du mot de passe{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">Réinitialisation du mot de passe</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>Réinitialisation du mot de passe</h2> |
||||
|
<p>Vous recevrez un lien pour réinitilisaser votre mot de passe sur votre adresse e-mail.</p> |
||||
|
</header> |
||||
|
<section> |
||||
|
<form method="post"> |
||||
|
{% csrf_token %} |
||||
|
{{ form }} |
||||
|
<br> |
||||
|
<button type="submit"><i class="fa fa-lock"></i> Réinitialiser</button> |
||||
|
</form> |
||||
|
</section> |
||||
|
</section> |
||||
|
{{form.media}} |
||||
|
{% endblock %} |
||||
@ -0,0 +1 @@ |
|||||
|
Réinitialisation du mot de passe Coopé TM |
||||
@ -0,0 +1,31 @@ |
|||||
|
{% extends 'base.html' %} |
||||
|
{% block entete %}{{form_title}}{% endblock %} |
||||
|
{% block navbar %} |
||||
|
<ul> |
||||
|
<li><a href="#first">{{form_title}}</a></li> |
||||
|
</ul> |
||||
|
{% endblock %} |
||||
|
{% block content %} |
||||
|
<section id="first" class="main"> |
||||
|
<header class="major"> |
||||
|
<h2>{{form_title}}</h2> |
||||
|
<p>{{form_p}}</p> |
||||
|
</header> |
||||
|
<section> |
||||
|
<form action="" method="post"> |
||||
|
{% csrf_token %} |
||||
|
{{ form }} |
||||
|
<br> |
||||
|
{{ extra_html | safe }}<br><br> |
||||
|
<button type="submit"><i class="fa fa-{{form_button_icon}}"></i> {{form_button}}</button> |
||||
|
</form> |
||||
|
</section> |
||||
|
Si vous avez perdu votre mot de passe : <a href="{% url 'password_reset' %}">mot de passe oublié</a>. |
||||
|
</section> |
||||
|
{% if extra_css %} |
||||
|
<style> |
||||
|
{{extra_css}} |
||||
|
</style> |
||||
|
{% endif %} |
||||
|
{{form.media}} |
||||
|
{% endblock %} |
||||
@ -0,0 +1,15 @@ |
|||||
|
{% autoescape off %} |
||||
|
Bonjour {{user.username}},<br> |
||||
|
|
||||
|
Vous venez de créer votre compte sur le logiciel de gestion de l'association Coopé Technopôle Metz. Pour finir vous adhésion à l'association, vous devez |
||||
|
<ul> |
||||
|
<li>lire et accepter les statuts et le règlement intérieur (disponibles en pièces jointes),</li> |
||||
|
<li>vous acquittez d'une cotisation auprès de l'un de nos membres actifs.</li> |
||||
|
</ul> |
||||
|
|
||||
|
Vous pouvez acceder à votre compte sur {{protocol}}://{{domain}} après avoir activé votre mot de passe avec le lien suivant : <br> |
||||
|
|
||||
|
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}<br><br> |
||||
|
|
||||
|
Le Staff Coopé Technopôle Metz |
||||
|
{% endautoescape %} |
||||
@ -0,0 +1,11 @@ |
|||||
|
Bonjour {{user.username}}, |
||||
|
|
||||
|
Vous venez de créer votre compte sur le logiciel de gestion de l'association Coopé Technopôle Metz. Pour finir vous adhésion à l'association, vous devez |
||||
|
- lire et accepter les statuts et le règlement intérieur (disponibles en pièces jointes), |
||||
|
- vous acquittez d'une cotisation auprès de l'un de nos membres actifs. |
||||
|
|
||||
|
Vous pouvez acceder à votre compte sur {{procotol}}://{{domain}} après avoir activé votre mot de passe avec le lien suivant : |
||||
|
|
||||
|
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} |
||||
|
|
||||
|
Le Staff Coopé Technopôle Metz |
||||
Loading…
Reference in new issue