mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-30 08:32:26 +00:00
Merge branch 'master' of https://gitlab.rezometz.org/rezo/re2o
This commit is contained in:
commit
bfb07c3a24
49 changed files with 840 additions and 139 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
|||
settings.py
|
||||
settings*
|
||||
settings_local.py
|
||||
*.swp
|
||||
*.pyc
|
||||
__pycache__
|
||||
|
|
|
@ -3,10 +3,10 @@ from django.contrib import admin
|
|||
from .models import Facture, Article, Banque, Paiement, Cotisation
|
||||
|
||||
class FactureAdmin(admin.ModelAdmin):
|
||||
list_display = ('user','paiement','name', 'number', 'date')
|
||||
list_display = ('user','paiement','name', 'number','prix', 'date','valid')
|
||||
|
||||
class ArticleAdmin(admin.ModelAdmin):
|
||||
list_display = ('name','prix','cotisation')
|
||||
list_display = ('name','prix','cotisation','duration')
|
||||
|
||||
class BanqueAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
|
|
88
cotisations/forms.py
Normal file
88
cotisations/forms.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
from django import forms
|
||||
from django.forms import ModelForm
|
||||
from .models import Article, Paiement, Facture, Banque
|
||||
|
||||
class NewFactureForm(ModelForm):
|
||||
article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(NewFactureForm, self).__init__(*args, **kwargs)
|
||||
self.fields['number'].label = 'Quantité'
|
||||
self.fields['cheque'].required = False
|
||||
self.fields['banque'].required = False
|
||||
self.fields['cheque'].label = 'Numero de chèque'
|
||||
self.fields['banque'].empty_label = "Non renseigné"
|
||||
self.fields['paiement'].empty_label = "Séléctionner un moyen de paiement"
|
||||
|
||||
class Meta:
|
||||
model = Facture
|
||||
fields = ['paiement','banque','cheque','number']
|
||||
|
||||
def clean(self):
|
||||
cleaned_data=super(NewFactureForm, self).clean()
|
||||
paiement = cleaned_data.get("paiement")
|
||||
cheque = cleaned_data.get("cheque")
|
||||
banque = cleaned_data.get("banque")
|
||||
if paiement.moyen=="chèque" and not (cheque and banque):
|
||||
raise forms.ValidationError("Le numero de chèque et la banque sont obligatoires")
|
||||
return cleaned_data
|
||||
|
||||
class EditFactureForm(NewFactureForm):
|
||||
class Meta(NewFactureForm.Meta):
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EditFactureForm, self).__init__(*args, **kwargs)
|
||||
self.fields['user'].label = 'Adherent'
|
||||
self.fields['name'].label = 'Designation'
|
||||
self.fields['prix'].label = 'Prix unitaire'
|
||||
self.fields['user'].empty_label = "Séléctionner l'adhérent propriétaire"
|
||||
self.fields.pop('article')
|
||||
|
||||
class ArticleForm(ModelForm):
|
||||
class Meta:
|
||||
model = Article
|
||||
fields = '__all__'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ArticleForm, self).__init__(*args, **kwargs)
|
||||
self.fields['name'].label = "Désignation de l'article"
|
||||
|
||||
class DelArticleForm(ModelForm):
|
||||
articles = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Articles actuels", widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
class Meta:
|
||||
fields = ['articles']
|
||||
model = Article
|
||||
|
||||
class PaiementForm(ModelForm):
|
||||
class Meta:
|
||||
model = Paiement
|
||||
fields = ['moyen']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PaiementForm, self).__init__(*args, **kwargs)
|
||||
self.fields['moyen'].label = 'Moyen de paiement à ajouter'
|
||||
|
||||
class DelPaiementForm(ModelForm):
|
||||
paiements = forms.ModelMultipleChoiceField(queryset=Paiement.objects.all(), label="Moyens de paiement actuels", widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
class Meta:
|
||||
exclude = ['moyen']
|
||||
model = Paiement
|
||||
|
||||
class BanqueForm(ModelForm):
|
||||
class Meta:
|
||||
model = Banque
|
||||
fields = ['name']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(BanqueForm, self).__init__(*args, **kwargs)
|
||||
self.fields['name'].label = 'Banque à ajouter'
|
||||
|
||||
class DelBanqueForm(ModelForm):
|
||||
banques = forms.ModelMultipleChoiceField(queryset=Banque.objects.all(), label="Banques actuelles", widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
class Meta:
|
||||
exclude = ['name']
|
||||
model = Banque
|
|
@ -1,8 +1,5 @@
|
|||
from django.db import models
|
||||
from django import forms
|
||||
from django.forms import ModelForm
|
||||
|
||||
from users.models import User
|
||||
|
||||
class Facture(models.Model):
|
||||
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
||||
|
@ -47,31 +44,3 @@ class Cotisation(models.Model):
|
|||
def __str__(self):
|
||||
return str(self.facture)
|
||||
|
||||
class NewFactureForm(ModelForm):
|
||||
article = forms.ModelMultipleChoiceField(queryset=Article.objects.all(), label="Article")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(NewFactureForm, self).__init__(*args, **kwargs)
|
||||
self.fields['number'].label = 'Quantité'
|
||||
self.fields['cheque'].required = False
|
||||
self.fields['banque'].required = False
|
||||
self.fields['cheque'].label = 'Numero de chèque'
|
||||
|
||||
class Meta:
|
||||
model = Facture
|
||||
exclude = ['user', 'prix', 'name', 'valid']
|
||||
|
||||
class EditFactureForm(ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EditFactureForm, self).__init__(*args, **kwargs)
|
||||
self.fields['user'].label = 'Adherent'
|
||||
self.fields['number'].label = 'Quantité'
|
||||
self.fields['cheque'].required = False
|
||||
self.fields['banque'].required = False
|
||||
self.fields['cheque'].label = 'Numero de chèque'
|
||||
self.fields['name'].label = 'Designation'
|
||||
self.fields['prix'].label = 'Prix unitaire'
|
||||
|
||||
class Meta:
|
||||
model = Facture
|
||||
fields = '__all__'
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<td>{{ facture.prix }}</td>
|
||||
<td>{{ facture.paiement }}</td>
|
||||
<td>{{ facture.date }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-facture' facture.id %}"><i class="glyphicon glyphicon-tree-conifer"></i> Editer</a></td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'cotisations:edit-facture' facture.id %}"><i class="glyphicon glyphicon-bitcoin"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p><a href="{% url "search:search" %}">Créer une facture</a></p>
|
||||
<p><a href="{% url "search:search" %}">Editer une facture</a></p>
|
||||
<p><a href="{% url "cotisations:index" %}">Liste des factures</a></p>
|
||||
<p><a href="{% url "cotisations:add-article" %}">Ajouter un article</a></p>
|
||||
<p><a href="{% url "cotisations:del-article" %}">Retirer un article</a></p>
|
||||
<p><a href="{% url "cotisations:add-paiement" %}">Ajouter un moyen de paiement</a></p>
|
||||
<p><a href="{% url "cotisations:del-paiement" %}">Retirer un moyen de paiement</a></p>
|
||||
<p><a href="{% url "cotisations:add-banque" %}">Ajouter une banque</a></p>
|
||||
<p><a href="{% url "cotisations:del-banque" %}">Retirer une banque</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -5,6 +5,12 @@ from . import views
|
|||
urlpatterns = [
|
||||
url(r'^new_facture/(?P<userid>[0-9]+)$', views.new_facture, name='new-facture'),
|
||||
url(r'^edit_facture/(?P<factureid>[0-9]+)$', views.edit_facture, name='edit-facture'),
|
||||
url(r'^add_article/$', views.add_article, name='add-article'),
|
||||
url(r'^del_article/$', views.del_article, name='del-article'),
|
||||
url(r'^add_paiement/$', views.add_paiement, name='add-paiement'),
|
||||
url(r'^del_paiement/$', views.del_paiement, name='del-paiement'),
|
||||
url(r'^add_banque/$', views.add_banque, name='add-banque'),
|
||||
url(r'^del_banque/$', views.del_banque, name='del-banque'),
|
||||
url(r'^$', views.index, name='index'),
|
||||
]
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ from django.shortcuts import render_to_response, get_object_or_404
|
|||
from django.core.context_processors import csrf
|
||||
from django.template import Context, RequestContext, loader
|
||||
from django.contrib import messages
|
||||
from django.db.models import Max
|
||||
from django.db.models import Max, ProtectedError
|
||||
|
||||
from cotisations.models import NewFactureForm, EditFactureForm, Facture, Article, Cotisation
|
||||
from .models import Facture, Article, Cotisation, Article
|
||||
from .forms import NewFactureForm, EditFactureForm, ArticleForm, DelArticleForm, PaiementForm, DelPaiementForm, BanqueForm, DelBanqueForm
|
||||
from users.models import User
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
@ -34,14 +35,14 @@ def is_adherent(user):
|
|||
else:
|
||||
return True
|
||||
|
||||
def create_cotis(facture, user, article):
|
||||
def create_cotis(facture, user, duration):
|
||||
""" Update et crée l'objet cotisation associé à une facture, prend en argument l'user, la facture pour la quantitéi, et l'article pour la durée"""
|
||||
cotisation=Cotisation(facture=facture)
|
||||
date_max = end_adhesion(user) or timezone.now()
|
||||
if date_max < timezone.now():
|
||||
datemax = timezone.now()
|
||||
cotisation.date_start=date_max
|
||||
cotisation.date_end = cotisation.date_start + relativedelta(months=article[0].duration*facture.number)
|
||||
cotisation.date_end = cotisation.date_start + relativedelta(months=duration)
|
||||
cotisation.save()
|
||||
return
|
||||
|
||||
|
@ -56,11 +57,12 @@ def new_facture(request, userid):
|
|||
if facture_form.is_valid():
|
||||
new_facture = facture_form.save(commit=False)
|
||||
article = facture_form.cleaned_data['article']
|
||||
new_facture.prix = article[0].prix
|
||||
new_facture.name = article[0].name
|
||||
new_facture.prix = sum(art.prix for art in article)
|
||||
new_facture.name = ' - '.join(art.name for art in article)
|
||||
new_facture.save()
|
||||
if article[0].cotisation == True:
|
||||
create_cotis(new_facture, user, article)
|
||||
if any(art.cotisation for art in article):
|
||||
duration = sum(art.duration*facture.number for art in article if art.cotisation)
|
||||
create_cotis(new_facture, user, duration)
|
||||
messages.success(request, "La cotisation a été prolongée pour l'adhérent %s " % user.name )
|
||||
else:
|
||||
messages.success(request, "La facture a été crée")
|
||||
|
@ -80,6 +82,65 @@ def edit_facture(request, factureid):
|
|||
return redirect("/cotisations/")
|
||||
return form({'factureform': facture_form}, 'cotisations/facture.html', request)
|
||||
|
||||
def add_article(request):
|
||||
article = ArticleForm(request.POST or None)
|
||||
if article.is_valid():
|
||||
article.save()
|
||||
messages.success(request, "L'article a été ajouté")
|
||||
return redirect("/cotisations/")
|
||||
return form({'factureform': article}, 'cotisations/facture.html', request)
|
||||
|
||||
def del_article(request):
|
||||
article = DelArticleForm(request.POST or None)
|
||||
if article.is_valid():
|
||||
article_del = article.cleaned_data['articles']
|
||||
article_del.delete()
|
||||
messages.success(request, "Le/les articles ont été supprimé")
|
||||
return redirect("/cotisations/")
|
||||
return form({'factureform': article}, 'cotisations/facture.html', request)
|
||||
|
||||
def add_paiement(request):
|
||||
paiement = PaiementForm(request.POST or None)
|
||||
if paiement.is_valid():
|
||||
paiement.save()
|
||||
messages.success(request, "Le moyen de paiement a été ajouté")
|
||||
return redirect("/cotisations/")
|
||||
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
||||
|
||||
def del_paiement(request):
|
||||
paiement = DelPaiementForm(request.POST or None)
|
||||
if paiement.is_valid():
|
||||
paiement_dels = paiement.cleaned_data['paiements']
|
||||
for paiement_del in paiement_dels:
|
||||
try:
|
||||
paiement_del.delete()
|
||||
messages.success(request, "Le moyen de paiement a été supprimé")
|
||||
except ProtectedError:
|
||||
messages.error(request, "Le moyen de paiement %s est affecté à au moins une facture, vous ne pouvez pas le supprimer" % paiement_del)
|
||||
return redirect("/cotisations/")
|
||||
return form({'factureform': paiement}, 'cotisations/facture.html', request)
|
||||
|
||||
def add_banque(request):
|
||||
banque = BanqueForm(request.POST or None)
|
||||
if banque.is_valid():
|
||||
banque.save()
|
||||
messages.success(request, "La banque a été ajoutée")
|
||||
return redirect("/cotisations/")
|
||||
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
||||
|
||||
def del_banque(request):
|
||||
banque = DelBanqueForm(request.POST or None)
|
||||
if banque.is_valid():
|
||||
banque_dels = banque.cleaned_data['banques']
|
||||
for banque_del in banque_dels:
|
||||
try:
|
||||
banque_del.delete()
|
||||
messages.success(request, "La banque a été supprimée")
|
||||
except ProtectedError:
|
||||
messages.error(request, "La banque %s est affectée à au moins une facture, vous ne pouvez pas la supprimer" % banque_del)
|
||||
return redirect("/cotisations/")
|
||||
return form({'factureform': banque}, 'cotisations/facture.html', request)
|
||||
|
||||
def index(request):
|
||||
facture_list = Facture.objects.order_by('pk')
|
||||
facture_list = Facture.objects.order_by('date').reverse()
|
||||
return render(request, 'cotisations/index.html', {'facture_list': facture_list})
|
||||
|
|
|
@ -3,7 +3,7 @@ from django.contrib import admin
|
|||
from .models import Machine, MachineType, IpList, Interface
|
||||
|
||||
class MachineAdmin(admin.ModelAdmin):
|
||||
list_display = ('user','name','type')
|
||||
list_display = ('user','name','type','active')
|
||||
|
||||
class MachineTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('type',)
|
||||
|
|
24
machines/migrations/0013_auto_20160705_1014.py
Normal file
24
machines/migrations/0013_auto_20160705_1014.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0012_auto_20160704_0118'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='machine',
|
||||
name='active',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='dns',
|
||||
field=models.CharField(max_length=255, unique=True, help_text='Obligatoire et unique, doit se terminer en .rez et ne pas comporter de points'),
|
||||
),
|
||||
]
|
20
machines/migrations/0014_auto_20160706_1220.py
Normal file
20
machines/migrations/0014_auto_20160706_1220.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import machines.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0013_auto_20160705_1014'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='interface',
|
||||
name='dns',
|
||||
field=models.CharField(unique=True, validators=[machines.models.full_domain_validator], max_length=255, help_text="Obligatoire et unique, doit se terminer en .rez et ne pas comporter d'autres points"),
|
||||
),
|
||||
]
|
|
@ -1,13 +1,38 @@
|
|||
from django.db import models
|
||||
from django.forms import ModelForm, Form
|
||||
from django.forms import ModelForm, Form, ValidationError
|
||||
from macaddress.fields import MACAddressField
|
||||
|
||||
from users.models import User
|
||||
from django.conf import settings
|
||||
import re
|
||||
|
||||
def full_domain_validator(hostname):
|
||||
""" Validation du nom de domaine, extensions dans settings, prefixe pas plus long que 63 caractères """
|
||||
HOSTNAME_LABEL_PATTERN = re.compile("(?!-)[A-Z\d-]+(?<!-)$", re.IGNORECASE)
|
||||
if not any(ext in hostname for ext in settings.ALLOWED_EXTENSIONS):
|
||||
raise ValidationError(
|
||||
", le nom de domaine '%(label)s' doit comporter une extension valide",
|
||||
params={'label': hostname},
|
||||
)
|
||||
for extension in settings.ALLOWED_EXTENSIONS:
|
||||
if hostname.endswith(extension):
|
||||
hostname=re.sub('%s$' % extension, '', hostname)
|
||||
break
|
||||
if len(hostname) > 63:
|
||||
raise ValidationError(
|
||||
", le nom de domaine '%(label)s' est trop long (maximum de 63 caractères).",
|
||||
params={'label': hostname},
|
||||
)
|
||||
if not HOSTNAME_LABEL_PATTERN.match(hostname):
|
||||
raise ValidationError(
|
||||
", ce nom de domaine '%(label)s' contient des carractères interdits.",
|
||||
params={'label': hostname},
|
||||
)
|
||||
|
||||
class Machine(models.Model):
|
||||
user = models.ForeignKey('users.User', on_delete=models.PROTECT)
|
||||
type = models.ForeignKey('MachineType', on_delete=models.PROTECT)
|
||||
name = models.CharField(max_length=255, help_text="Optionnel", blank=True, null=True)
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user) + ' - ' + str(self.id) + ' - ' + str(self.name)
|
||||
|
@ -25,11 +50,14 @@ class Interface(models.Model):
|
|||
mac_address = MACAddressField(integer=False, unique=True)
|
||||
machine = models.ForeignKey('Machine', on_delete=models.PROTECT)
|
||||
details = models.CharField(max_length=255, blank=True)
|
||||
dns = models.CharField(help_text="Obligatoire et unique", max_length=255, unique=True)
|
||||
dns = models.CharField(help_text="Obligatoire et unique, doit se terminer en %s et ne pas comporter d'autres points" % ", ".join(settings.ALLOWED_EXTENSIONS), max_length=255, unique=True, validators=[full_domain_validator])
|
||||
|
||||
def __str__(self):
|
||||
return self.dns
|
||||
|
||||
def clean(self):
|
||||
self.dns=self.dns.lower()
|
||||
|
||||
class IpList(models.Model):
|
||||
ipv4 = models.GenericIPAddressField(protocol='IPv4', unique=True)
|
||||
|
||||
|
@ -45,6 +73,7 @@ class EditMachineForm(ModelForm):
|
|||
super(EditMachineForm, self).__init__(*args, **kwargs)
|
||||
self.fields['name'].label = 'Nom de la machine'
|
||||
self.fields['type'].label = 'Type de machine'
|
||||
self.fields['type'].empty_label = "Séléctionner un type de machine"
|
||||
|
||||
class NewMachineForm(EditMachineForm):
|
||||
class Meta(EditMachineForm.Meta):
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<td>{{ machine.machine.type }}</td>
|
||||
<td>{{ machine.mac_address }}</td>
|
||||
<td>{{ machine.ipv4 }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:edit-machine' machine.id %}"><i class="glyphicon glyphicon-tree-conifer"></i> Editer</a></td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'machines:edit-machine' machine.id %}"><i class="glyphicon glyphicon-hdd"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p><a href="{% url "search:search" %}">Nouvelle machine</a></p>
|
||||
{% endblock %}
|
||||
|
|
108
re2o/settings.py
Normal file
108
re2o/settings.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
"""
|
||||
Django settings for re2o project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.8.13.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.8/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.8/ref/settings/
|
||||
"""
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
import os
|
||||
from .settings_local import SECRET_KEY, DATABASES, DEBUG, ALLOWED_HOSTS, ALLOWED_EXTENSIONS
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'bootstrap3',
|
||||
'users',
|
||||
'machines',
|
||||
'cotisations',
|
||||
'topologie',
|
||||
'search',
|
||||
'logs',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 're2o.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [
|
||||
os.path.join(BASE_DIR, 'templates').replace('\\', '/'),
|
||||
],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 're2o.wsgi.application'
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/1.8/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'fr-fr'
|
||||
|
||||
TIME_ZONE = 'Europe/Paris'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# django-bootstrap3 config dictionnary
|
||||
BOOTSTRAP3 = {
|
||||
'jquery_url': '/static/js/jquery-2.2.4.min.js',
|
||||
'base_url': '/static/bootstrap/',
|
||||
'include_jquery': True,
|
||||
}
|
||||
|
||||
BOOTSTRAP_BASE_URL = '/static/bootstrap/'
|
||||
|
||||
STATICFILES_DIRS = (
|
||||
# Put strings here, like "/home/html/static" or "C:/www/django/static".
|
||||
# Always use forward slashes, even on Windows.
|
||||
# Don't forget to use absolute paths, not relative paths.
|
||||
os.path.join(
|
||||
BASE_DIR,
|
||||
'static',
|
||||
),
|
||||
)
|
||||
|
||||
STATIC_URL = '/static/'
|
20
re2o/settings_local.example.py
Normal file
20
re2o/settings_local.example.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
SECRET_KEY = 'SUPER_SECRET'
|
||||
|
||||
DB_PASSWORD = 'SUPER_SECRET'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'NAME': 're2o',
|
||||
'USER': 're2o',
|
||||
'PASSWORD': DB_PASSWORD,
|
||||
'HOST': 'localhost',
|
||||
}
|
||||
}
|
||||
|
||||
ALLOWED_EXTENSIONS = ['.example']
|
|
@ -24,5 +24,6 @@ urlpatterns = [
|
|||
url(r'^search/', include('search.urls', namespace='search')),
|
||||
url(r'^cotisations/', include('cotisations.urls', namespace='cotisations')),
|
||||
url(r'^machines/', include('machines.urls', namespace='machines')),
|
||||
url(r'^topologie/', include('topologie.urls', namespace='topologie')),
|
||||
#url(r'^logs/', include('logs.urls', namespace='logs')),
|
||||
]
|
||||
|
|
|
@ -3,9 +3,6 @@ from django import forms
|
|||
from django.forms import Form
|
||||
from django.forms import ModelForm
|
||||
|
||||
from users.models import User
|
||||
# Create your models here.
|
||||
|
||||
CHOICES = (
|
||||
('0', 'Actifs'),
|
||||
('1', 'Désactivés'),
|
||||
|
|
|
@ -12,6 +12,7 @@ from machines.models import Machine, Interface
|
|||
from cotisations.models import Facture
|
||||
from search.models import SearchForm, SearchFormPlus
|
||||
from users.views import has_access
|
||||
from cotisations.views import end_adhesion
|
||||
|
||||
def form(ctx, template, request):
|
||||
c = ctx
|
||||
|
@ -23,7 +24,7 @@ def search_result(search, type):
|
|||
date_fin = None
|
||||
states=[]
|
||||
co=[]
|
||||
aff=[0,1,2,3,4]
|
||||
aff=['0','1','2','3','4']
|
||||
if(type):
|
||||
aff = search.cleaned_data['affichage']
|
||||
co = search.cleaned_data['connexion']
|
||||
|
@ -32,7 +33,7 @@ def search_result(search, type):
|
|||
date_fin = search.cleaned_data['date_fin']
|
||||
date_query = Q()
|
||||
if aff==[]:
|
||||
aff = [0,1,2,3,4]
|
||||
aff = ['0','1','2','3','4']
|
||||
if date_deb != None:
|
||||
date_query = date_query & Q(date__gte=date_deb)
|
||||
if date_fin != None:
|
||||
|
@ -54,9 +55,13 @@ def search_result(search, type):
|
|||
users = User.objects.filter((Q(pseudo__icontains = search) | Q(name__icontains = search) | Q(surname__icontains = search)) & query)
|
||||
connexion = []
|
||||
for user in users:
|
||||
end=end_adhesion(user)
|
||||
access=has_access(user)
|
||||
if(len(co)==0 or (len(co)==1 and bool(co[0])==access) or (len(co)==2 and (bool(co[0])==access or bool(co[1])==access))):
|
||||
connexion.append([user, access])
|
||||
if(end!=None):
|
||||
connexion.append([user, access, end])
|
||||
else:
|
||||
connexion.append([user, access, "Non adhérent"])
|
||||
query = Q(user__pseudo__icontains = search) | Q(user__name__icontains = search) | Q(user__surname__icontains = search)
|
||||
if i == '1':
|
||||
machines = Interface.objects.filter(machine=Machine.objects.filter(query)) | Interface.objects.filter(Q(dns__icontains = search))
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<li><a href="{% url "users:index" %}">Adhérents</a></li>
|
||||
<li><a href="{% url "machines:index" %}">Machines</a></li>
|
||||
<li><a href="{% url "cotisations:index" %}">Cotisations</a></li>
|
||||
<li><a href="#">Topologie</a></li>
|
||||
<li><a href="{% url "topologie:index" %}">Topologie</a></li>
|
||||
<li><a href="#">Statistiques</a></li>
|
||||
</ul>
|
||||
<div class="col-sm-3 col-md-3 navbar-right">
|
||||
|
|
|
@ -7,7 +7,7 @@ class SwitchAdmin(admin.ModelAdmin):
|
|||
list_display = ('building','number','details')
|
||||
|
||||
class PortAdmin(admin.ModelAdmin):
|
||||
list_display = ('switch', 'port','room','details')
|
||||
list_display = ('switch', 'port','room','machine_interface','details')
|
||||
|
||||
class RoomAdmin(admin.ModelAdmin):
|
||||
list_display = ('name',)
|
||||
|
|
11
topologie/forms.py
Normal file
11
topologie/forms.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from .models import Port
|
||||
from django.forms import ModelForm, Form
|
||||
|
||||
class PortForm(ModelForm):
|
||||
class Meta:
|
||||
model = Port
|
||||
fields = '__all__'
|
||||
|
||||
class EditPortForm(ModelForm):
|
||||
class Meta(PortForm.Meta):
|
||||
fields = ['room', 'machine_interface', 'related', 'details']
|
21
topologie/migrations/0012_port_machine_interface.py
Normal file
21
topologie/migrations/0012_port_machine_interface.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('machines', '0014_auto_20160706_1220'),
|
||||
('topologie', '0011_auto_20160704_2153'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='port',
|
||||
name='machine_interface',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, null=True, blank=True, to='machines.Interface'),
|
||||
),
|
||||
]
|
19
topologie/migrations/0013_port_related.py
Normal file
19
topologie/migrations/0013_port_related.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('topologie', '0012_port_machine_interface'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='port',
|
||||
name='related',
|
||||
field=models.OneToOneField(null=True, to='topologie.Port', blank=True, related_name='related_port'),
|
||||
),
|
||||
]
|
26
topologie/migrations/0014_auto_20160706_1238.py
Normal file
26
topologie/migrations/0014_auto_20160706_1238.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('topologie', '0013_port_related'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='port',
|
||||
unique_together=set([('switch', 'port')]),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='port',
|
||||
name='_content_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='port',
|
||||
name='_object_id',
|
||||
),
|
||||
]
|
23
topologie/migrations/0015_auto_20160706_1452.py
Normal file
23
topologie/migrations/0015_auto_20160706_1452.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('topologie', '0014_auto_20160706_1238'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='port',
|
||||
name='related',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='port',
|
||||
name='related',
|
||||
field=models.ManyToManyField(related_name='_port_related_+', to='topologie.Port', blank=True),
|
||||
),
|
||||
]
|
23
topologie/migrations/0016_auto_20160706_1531.py
Normal file
23
topologie/migrations/0016_auto_20160706_1531.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('topologie', '0015_auto_20160706_1452'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='port',
|
||||
name='related',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='port',
|
||||
name='related',
|
||||
field=models.OneToOneField(blank=True, to='topologie.Port', related_name='related_port', null=True),
|
||||
),
|
||||
]
|
Binary file not shown.
|
@ -1,7 +1,18 @@
|
|||
from django.db import models
|
||||
from django.forms import ModelForm, Form
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
def make_port_related(port):
|
||||
related_port = port.related
|
||||
related_port.related = port
|
||||
related_port.save()
|
||||
|
||||
def clean_port_related(port):
|
||||
related_port = port.related_port
|
||||
related_port.related = None
|
||||
related_port.save()
|
||||
|
||||
class Switch(models.Model):
|
||||
building = models.CharField(max_length=10)
|
||||
|
@ -17,25 +28,26 @@ class Switch(models.Model):
|
|||
class Port(models.Model):
|
||||
switch = models.ForeignKey(Switch, related_name="ports")
|
||||
port = models.IntegerField()
|
||||
details = models.CharField(max_length=255, blank=True)
|
||||
room = models.ForeignKey('Room', on_delete=models.PROTECT, blank=True, null=True)
|
||||
# machine_interface = models.OneToOneField('machines.Interface', on_delete=models.PROTECT, blank=True, null=True)
|
||||
machine_interface = models.OneToOneField('machines.Interface', on_delete=models.PROTECT, blank=True, null=True)
|
||||
related = models.OneToOneField('self', null=True, blank=True, related_name='related_port')
|
||||
details = models.CharField(max_length=255, blank=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('_content_type', '_object_id')
|
||||
unique_together = ('switch', 'port')
|
||||
|
||||
_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, blank=True, null=True)
|
||||
_object_id = models.PositiveIntegerField(blank=True, null=True)
|
||||
goto = GenericForeignKey('_content_type', '_object_id')
|
||||
|
||||
@property
|
||||
def comefrom(self):
|
||||
ctype = ContentType.objects.get_for_model(self.__class__)
|
||||
try:
|
||||
event = Port.objects.get(_content_type__pk=ctype.id, _object_id=self.id)
|
||||
except:
|
||||
return None
|
||||
return event
|
||||
def clean(self):
|
||||
if self.room and self.machine_interface or self.room and self.related or self.machine_interface and self.related:
|
||||
raise ValidationError("Chambre, interface et related_port sont mutuellement exclusifs")
|
||||
if self.related==self:
|
||||
raise ValidationError("On ne peut relier un port à lui même")
|
||||
if self.related and not self.related.related:
|
||||
if self.related.machine_interface or self.related.room:
|
||||
raise ValidationError("Le port relié est déjà occupé, veuillez le libérer avant de créer une relation")
|
||||
else:
|
||||
make_port_related(self)
|
||||
elif hasattr(self, 'related_port'):
|
||||
clean_port_related(self)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.switch) + " - " + str(self.port)
|
||||
|
|
23
topologie/templates/topologie/aff_port.html
Normal file
23
topologie/templates/topologie/aff_port.html
Normal file
|
@ -0,0 +1,23 @@
|
|||
<h2>Switch {% if port_list.0 %}{{ port_list.0.switch }}{% endif %}</h2>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Port</th>
|
||||
<th>Room</th>
|
||||
<th>Interface machine</th>
|
||||
<th>Related</th>
|
||||
<th>Détails</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for port in port_list %}
|
||||
<tr>
|
||||
<td>{{ port.port }}</td>
|
||||
<td>{{ port.room }}</td>
|
||||
<td>{{ port.machine_interface }}</td>
|
||||
<td>{{ port.related }}</td>
|
||||
<td>{{ port.details }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:edit-port' port.id %}"><i class="glyphicon glyphicon-random"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
18
topologie/templates/topologie/aff_switch.html
Normal file
18
topologie/templates/topologie/aff_switch.html
Normal file
|
@ -0,0 +1,18 @@
|
|||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bâtiment</th>
|
||||
<th>Numero</th>
|
||||
<th>Détails</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for switch in switch_list %}
|
||||
<tr>
|
||||
<td>{{switch.building}}</td>
|
||||
<td>{{switch.number}}</td>
|
||||
<td>{{switch.details}}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'topologie:index-port' switch.pk %}"><i class="glyphicon glyphicon-list-alt"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
11
topologie/templates/topologie/index.html
Normal file
11
topologie/templates/topologie/index.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends "topologie/sidebar.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Switchs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "topologie/aff_switch.html" with switch_list=switch_list %}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
11
topologie/templates/topologie/index_p.html
Normal file
11
topologie/templates/topologie/index_p.html
Normal file
|
@ -0,0 +1,11 @@
|
|||
{% extends "topologie/sidebar.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Ports du switch{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include "topologie/aff_port.html" with port_list=port_list %}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
17
topologie/templates/topologie/port.html
Normal file
17
topologie/templates/topologie/port.html
Normal file
|
@ -0,0 +1,17 @@
|
|||
{% extends "topologie/sidebar.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Création et modificationd 'utilisateur{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% bootstrap_form_errors topoform %}
|
||||
|
||||
<form class="form" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form topoform %}
|
||||
{%bootstrap_button "Créer ou modifier" button_type="submit" icon="ok" %}
|
||||
</form>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
5
topologie/templates/topologie/sidebar.html
Normal file
5
topologie/templates/topologie/sidebar.html
Normal file
|
@ -0,0 +1,5 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p><a href="{% url "topologie:index" %}">Liste des switchs</a></p>
|
||||
{% endblock %}
|
10
topologie/urls.py
Normal file
10
topologie/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.index, name='index'),
|
||||
url(r'^switch/(?P<switch_id>[0-9]+)$', views.index_port, name='index-port'),
|
||||
url(r'^edit_port/(?P<port_id>[0-9]+)$', views.edit_port, name='edit-port'),
|
||||
]
|
||||
|
|
@ -1,3 +1,35 @@
|
|||
from django.shortcuts import render
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
from topologie.models import Switch, Port
|
||||
from topologie.forms import EditPortForm
|
||||
from users.views import form
|
||||
|
||||
|
||||
def index(request):
|
||||
switch_list = Switch.objects.order_by('building', 'number')
|
||||
return render(request, 'topologie/index.html', {'switch_list': switch_list})
|
||||
|
||||
def index_port(request, switch_id):
|
||||
try:
|
||||
switch = Switch.objects.get(pk=switch_id)
|
||||
except Switch.DoesNotExist:
|
||||
messages.error(request, u"Switch inexistant")
|
||||
return redirect("/topologie/")
|
||||
port_list = Port.objects.filter(switch = switch).order_by('port')
|
||||
return render(request, 'topologie/index_p.html', {'port_list':port_list})
|
||||
|
||||
def edit_port(request, port_id):
|
||||
try:
|
||||
port = Port.objects.get(pk=port_id)
|
||||
except Port.DoesNotExist:
|
||||
messages.error(request, u"Port inexistant")
|
||||
return redirect("/topologie/")
|
||||
port = EditPortForm(request.POST or None, instance=port)
|
||||
if port.is_valid():
|
||||
port.save()
|
||||
messages.success(request, "Le port a bien été modifié")
|
||||
return redirect("/topologie")
|
||||
return form({'topoform':port}, 'topologie/port.html', request)
|
||||
|
||||
# Create your views here.
|
||||
|
|
30
users/migrations/0016_auto_20160706_1220.py
Normal file
30
users/migrations/0016_auto_20160706_1220.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import users.models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0015_whitelist'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='ban',
|
||||
name='date_end',
|
||||
field=models.DateTimeField(help_text='%d/%m/%y %H:%M:%S'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='pseudo',
|
||||
field=models.CharField(unique=True, validators=[users.models.linux_user_validator], max_length=32, help_text='Doit contenir uniquement des lettres, chiffres, ou tirets'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='whitelist',
|
||||
name='date_end',
|
||||
field=models.DateTimeField(help_text='%d/%m/%y %H:%M:%S'),
|
||||
),
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
from django.db import models
|
||||
from django.forms import ModelForm, Form
|
||||
from django import forms
|
||||
import re
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
|
@ -15,6 +16,15 @@ def remove_user_room(room):
|
|||
user.room = None
|
||||
user.save()
|
||||
|
||||
def linux_user_validator(login):
|
||||
""" Validation du pseudo pour respecter les contraintes unix"""
|
||||
UNIX_LOGIN_PATTERN = re.compile("^[a-z_][a-z0-9_-]*[$]?$")
|
||||
if not UNIX_LOGIN_PATTERN.match(login):
|
||||
raise forms.ValidationError(
|
||||
", ce pseudo ('%(label)s') contient des carractères interdits",
|
||||
params={'label': login},
|
||||
)
|
||||
|
||||
class User(models.Model):
|
||||
STATE_ACTIVE = 0
|
||||
STATE_DEACTIVATED = 1
|
||||
|
@ -27,9 +37,9 @@ class User(models.Model):
|
|||
|
||||
name = models.CharField(max_length=255)
|
||||
surname = models.CharField(max_length=255)
|
||||
pseudo = models.CharField(max_length=255, unique=True)
|
||||
pseudo = models.CharField(max_length=32, unique=True, help_text="Doit contenir uniquement des lettres, chiffres, ou tirets", validators=[linux_user_validator])
|
||||
email = models.EmailField()
|
||||
school = models.ForeignKey('School', on_delete=models.PROTECT)
|
||||
school = models.ForeignKey('School', on_delete=models.PROTECT, null=False, blank=False)
|
||||
comment = models.CharField(help_text="Commentaire, promo", max_length=255, blank=True)
|
||||
room = models.OneToOneField('topologie.Room', on_delete=models.PROTECT, blank=True, null=True)
|
||||
pwd_ssha = models.CharField(max_length=255)
|
||||
|
@ -66,7 +76,7 @@ class Ban(models.Model):
|
|||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||
raison = models.CharField(max_length=255)
|
||||
date_start = models.DateTimeField(auto_now_add=True)
|
||||
date_end = models.DateTimeField(help_text='%m/%d/%y %H:%M:%S')
|
||||
date_end = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user) + ' ' + str(self.raison)
|
||||
|
@ -75,24 +85,11 @@ class Whitelist(models.Model):
|
|||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||
raison = models.CharField(max_length=255)
|
||||
date_start = models.DateTimeField(auto_now_add=True)
|
||||
date_end = models.DateTimeField(help_text='%m/%d/%y %H:%M:%S')
|
||||
date_end = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')
|
||||
|
||||
def __str__(self):
|
||||
return str(self.user) + ' ' + str(self.raison)
|
||||
|
||||
class UserForm(ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(InfoForm, self).__init__(*args, **kwargs)
|
||||
self.fields['name'].label = 'Nom'
|
||||
self.fields['surname'].label = 'Prénom'
|
||||
self.fields['school'].label = 'Établissement'
|
||||
self.fields['comment'].label = 'Commentaire'
|
||||
self.fields['room'].label = 'Chambre'
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = '__all__'
|
||||
|
||||
class InfoForm(ModelForm):
|
||||
force = forms.BooleanField(label="Forcer le déménagement ?", initial=False, required=False)
|
||||
|
||||
|
@ -103,6 +100,8 @@ class InfoForm(ModelForm):
|
|||
self.fields['school'].label = 'Établissement'
|
||||
self.fields['comment'].label = 'Commentaire'
|
||||
self.fields['room'].label = 'Chambre'
|
||||
self.fields['room'].empty_label = "Pas de chambre"
|
||||
self.fields['school'].empty_label = "Séléctionner un établissement"
|
||||
|
||||
def clean_force(self):
|
||||
if self.cleaned_data.get('force', False):
|
||||
|
@ -113,6 +112,10 @@ class InfoForm(ModelForm):
|
|||
model = User
|
||||
fields = ['name','surname','pseudo','email', 'school', 'comment', 'room']
|
||||
|
||||
class UserForm(InfoForm):
|
||||
class Meta(InfoForm.Meta):
|
||||
fields = '__all__'
|
||||
|
||||
class PasswordForm(ModelForm):
|
||||
class Meta:
|
||||
model = User
|
||||
|
@ -128,10 +131,22 @@ class SchoolForm(ModelForm):
|
|||
model = School
|
||||
fields = ['name']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SchoolForm, self).__init__(*args, **kwargs)
|
||||
self.fields['name'].label = 'Établissement à ajouter'
|
||||
|
||||
class DelSchoolForm(ModelForm):
|
||||
schools = forms.ModelMultipleChoiceField(queryset=School.objects.all(), label="Etablissements actuels", widget=forms.CheckboxSelectMultiple)
|
||||
|
||||
class Meta:
|
||||
exclude = ['name']
|
||||
model = School
|
||||
|
||||
class RightForm(ModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RightForm, self).__init__(*args, **kwargs)
|
||||
self.fields['right'].label = 'Droit'
|
||||
self.fields['right'].empty_label = "Choisir un nouveau droit"
|
||||
|
||||
class Meta:
|
||||
model = Right
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<td>{{ ban.raison }}</td>
|
||||
<td>{{ ban.date_start }}</td>
|
||||
<td>{{ ban.date_end }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-ban' ban.id %}"><i class="glyphicon glyphicon-grain"></i> Editer</a></td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-ban' ban.id %}"><i class="glyphicon glyphicon-pushpin"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<th>Prénom</th>
|
||||
<th>Nom</th>
|
||||
<th>Pseudo</th>
|
||||
<th>Inscrit le</th>
|
||||
<th>Fin de cotisation le</th>
|
||||
<th>Connexion</th>
|
||||
<th>Profil</th>
|
||||
</tr>
|
||||
|
@ -14,19 +14,15 @@
|
|||
<td>{{ donnee.0.name }}</td>
|
||||
<td>{{ donnee.0.surname }}</td>
|
||||
<td>{{ donnee.0.pseudo }}</td>
|
||||
<td>{{ donnee.0.registered }}</td>
|
||||
<td>{{ donnee.2 }}</td>
|
||||
<td>{% if donnee.1 == True %}
|
||||
<font color="green">Active</font>
|
||||
{% else %}
|
||||
<font color="red">Désactivée</font>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><form method="POST" action="{% url "users:profil"%}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="user" id="user" value="{{ donnee.0.pseudo }}"></input>
|
||||
<button class="btn btn-primary btn-sm" type="submit"><i class="glyphicon glyphicon-tree-deciduous"></i></button>
|
||||
</form>
|
||||
</td>
|
||||
<td><a href="{% url "users:profil" donnee.0.id%}" class="btn btn-primary btn-sm" role="button"><i class="glyphicon glyphicon-user"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<td>{{ whitelist.raison }}</td>
|
||||
<td>{{ whitelist.date_start }}</td>
|
||||
<td>{{ whitelist.date_end }}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-whitelist' whitelist.id %}"><i class="glyphicon glyphicon-grain"></i> Editer</a></td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-whitelist' whitelist.id %}"><i class="glyphicon glyphicon-flag"></i> Editer</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
{% block title %}Utilisateurs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Adhérents</h2>
|
||||
{% include "users/aff_users.html" with users_list=users_list %}
|
||||
<br />
|
||||
<br />
|
||||
|
|
13
users/templates/users/index_ban.html
Normal file
13
users/templates/users/index_ban.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% extends "users/sidebar.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Utilisateurs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Bannissements</h2>
|
||||
{% include "users/aff_bans.html" with ban_list=ban_list %}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
||||
|
13
users/templates/users/index_whitelist.html
Normal file
13
users/templates/users/index_whitelist.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
{% extends "users/sidebar.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}Utilisateurs{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Accès à titre gracieux</h2>
|
||||
{% include "users/aff_whitelists.html" with white_list=white_list %}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
{% endblock %}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
{% block content %}
|
||||
<h2>Adhérent</h2>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-info' user.id %}"><i class="glyphicon glyphicon-fire"></i> Editer</a>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:edit-info' user.id %}"><i class="glyphicon glyphicon-edit"></i> Editer</a>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:password' user.id %}"><i class="glyphicon glyphicon-lock"></i> Changer le mot de passe</a>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:state' user.id %}"><i class="glyphicon glyphicon-flash"></i> Changer le statut</a>
|
||||
<a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-right' user.id %}"><i class="glyphicon glyphicon-ok"></i> Ajouter un droit</a>
|
||||
|
@ -74,7 +74,7 @@
|
|||
{% endif %}
|
||||
<th>Droits</th>
|
||||
{% if list_droits %}
|
||||
<td>{% for droit in list_droits %}{{ droit.right }} - {% endfor %}</td>
|
||||
<td>{% for droit in list_droits %}{{ droit.right }}{% if list_droits|length != forloop.counter %} - {% endif %} {% endfor %}</td>
|
||||
{% else %}
|
||||
<td>Aucun</td>
|
||||
{% endif %}
|
||||
|
@ -101,7 +101,7 @@
|
|||
<p>Aucun bannissement</p>
|
||||
{% endif %}
|
||||
<h2>Accès à titre gracieux :</h2>
|
||||
<h4><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-whitelist' user.id %}"><i class="glyphicon glyphicon-pushpin"></i> Accorder un accès à titre gracieux</a></h4>
|
||||
<h4><a class="btn btn-primary btn-sm" role="button" href="{% url 'users:add-whitelist' user.id %}"><i class="glyphicon glyphicon-flag"></i> Accorder un accès à titre gracieux</a></h4>
|
||||
{% if white_list %}
|
||||
{% include "users/aff_whitelists.html" with white_list=white_list %}
|
||||
{% else %}
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
{% block sidebar %}
|
||||
<p><a href="{% url "users:new-user" %}">Créer un adhérent</a></p>
|
||||
<p><a href="{% url "search:search" %}">Editer un adhérent</a></p>
|
||||
<p><a href="{% url "users:index" %}">Liste des adhérents</a></p>
|
||||
<p><a href="{% url "search:search" %}">Ajouter un bannissement</a></p>
|
||||
<p><a href="{% url "search:search" %}">Gérer les bannissements</a></p>
|
||||
<p><a href="{% url "users:index-ban" %}">Liste des bannissements</a></p>
|
||||
<p><a href="{% url "users:index-white" %}">Liste des accès à titre gracieux</a></p>
|
||||
<p><a href="{% url "users:add-school" %}">Ajouter un établissement</a></p>
|
||||
<p><a href="{% url "users:del-school" %}">Supprimer un établissement</a></p>
|
||||
<p><a href="{% url "users:del-right" %}">Retirer un droit rezo</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -13,7 +13,11 @@ urlpatterns = [
|
|||
url(r'^edit_whitelist/(?P<whitelistid>[0-9]+)$', views.edit_whitelist, name='edit-whitelist'),
|
||||
url(r'^add_right/(?P<userid>[0-9]+)$', views.add_right, name='add-right'),
|
||||
url(r'^del_right/$', views.del_right, name='del-right'),
|
||||
url(r'^profil/$', views.profil, name='profil'),
|
||||
url(r'^add_school/$', views.add_school, name='add-school'),
|
||||
url(r'^del_school/$', views.del_school, name='del-school'),
|
||||
url(r'^profil/(?P<userid>[0-9]+)$', views.profil, name='profil'),
|
||||
url(r'^index_ban/$', views.index_ban, name='index-ban'),
|
||||
url(r'^index_white/$', views.index_white, name='index-white'),
|
||||
url(r'^$', views.index, name='index'),
|
||||
]
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@ from django.shortcuts import render_to_response, get_object_or_404
|
|||
from django.core.context_processors import csrf
|
||||
from django.template import Context, RequestContext, loader
|
||||
from django.contrib import messages
|
||||
from django.db.models import Max
|
||||
from django.db.models import Max, ProtectedError
|
||||
from django.db import IntegrityError
|
||||
from django.utils import timezone
|
||||
|
||||
from users.models import User, Right, Ban, DelRightForm, UserForm, InfoForm, PasswordForm, StateForm, RightForm, BanForm, ProfilForm, Whitelist, WhitelistForm
|
||||
from users.models import User, Right, Ban, DelRightForm, UserForm, InfoForm, PasswordForm, StateForm, RightForm, BanForm, ProfilForm, Whitelist, WhitelistForm, DelSchoolForm, SchoolForm
|
||||
from cotisations.models import Facture
|
||||
from machines.models import Machine, Interface
|
||||
from users.forms import PassForm
|
||||
|
@ -62,10 +62,13 @@ def is_whitelisted(user):
|
|||
|
||||
def has_access(user):
|
||||
""" Renvoie si un utilisateur a accès à internet"""
|
||||
if user.state == User.STATE_ACTIVE and not is_ban(user) and ( is_adherent(user) or is_whitelisted(user)):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return user.state == User.STATE_ACTIVE and not is_ban(user) and ( is_adherent(user) or is_whitelisted(user))
|
||||
|
||||
def is_active(interface):
|
||||
""" Renvoie si une interface doit avoir accès ou non """
|
||||
machine = interface.machine
|
||||
user = machine.user
|
||||
return machine.active and has_access(user)
|
||||
|
||||
def form(ctx, template, request):
|
||||
c = ctx
|
||||
|
@ -214,31 +217,63 @@ def edit_whitelist(request, whitelistid):
|
|||
return redirect("/users/")
|
||||
return form({'userform': whitelist}, 'users/user.html', request)
|
||||
|
||||
def add_school(request):
|
||||
school = SchoolForm(request.POST or None)
|
||||
if school.is_valid():
|
||||
school.save()
|
||||
messages.success(request, "L'établissement a été ajouté")
|
||||
return redirect("/users/")
|
||||
return form({'userform': school}, 'users/user.html', request)
|
||||
|
||||
def del_school(request):
|
||||
school = DelSchoolForm(request.POST or None)
|
||||
if school.is_valid():
|
||||
school_dels = school.cleaned_data['schools']
|
||||
for school_del in school_dels:
|
||||
try:
|
||||
school_del.delete()
|
||||
messages.success(request, "L'établissement a été supprimé")
|
||||
except ProtectedError:
|
||||
messages.error(request, "L'établissement %s est affecté à au moins un user, vous ne pouvez pas le supprimer" % school_del)
|
||||
return redirect("/users/")
|
||||
return form({'userform': school}, 'users/user.html', request)
|
||||
|
||||
def index(request):
|
||||
users_list = User.objects.order_by('pk')
|
||||
connexion = []
|
||||
for user in users_list:
|
||||
connexion.append([user, has_access(user)])
|
||||
end = end_adhesion(user)
|
||||
access = has_access(user)
|
||||
if(end!=None):
|
||||
connexion.append([user, access, end])
|
||||
else:
|
||||
connexion.append([user, access, "Non adhérent"])
|
||||
return render(request, 'users/index.html', {'users_list': connexion})
|
||||
|
||||
def profil(request):
|
||||
if request.method == 'POST':
|
||||
profil = ProfilForm(request.POST or None)
|
||||
if profil.is_valid():
|
||||
profils = profil.cleaned_data['user']
|
||||
users = User.objects.get(pseudo = profils)
|
||||
machines = Interface.objects.filter(machine=Machine.objects.filter(user__pseudo = users))
|
||||
factures = Facture.objects.filter(user__pseudo = users)
|
||||
bans = Ban.objects.filter(user__pseudo = users)
|
||||
whitelists = Whitelist.objects.filter(user__pseudo = users)
|
||||
end_bans = None
|
||||
end_whitelists = None
|
||||
if(is_ban(users)):
|
||||
end_bans=end_ban(users)
|
||||
if(is_whitelisted(users)):
|
||||
end_whitelists=end_whitelist(users)
|
||||
list_droits = Right.objects.filter(user=users)
|
||||
return render(request, 'users/profil.html', {'user': users, 'machine_list' :machines, 'facture_list':factures, 'ban_list':bans, 'white_list':whitelists,'end_ban':end_bans,'end_whitelist':end_whitelists, 'end_adhesion':end_adhesion(users), 'actif':has_access(users), 'list_droits': list_droits})
|
||||
return redirect("/users/")
|
||||
return redirect("/users/")
|
||||
def index_ban(request):
|
||||
ban_list = Ban.objects.order_by('date_start')
|
||||
return render(request, 'users/index_ban.html', {'ban_list':ban_list})
|
||||
|
||||
def index_white(request):
|
||||
white_list = Whitelist.objects.order_by('date_start')
|
||||
return render(request, 'users/index_whitelist.html', {'white_list':white_list})
|
||||
|
||||
def profil(request, userid):
|
||||
try:
|
||||
users = User.objects.get(pk=userid)
|
||||
except User.DoesNotExist:
|
||||
messages.error(request, u"Utilisateur inexistant" )
|
||||
return redirect("/users/")
|
||||
machines = Interface.objects.filter(machine=Machine.objects.filter(user__pseudo = users))
|
||||
factures = Facture.objects.filter(user__pseudo = users)
|
||||
bans = Ban.objects.filter(user__pseudo = users)
|
||||
whitelists = Whitelist.objects.filter(user__pseudo = users)
|
||||
end_bans = None
|
||||
end_whitelists = None
|
||||
if(is_ban(users)):
|
||||
end_bans=end_ban(users)
|
||||
if(is_whitelisted(users)):
|
||||
end_whitelists=end_whitelist(users)
|
||||
list_droits = Right.objects.filter(user=users)
|
||||
return render(request, 'users/profil.html', {'user': users, 'machine_list' :machines, 'facture_list':factures, 'ban_list':bans, 'white_list':whitelists,'end_ban':end_bans,'end_whitelist':end_whitelists, 'end_adhesion':end_adhesion(users), 'actif':has_access(users), 'list_droits': list_droits})
|
||||
|
||||
|
|
Loading…
Reference in a new issue