mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-12-26 08:53:46 +00:00
Merge branch 'master' into massive_use_bft_tag
This commit is contained in:
commit
25d460cb91
19 changed files with 1719 additions and 619 deletions
|
@ -19,7 +19,10 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Urls de l'application logs, pointe vers les fonctions de views.
|
||||||
|
Inclu dans le re2o.urls
|
||||||
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
@ -29,7 +32,9 @@ from . import views
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', views.index, name='index'),
|
url(r'^$', views.index, name='index'),
|
||||||
url(r'^stats_logs$', views.stats_logs, name='stats-logs'),
|
url(r'^stats_logs$', views.stats_logs, name='stats-logs'),
|
||||||
url(r'^revert_action/(?P<revision_id>[0-9]+)$', views.revert_action, name='revert-action'),
|
url(r'^revert_action/(?P<revision_id>[0-9]+)$',
|
||||||
|
views.revert_action,
|
||||||
|
name='revert-action'),
|
||||||
url(r'^stats_general/$', views.stats_general, name='stats-general'),
|
url(r'^stats_general/$', views.stats_general, name='stats-general'),
|
||||||
url(r'^stats_models/$', views.stats_models, name='stats-models'),
|
url(r'^stats_models/$', views.stats_models, name='stats-models'),
|
||||||
url(r'^stats_users/$', views.stats_users, name='stats-users'),
|
url(r'^stats_users/$', views.stats_users, name='stats-users'),
|
||||||
|
|
335
logs/views.py
335
logs/views.py
|
@ -23,62 +23,67 @@
|
||||||
# App de gestion des statistiques pour re2o
|
# App de gestion des statistiques pour re2o
|
||||||
# Gabriel Détraz
|
# Gabriel Détraz
|
||||||
# Gplv2
|
# Gplv2
|
||||||
|
"""
|
||||||
|
Vues des logs et statistiques générales.
|
||||||
|
|
||||||
|
La vue index générale affiche une selection des dernières actions,
|
||||||
|
classées selon l'importance, avec date, et user formatés.
|
||||||
|
|
||||||
|
Stats_logs renvoie l'ensemble des logs.
|
||||||
|
|
||||||
|
Les autres vues sont thématiques, ensemble des statistiques et du
|
||||||
|
nombre d'objets par models, nombre d'actions par user, etc
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.template.context_processors import csrf
|
|
||||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||||
from django.template import Context, RequestContext, loader
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.db.models import ProtectedError
|
|
||||||
from django.forms import ValidationError
|
|
||||||
from django.db import transaction
|
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
from reversion.models import Revision
|
from reversion.models import Revision
|
||||||
from reversion.models import Version, ContentType
|
from reversion.models import Version, ContentType
|
||||||
|
|
||||||
from users.models import User, ServiceUser, Right, School, ListRight, ListShell, Ban, Whitelist
|
from users.models import User, ServiceUser, Right, School, ListRight, ListShell
|
||||||
from users.models import all_has_access, all_whitelisted, all_baned, all_adherent
|
from users.models import Ban, Whitelist
|
||||||
from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation
|
from cotisations.models import Facture, Vente, Article, Banque, Paiement
|
||||||
from machines.models import Machine, MachineType, IpType, Extension, Interface, Domain, IpList
|
from cotisations.models import Cotisation
|
||||||
from machines.views import all_active_assigned_interfaces_count, all_active_interfaces_count
|
from machines.models import Machine, MachineType, IpType, Extension, Interface
|
||||||
|
from machines.models import Domain, IpList
|
||||||
from topologie.models import Switch, Port, Room
|
from topologie.models import Switch, Port, Room
|
||||||
from preferences.models import GeneralOption
|
from preferences.models import GeneralOption
|
||||||
|
from re2o.views import form
|
||||||
from django.utils import timezone
|
from re2o.utils import all_whitelisted, all_baned, all_has_access, all_adherent
|
||||||
from dateutil.relativedelta import relativedelta
|
from re2o.utils import all_active_assigned_interfaces_count
|
||||||
|
from re2o.utils import all_active_interfaces_count
|
||||||
|
|
||||||
STATS_DICT = {
|
STATS_DICT = {
|
||||||
0 : ["Tout", 36],
|
0: ["Tout", 36],
|
||||||
1 : ["1 mois", 1],
|
1: ["1 mois", 1],
|
||||||
2 : ["2 mois", 2],
|
2: ["2 mois", 2],
|
||||||
3 : ["6 mois", 6],
|
3: ["6 mois", 6],
|
||||||
4 : ["1 an", 12],
|
4: ["1 an", 12],
|
||||||
5 : ["2 an", 24],
|
5: ["2 an", 24],
|
||||||
}
|
}
|
||||||
|
|
||||||
def form(ctx, template, request):
|
|
||||||
c = ctx
|
|
||||||
c.update(csrf(request))
|
|
||||||
return render(request, template, c)
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index(request):
|
def index(request):
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
"""Affiche les logs affinés, date reformatées, selectionne
|
||||||
|
les event importants (ajout de droits, ajout de ban/whitelist)"""
|
||||||
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
|
|
||||||
# The types of content kept for display
|
# The types of content kept for display
|
||||||
content_type_filter = ['ban', 'whitelist', 'vente', 'interface', 'user']
|
content_type_filter = ['ban', 'whitelist', 'vente', 'interface', 'user']
|
||||||
|
|
||||||
# Select only wanted versions
|
# Select only wanted versions
|
||||||
versions = Version.objects.filter(content_type__in=ContentType.objects.filter(model__in=content_type_filter)).order_by('revision__date_created').reverse().select_related('revision')
|
versions = Version.objects.filter(
|
||||||
|
content_type__in=ContentType.objects.filter(
|
||||||
|
model__in=content_type_filter
|
||||||
|
)
|
||||||
|
).order_by('revision__date_created').reverse().select_related('revision')
|
||||||
paginator = Paginator(versions, pagination_number)
|
paginator = Paginator(versions, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
try:
|
try:
|
||||||
|
@ -87,7 +92,7 @@ def index(request):
|
||||||
# If page is not an integer, deliver first page.
|
# If page is not an integer, deliver first page.
|
||||||
versions = paginator.page(1)
|
versions = paginator.page(1)
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
versions = paginator.page(paginator.num_pages)
|
versions = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
# Force to have a list instead of QuerySet
|
# Force to have a list instead of QuerySet
|
||||||
|
@ -95,30 +100,38 @@ def index(request):
|
||||||
# Items to remove later because invalid
|
# Items to remove later because invalid
|
||||||
to_remove = []
|
to_remove = []
|
||||||
# Parse every item (max = pagination_number)
|
# Parse every item (max = pagination_number)
|
||||||
for i in range( len( versions.object_list ) ):
|
for i in range(len(versions.object_list)):
|
||||||
if versions.object_list[i].object :
|
if versions.object_list[i].object:
|
||||||
v = versions.object_list[i]
|
version = versions.object_list[i]
|
||||||
versions.object_list[i] = {
|
versions.object_list[i] = {
|
||||||
'rev_id' : v.revision.id,
|
'rev_id': version.revision.id,
|
||||||
'comment': v.revision.comment,
|
'comment': version.revision.comment,
|
||||||
'datetime': v.revision.date_created.strftime('%d/%m/%y %H:%M:%S'),
|
'datetime': version.revision.date_created.strftime(
|
||||||
'username': v.revision.user.get_username() if v.revision.user else '?',
|
'%d/%m/%y %H:%M:%S'
|
||||||
'user_id': v.revision.user_id,
|
),
|
||||||
'version': v }
|
'username':
|
||||||
else :
|
version.revision.user.get_username()
|
||||||
to_remove.insert(0,i)
|
if version.revision.user else '?',
|
||||||
|
'user_id': version.revision.user_id,
|
||||||
|
'version': version}
|
||||||
|
else:
|
||||||
|
to_remove.insert(0, i)
|
||||||
# Remove all tagged invalid items
|
# Remove all tagged invalid items
|
||||||
for i in to_remove :
|
for i in to_remove:
|
||||||
versions.object_list.pop(i)
|
versions.object_list.pop(i)
|
||||||
|
|
||||||
return render(request, 'logs/index.html', {'versions_list': versions})
|
return render(request, 'logs/index.html', {'versions_list': versions})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def stats_logs(request):
|
def stats_logs(request):
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
"""Affiche l'ensemble des logs et des modifications sur les objets,
|
||||||
|
classés par date croissante, en vrac"""
|
||||||
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
revisions = Revision.objects.all().order_by('date_created').reverse().select_related('user').prefetch_related('version_set__object')
|
revisions = Revision.objects.all().order_by('date_created')\
|
||||||
|
.reverse().select_related('user')\
|
||||||
|
.prefetch_related('version_set__object')
|
||||||
paginator = Paginator(revisions, pagination_number)
|
paginator = Paginator(revisions, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
try:
|
try:
|
||||||
|
@ -127,9 +140,12 @@ def stats_logs(request):
|
||||||
# If page is not an integer, deliver first page.
|
# If page is not an integer, deliver first page.
|
||||||
revisions = paginator.page(1)
|
revisions = paginator.page(1)
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
revisions = paginator.page(paginator.num_pages)
|
revisions = paginator.page(paginator.num_pages)
|
||||||
return render(request, 'logs/stats_logs.html', {'revisions_list': revisions})
|
return render(request, 'logs/stats_logs.html', {
|
||||||
|
'revisions_list': revisions
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
|
@ -138,121 +154,182 @@ def revert_action(request, revision_id):
|
||||||
try:
|
try:
|
||||||
revision = Revision.objects.get(id=revision_id)
|
revision = Revision.objects.get(id=revision_id)
|
||||||
except Revision.DoesNotExist:
|
except Revision.DoesNotExist:
|
||||||
messages.error(request, u"Revision inexistante" )
|
messages.error(request, u"Revision inexistante")
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
revision.revert()
|
revision.revert()
|
||||||
messages.success(request, "L'action a été supprimée")
|
messages.success(request, "L'action a été supprimée")
|
||||||
return redirect("/logs/")
|
return redirect("/logs/")
|
||||||
return form({'objet': revision, 'objet_name': revision.__class__.__name__ }, 'logs/delete.html', request)
|
return form({
|
||||||
|
'objet': revision,
|
||||||
|
'objet_name': revision.__class__.__name__
|
||||||
|
}, 'logs/delete.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def stats_general(request):
|
def stats_general(request):
|
||||||
all_active_users = User.objects.filter(state=User.STATE_ACTIVE)
|
"""Statistiques générales affinées sur les ip, activées, utilisées par
|
||||||
ip = dict()
|
range, et les statistiques générales sur les users : users actifs,
|
||||||
|
cotisants, activés, archivés, etc"""
|
||||||
|
ip_dict = dict()
|
||||||
for ip_range in IpType.objects.all():
|
for ip_range in IpType.objects.all():
|
||||||
all_ip = IpList.objects.filter(ip_type=ip_range)
|
all_ip = IpList.objects.filter(ip_type=ip_range)
|
||||||
used_ip = Interface.objects.filter(ipv4__in=all_ip).count()
|
used_ip = Interface.objects.filter(ipv4__in=all_ip).count()
|
||||||
active_ip = all_active_assigned_interfaces_count().filter(ipv4__in=IpList.objects.filter(ip_type=ip_range)).count()
|
active_ip = all_active_assigned_interfaces_count().filter(
|
||||||
ip[ip_range] = [ip_range, all_ip.count(), used_ip, active_ip, all_ip.count()-used_ip]
|
ipv4__in=IpList.objects.filter(ip_type=ip_range)
|
||||||
|
).count()
|
||||||
|
ip_dict[ip_range] = [ip_range, all_ip.count(),
|
||||||
|
used_ip, active_ip, all_ip.count()-used_ip]
|
||||||
stats = [
|
stats = [
|
||||||
[["Categorie", "Nombre d'utilisateurs"], {
|
[["Categorie", "Nombre d'utilisateurs"], {
|
||||||
'active_users' : ["Users actifs", User.objects.filter(state=User.STATE_ACTIVE).count()],
|
'active_users': [
|
||||||
'inactive_users' : ["Users désactivés", User.objects.filter(state=User.STATE_DISABLED).count()],
|
"Users actifs",
|
||||||
'archive_users' : ["Users archivés", User.objects.filter(state=User.STATE_ARCHIVE).count()],
|
User.objects.filter(state=User.STATE_ACTIVE).count()],
|
||||||
'adherent_users' : ["Adhérents à l'association", all_adherent().count()],
|
'inactive_users': [
|
||||||
'connexion_users' : ["Utilisateurs bénéficiant d'une connexion", all_has_access().count()],
|
"Users désactivés",
|
||||||
'ban_users' : ["Utilisateurs bannis", all_baned().count()],
|
User.objects.filter(state=User.STATE_DISABLED).count()],
|
||||||
'whitelisted_user' : ["Utilisateurs bénéficiant d'une connexion gracieuse", all_whitelisted().count()],
|
'archive_users': [
|
||||||
'actives_interfaces' : ["Interfaces actives (ayant accès au reseau)", all_active_interfaces_count().count()],
|
"Users archivés",
|
||||||
'actives_assigned_interfaces' : ["Interfaces actives et assignées ipv4", all_active_assigned_interfaces_count().count()]
|
User.objects.filter(state=User.STATE_ARCHIVE).count()],
|
||||||
}],
|
'adherent_users': [
|
||||||
[["Range d'ip", "Nombre d'ip totales", "Ip assignées", "Ip assignées à une machine active", "Ip non assignées"] ,ip]
|
"Adhérents à l'association",
|
||||||
]
|
all_adherent().count()],
|
||||||
|
'connexion_users': [
|
||||||
|
"Utilisateurs bénéficiant d'une connexion",
|
||||||
|
all_has_access().count()],
|
||||||
|
'ban_users': [
|
||||||
|
"Utilisateurs bannis",
|
||||||
|
all_baned().count()],
|
||||||
|
'whitelisted_user': [
|
||||||
|
"Utilisateurs bénéficiant d'une connexion gracieuse",
|
||||||
|
all_whitelisted().count()],
|
||||||
|
'actives_interfaces': [
|
||||||
|
"Interfaces actives (ayant accès au reseau)",
|
||||||
|
all_active_interfaces_count().count()],
|
||||||
|
'actives_assigned_interfaces': [
|
||||||
|
"Interfaces actives et assignées ipv4",
|
||||||
|
all_active_assigned_interfaces_count().count()]
|
||||||
|
}],
|
||||||
|
[["Range d'ip", "Nombre d'ip totales", "Ip assignées",
|
||||||
|
"Ip assignées à une machine active", "Ip non assignées"], ip_dict]
|
||||||
|
]
|
||||||
return render(request, 'logs/stats_general.html', {'stats_list': stats})
|
return render(request, 'logs/stats_general.html', {'stats_list': stats})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def stats_models(request):
|
def stats_models(request):
|
||||||
all_active_users = User.objects.filter(state=User.STATE_ACTIVE)
|
"""Statistiques générales, affiche les comptages par models:
|
||||||
|
nombre d'users, d'écoles, de droits, de bannissements,
|
||||||
|
de factures, de ventes, de banque, de machines, etc"""
|
||||||
stats = {
|
stats = {
|
||||||
'Users' : {
|
'Users': {
|
||||||
'users' : [User.PRETTY_NAME, User.objects.count()],
|
'users': [User.PRETTY_NAME, User.objects.count()],
|
||||||
'serviceuser' : [ServiceUser.PRETTY_NAME, ServiceUser.objects.count()],
|
'serviceuser': [ServiceUser.PRETTY_NAME,
|
||||||
'right' : [Right.PRETTY_NAME, Right.objects.count()],
|
ServiceUser.objects.count()],
|
||||||
'school' : [School.PRETTY_NAME, School.objects.count()],
|
'right': [Right.PRETTY_NAME, Right.objects.count()],
|
||||||
'listright' : [ListRight.PRETTY_NAME, ListRight.objects.count()],
|
'school': [School.PRETTY_NAME, School.objects.count()],
|
||||||
'listshell' : [ListShell.PRETTY_NAME, ListShell.objects.count()],
|
'listright': [ListRight.PRETTY_NAME, ListRight.objects.count()],
|
||||||
'ban' : [Ban.PRETTY_NAME, Ban.objects.count()],
|
'listshell': [ListShell.PRETTY_NAME, ListShell.objects.count()],
|
||||||
'whitelist' : [Whitelist.PRETTY_NAME, Whitelist.objects.count()]
|
'ban': [Ban.PRETTY_NAME, Ban.objects.count()],
|
||||||
},
|
'whitelist': [Whitelist.PRETTY_NAME, Whitelist.objects.count()]
|
||||||
'Cotisations' : {
|
},
|
||||||
'factures' : [Facture.PRETTY_NAME, Facture.objects.count()],
|
'Cotisations': {
|
||||||
'vente' : [Vente.PRETTY_NAME, Vente.objects.count()],
|
'factures': [Facture.PRETTY_NAME, Facture.objects.count()],
|
||||||
'cotisation' : [Cotisation.PRETTY_NAME, Cotisation.objects.count()],
|
'vente': [Vente.PRETTY_NAME, Vente.objects.count()],
|
||||||
'article' : [Article.PRETTY_NAME, Article.objects.count()],
|
'cotisation': [Cotisation.PRETTY_NAME, Cotisation.objects.count()],
|
||||||
'banque' : [Banque.PRETTY_NAME, Banque.objects.count()],
|
'article': [Article.PRETTY_NAME, Article.objects.count()],
|
||||||
'cotisation' : [Cotisation.PRETTY_NAME, Cotisation.objects.count()],
|
'banque': [Banque.PRETTY_NAME, Banque.objects.count()],
|
||||||
},
|
},
|
||||||
'Machines' : {
|
'Machines': {
|
||||||
'machine' : [Machine.PRETTY_NAME, Machine.objects.count()],
|
'machine': [Machine.PRETTY_NAME, Machine.objects.count()],
|
||||||
'typemachine' : [MachineType.PRETTY_NAME, MachineType.objects.count()],
|
'typemachine': [MachineType.PRETTY_NAME,
|
||||||
'typeip' : [IpType.PRETTY_NAME, IpType.objects.count()],
|
MachineType.objects.count()],
|
||||||
'extension' : [Extension.PRETTY_NAME, Extension.objects.count()],
|
'typeip': [IpType.PRETTY_NAME, IpType.objects.count()],
|
||||||
'interface' : [Interface.PRETTY_NAME, Interface.objects.count()],
|
'extension': [Extension.PRETTY_NAME, Extension.objects.count()],
|
||||||
'alias' : [Domain.PRETTY_NAME, Domain.objects.exclude(cname=None).count()],
|
'interface': [Interface.PRETTY_NAME, Interface.objects.count()],
|
||||||
'iplist' : [IpList.PRETTY_NAME, IpList.objects.count()],
|
'alias': [Domain.PRETTY_NAME,
|
||||||
},
|
Domain.objects.exclude(cname=None).count()],
|
||||||
'Topologie' : {
|
'iplist': [IpList.PRETTY_NAME, IpList.objects.count()],
|
||||||
'switch' : [Switch.PRETTY_NAME, Switch.objects.count()],
|
},
|
||||||
'port' : [Port.PRETTY_NAME, Port.objects.count()],
|
'Topologie': {
|
||||||
'chambre' : [Room.PRETTY_NAME, Room.objects.count()],
|
'switch': [Switch.PRETTY_NAME, Switch.objects.count()],
|
||||||
},
|
'port': [Port.PRETTY_NAME, Port.objects.count()],
|
||||||
'Actions effectuées sur la base' :
|
'chambre': [Room.PRETTY_NAME, Room.objects.count()],
|
||||||
{
|
},
|
||||||
'revision' : ["Nombre d'actions", Revision.objects.count()],
|
'Actions effectuées sur la base':
|
||||||
},
|
{
|
||||||
|
'revision': ["Nombre d'actions", Revision.objects.count()],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return render(request, 'logs/stats_models.html', {'stats_list': stats})
|
return render(request, 'logs/stats_models.html', {'stats_list': stats})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def stats_users(request):
|
def stats_users(request):
|
||||||
|
"""Affiche les statistiques base de données aggrégées par user :
|
||||||
|
nombre de machines par user, d'etablissements par user,
|
||||||
|
de moyens de paiements par user, de banque par user,
|
||||||
|
de bannissement par user, etc"""
|
||||||
onglet = request.GET.get('onglet')
|
onglet = request.GET.get('onglet')
|
||||||
try:
|
try:
|
||||||
search_field = STATS_DICT[onglet]
|
_search_field = STATS_DICT[onglet]
|
||||||
except:
|
except KeyError:
|
||||||
search_field = STATS_DICT[0]
|
_search_field = STATS_DICT[0]
|
||||||
onglet = 0
|
onglet = 0
|
||||||
start_date = timezone.now() + relativedelta(months=-search_field[1])
|
|
||||||
stats = {
|
stats = {
|
||||||
'Utilisateur' : {
|
'Utilisateur': {
|
||||||
'Machines' : User.objects.annotate(num=Count('machine')).order_by('-num')[:10],
|
'Machines': User.objects.annotate(
|
||||||
'Facture' : User.objects.annotate(num=Count('facture')).order_by('-num')[:10],
|
num=Count('machine')
|
||||||
'Bannissement' : User.objects.annotate(num=Count('ban')).order_by('-num')[:10],
|
).order_by('-num')[:10],
|
||||||
'Accès gracieux' : User.objects.annotate(num=Count('whitelist')).order_by('-num')[:10],
|
'Facture': User.objects.annotate(
|
||||||
'Droits' : User.objects.annotate(num=Count('right')).order_by('-num')[:10],
|
num=Count('facture')
|
||||||
},
|
).order_by('-num')[:10],
|
||||||
'Etablissement' : {
|
'Bannissement': User.objects.annotate(
|
||||||
'Utilisateur' : School.objects.annotate(num=Count('user')).order_by('-num')[:10],
|
num=Count('ban')
|
||||||
},
|
).order_by('-num')[:10],
|
||||||
'Moyen de paiement' : {
|
'Accès gracieux': User.objects.annotate(
|
||||||
'Utilisateur' : Paiement.objects.annotate(num=Count('facture')).order_by('-num')[:10],
|
num=Count('whitelist')
|
||||||
},
|
).order_by('-num')[:10],
|
||||||
'Banque' : {
|
'Droits': User.objects.annotate(
|
||||||
'Utilisateur' : Banque.objects.annotate(num=Count('facture')).order_by('-num')[:10],
|
num=Count('right')
|
||||||
},
|
).order_by('-num')[:10],
|
||||||
|
},
|
||||||
|
'Etablissement': {
|
||||||
|
'Utilisateur': School.objects.annotate(
|
||||||
|
num=Count('user')
|
||||||
|
).order_by('-num')[:10],
|
||||||
|
},
|
||||||
|
'Moyen de paiement': {
|
||||||
|
'Utilisateur': Paiement.objects.annotate(
|
||||||
|
num=Count('facture')
|
||||||
|
).order_by('-num')[:10],
|
||||||
|
},
|
||||||
|
'Banque': {
|
||||||
|
'Utilisateur': Banque.objects.annotate(
|
||||||
|
num=Count('facture')
|
||||||
|
).order_by('-num')[:10],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return render(request, 'logs/stats_users.html', {'stats_list': stats, 'stats_dict' : STATS_DICT, 'active_field': onglet})
|
return render(request, 'logs/stats_users.html', {
|
||||||
|
'stats_list': stats,
|
||||||
|
'stats_dict': STATS_DICT,
|
||||||
|
'active_field': onglet
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def stats_actions(request):
|
def stats_actions(request):
|
||||||
onglet = request.GET.get('onglet')
|
"""Vue qui affiche les statistiques de modifications d'objets par
|
||||||
|
utilisateurs.
|
||||||
|
Affiche le nombre de modifications aggrégées par utilisateurs"""
|
||||||
stats = {
|
stats = {
|
||||||
'Utilisateur' : {
|
'Utilisateur': {
|
||||||
'Action' : User.objects.annotate(num=Count('revision')).order_by('-num')[:40],
|
'Action': User.objects.annotate(
|
||||||
},
|
num=Count('revision')
|
||||||
|
).order_by('-num')[:40],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
return render(request, 'logs/stats_users.html', {'stats_list': stats})
|
return render(request, 'logs/stats_users.html', {'stats_list': stats})
|
||||||
|
|
|
@ -53,30 +53,10 @@ from .forms import EditIpTypeForm, IpTypeForm, DelIpTypeForm, DomainForm, AliasF
|
||||||
from .forms import EditOuverturePortListForm, EditOuverturePortConfigForm
|
from .forms import EditOuverturePortListForm, EditOuverturePortConfigForm
|
||||||
from .models import IpType, Machine, Interface, IpList, MachineType, Extension, Mx, Ns, Domain, Service, Service_link, Vlan, Nas, Text, OuverturePortList, OuverturePort
|
from .models import IpType, Machine, Interface, IpList, MachineType, Extension, Mx, Ns, Domain, Service, Service_link, Vlan, Nas, Text, OuverturePortList, OuverturePort
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from users.models import all_has_access
|
|
||||||
from preferences.models import GeneralOption, OptionalMachine
|
from preferences.models import GeneralOption, OptionalMachine
|
||||||
from re2o.templatetags.massive_bootstrap_form import hidden_id, input_id
|
from re2o.templatetags.massive_bootstrap_form import hidden_id, input_id
|
||||||
|
from re2o.utils import all_active_assigned_interfaces, all_has_access
|
||||||
def all_active_interfaces():
|
from re2o.views import form
|
||||||
"""Renvoie l'ensemble des machines autorisées à sortir sur internet """
|
|
||||||
return Interface.objects.filter(machine__in=Machine.objects.filter(user__in=all_has_access()).filter(active=True)).select_related('domain').select_related('machine').select_related('type').select_related('ipv4').select_related('domain__extension').select_related('ipv4__ip_type').distinct()
|
|
||||||
|
|
||||||
def all_active_assigned_interfaces():
|
|
||||||
""" Renvoie l'ensemble des machines qui ont une ipv4 assignées et disposant de l'accès internet"""
|
|
||||||
return all_active_interfaces().filter(ipv4__isnull=False)
|
|
||||||
|
|
||||||
def all_active_interfaces_count():
|
|
||||||
""" Version light seulement pour compter"""
|
|
||||||
return Interface.objects.filter(machine__in=Machine.objects.filter(user__in=all_has_access()).filter(active=True))
|
|
||||||
|
|
||||||
def all_active_assigned_interfaces_count():
|
|
||||||
""" Version light seulement pour compter"""
|
|
||||||
return all_active_interfaces_count().filter(ipv4__isnull=False)
|
|
||||||
|
|
||||||
def form(ctx, template, request):
|
|
||||||
c = ctx
|
|
||||||
c.update(csrf(request))
|
|
||||||
return render(request, template, c)
|
|
||||||
|
|
||||||
def f_type_id( is_type_tt ):
|
def f_type_id( is_type_tt ):
|
||||||
""" The id that will be used in HTML to store the value of the field
|
""" The id that will be used in HTML to store the value of the field
|
||||||
|
|
|
@ -20,35 +20,53 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Classes admin pour les models de preferences
|
||||||
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from reversion.admin import VersionAdmin
|
from reversion.admin import VersionAdmin
|
||||||
|
|
||||||
from .models import OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption, Service, AssoOption, MailMessageOption
|
from .models import OptionalUser, OptionalMachine, OptionalTopologie
|
||||||
|
from .models import GeneralOption, Service, AssoOption, MailMessageOption
|
||||||
|
|
||||||
|
|
||||||
class OptionalUserAdmin(VersionAdmin):
|
class OptionalUserAdmin(VersionAdmin):
|
||||||
|
"""Class admin options user"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OptionalTopologieAdmin(VersionAdmin):
|
class OptionalTopologieAdmin(VersionAdmin):
|
||||||
|
"""Class admin options topologie"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class OptionalMachineAdmin(VersionAdmin):
|
class OptionalMachineAdmin(VersionAdmin):
|
||||||
|
"""Class admin options machines"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GeneralOptionAdmin(VersionAdmin):
|
class GeneralOptionAdmin(VersionAdmin):
|
||||||
|
"""Class admin options générales"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ServiceAdmin(VersionAdmin):
|
class ServiceAdmin(VersionAdmin):
|
||||||
|
"""Class admin gestion des services de la page d'accueil"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AssoOptionAdmin(VersionAdmin):
|
class AssoOptionAdmin(VersionAdmin):
|
||||||
|
"""Class admin options de l'asso"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MailMessageOptionAdmin(VersionAdmin):
|
class MailMessageOptionAdmin(VersionAdmin):
|
||||||
|
"""Class admin options mail"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(OptionalUser, OptionalUserAdmin)
|
admin.site.register(OptionalUser, OptionalUserAdmin)
|
||||||
admin.site.register(OptionalMachine, OptionalMachineAdmin)
|
admin.site.register(OptionalMachine, OptionalMachineAdmin)
|
||||||
admin.site.register(OptionalTopologie, OptionalTopologieAdmin)
|
admin.site.register(OptionalTopologie, OptionalTopologieAdmin)
|
||||||
|
|
|
@ -19,71 +19,116 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Formulaire d'edition des réglages : user, machine, topologie, asso...
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.forms import ModelForm, Form, ValidationError
|
from django.forms import ModelForm, Form
|
||||||
from django import forms
|
from django import forms
|
||||||
from .models import OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption, AssoOption, MailMessageOption, Service
|
from .models import OptionalUser, OptionalMachine, OptionalTopologie
|
||||||
from django.db.models import Q
|
from .models import GeneralOption, AssoOption, MailMessageOption, Service
|
||||||
|
|
||||||
|
|
||||||
class EditOptionalUserForm(ModelForm):
|
class EditOptionalUserForm(ModelForm):
|
||||||
|
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = OptionalUser
|
model = OptionalUser
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditOptionalUserForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditOptionalUserForm, self).__init__(
|
||||||
self.fields['is_tel_mandatory'].label = 'Exiger un numéro de téléphone'
|
*args,
|
||||||
self.fields['user_solde'].label = 'Activation du solde pour les utilisateurs'
|
prefix=prefix,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
self.fields['is_tel_mandatory'].label = 'Exiger un numéro de\
|
||||||
|
téléphone'
|
||||||
|
self.fields['user_solde'].label = 'Activation du solde pour\
|
||||||
|
les utilisateurs'
|
||||||
|
|
||||||
|
|
||||||
class EditOptionalMachineForm(ModelForm):
|
class EditOptionalMachineForm(ModelForm):
|
||||||
|
"""Options machines (max de machines, etc)"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = OptionalMachine
|
model = OptionalMachine
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditOptionalMachineForm, self).__init__(
|
||||||
self.fields['password_machine'].label = "Possibilité d'attribuer un mot de passe par interface"
|
*args,
|
||||||
self.fields['max_lambdauser_interfaces'].label = "Maximum d'interfaces autorisées pour un user normal"
|
prefix=prefix,
|
||||||
self.fields['max_lambdauser_aliases'].label = "Maximum d'alias dns autorisés pour un user normal"
|
**kwargs
|
||||||
|
)
|
||||||
|
self.fields['password_machine'].label = "Possibilité d'attribuer\
|
||||||
|
un mot de passe par interface"
|
||||||
|
self.fields['max_lambdauser_interfaces'].label = "Maximum\
|
||||||
|
d'interfaces autorisées pour un user normal"
|
||||||
|
self.fields['max_lambdauser_aliases'].label = "Maximum d'alias\
|
||||||
|
dns autorisés pour un user normal"
|
||||||
|
|
||||||
|
|
||||||
class EditOptionalTopologieForm(ModelForm):
|
class EditOptionalTopologieForm(ModelForm):
|
||||||
|
"""Options de topologie, formulaire d'edition (vlan par default etc)"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = OptionalTopologie
|
model = OptionalTopologie
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditOptionalTopologieForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditOptionalTopologieForm, self).__init__(
|
||||||
self.fields['vlan_decision_ok'].label = "Vlan où placer les machines après acceptation RADIUS"
|
*args,
|
||||||
self.fields['vlan_decision_nok'].label = "Vlan où placer les machines après rejet RADIUS"
|
prefix=prefix,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
self.fields['vlan_decision_ok'].label = "Vlan où placer les\
|
||||||
|
machines après acceptation RADIUS"
|
||||||
|
self.fields['vlan_decision_nok'].label = "Vlan où placer les\
|
||||||
|
machines après rejet RADIUS"
|
||||||
|
|
||||||
|
|
||||||
class EditGeneralOptionForm(ModelForm):
|
class EditGeneralOptionForm(ModelForm):
|
||||||
|
"""Options générales (affichages de résultats de recherche, etc)"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = GeneralOption
|
model = GeneralOption
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditGeneralOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditGeneralOptionForm, self).__init__(
|
||||||
self.fields['search_display_page'].label = 'Resultats affichés dans une recherche'
|
*args,
|
||||||
self.fields['pagination_number'].label = 'Items par page, taille normale (ex users)'
|
prefix=prefix,
|
||||||
self.fields['pagination_large_number'].label = 'Items par page, taille élevée (machines)'
|
**kwargs
|
||||||
self.fields['req_expire_hrs'].label = 'Temps avant expiration du lien de reinitialisation de mot de passe (en heures)'
|
)
|
||||||
|
self.fields['search_display_page'].label = 'Resultats\
|
||||||
|
affichés dans une recherche'
|
||||||
|
self.fields['pagination_number'].label = 'Items par page,\
|
||||||
|
taille normale (ex users)'
|
||||||
|
self.fields['pagination_large_number'].label = 'Items par page,\
|
||||||
|
taille élevée (machines)'
|
||||||
|
self.fields['req_expire_hrs'].label = 'Temps avant expiration du lien\
|
||||||
|
de reinitialisation de mot de passe (en heures)'
|
||||||
self.fields['site_name'].label = 'Nom du site web'
|
self.fields['site_name'].label = 'Nom du site web'
|
||||||
self.fields['email_from'].label = 'Adresse mail d\'expedition automatique'
|
self.fields['email_from'].label = "Adresse mail d\
|
||||||
|
'expedition automatique"
|
||||||
|
|
||||||
|
|
||||||
class EditAssoOptionForm(ModelForm):
|
class EditAssoOptionForm(ModelForm):
|
||||||
|
"""Options de l'asso (addresse, telephone, etc)"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AssoOption
|
model = AssoOption
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditAssoOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditAssoOptionForm, self).__init__(
|
||||||
|
*args,
|
||||||
|
prefix=prefix,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
self.fields['name'].label = 'Nom de l\'asso'
|
self.fields['name'].label = 'Nom de l\'asso'
|
||||||
self.fields['siret'].label = 'SIRET'
|
self.fields['siret'].label = 'SIRET'
|
||||||
self.fields['adresse1'].label = 'Adresse (ligne 1)'
|
self.fields['adresse1'].label = 'Adresse (ligne 1)'
|
||||||
|
@ -91,20 +136,31 @@ class EditAssoOptionForm(ModelForm):
|
||||||
self.fields['contact'].label = 'Email de contact'
|
self.fields['contact'].label = 'Email de contact'
|
||||||
self.fields['telephone'].label = 'Numéro de téléphone'
|
self.fields['telephone'].label = 'Numéro de téléphone'
|
||||||
self.fields['pseudo'].label = 'Pseudo d\'usage'
|
self.fields['pseudo'].label = 'Pseudo d\'usage'
|
||||||
self.fields['utilisateur_asso'].label = 'Compte utilisé pour faire les modifications depuis /admin'
|
self.fields['utilisateur_asso'].label = 'Compte utilisé pour\
|
||||||
|
faire les modifications depuis /admin'
|
||||||
|
|
||||||
|
|
||||||
class EditMailMessageOptionForm(ModelForm):
|
class EditMailMessageOptionForm(ModelForm):
|
||||||
|
"""Formulaire d'edition des messages de bienvenue personnalisés"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = MailMessageOption
|
model = MailMessageOption
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(EditMailMessageOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(EditMailMessageOptionForm, self).__init__(
|
||||||
self.fields['welcome_mail_fr'].label = 'Message dans le mail de bienvenue en français'
|
*args,
|
||||||
self.fields['welcome_mail_en'].label = 'Message dans le mail de bienvenue en anglais'
|
prefix=prefix,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
self.fields['welcome_mail_fr'].label = 'Message dans le\
|
||||||
|
mail de bienvenue en français'
|
||||||
|
self.fields['welcome_mail_en'].label = 'Message dans le\
|
||||||
|
mail de bienvenue en anglais'
|
||||||
|
|
||||||
|
|
||||||
class ServiceForm(ModelForm):
|
class ServiceForm(ModelForm):
|
||||||
|
"""Edition, ajout de services sur la page d'accueil"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Service
|
model = Service
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -113,6 +169,11 @@ class ServiceForm(ModelForm):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(ServiceForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
class DelServiceForm(Form):
|
|
||||||
services = forms.ModelMultipleChoiceField(queryset=Service.objects.all(), label="Enregistrements service actuels", widget=forms.CheckboxSelectMultiple)
|
|
||||||
|
|
||||||
|
class DelServiceForm(Form):
|
||||||
|
"""Suppression de services sur la page d'accueil"""
|
||||||
|
services = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Service.objects.all(),
|
||||||
|
label="Enregistrements service actuels",
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
|
@ -20,26 +20,38 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Reglages généraux, machines, utilisateurs, mail, general pour l'application.
|
||||||
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from cotisations.models import Paiement
|
from cotisations.models import Paiement
|
||||||
from machines.models import Vlan
|
|
||||||
|
|
||||||
class OptionalUser(models.Model):
|
class OptionalUser(models.Model):
|
||||||
|
"""Options pour l'user : obligation ou nom du telephone,
|
||||||
|
activation ou non du solde, autorisation du negatif, fingerprint etc"""
|
||||||
PRETTY_NAME = "Options utilisateur"
|
PRETTY_NAME = "Options utilisateur"
|
||||||
|
|
||||||
is_tel_mandatory = models.BooleanField(default=True)
|
is_tel_mandatory = models.BooleanField(default=True)
|
||||||
user_solde = models.BooleanField(default=False)
|
user_solde = models.BooleanField(default=False)
|
||||||
solde_negatif = models.DecimalField(max_digits=5, decimal_places=2, default=0)
|
solde_negatif = models.DecimalField(
|
||||||
|
max_digits=5,
|
||||||
|
decimal_places=2,
|
||||||
|
default=0
|
||||||
|
)
|
||||||
gpg_fingerprint = models.BooleanField(default=True)
|
gpg_fingerprint = models.BooleanField(default=True)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
"""Creation du mode de paiement par solde"""
|
||||||
if self.user_solde:
|
if self.user_solde:
|
||||||
Paiement.objects.get_or_create(moyen="Solde")
|
Paiement.objects.get_or_create(moyen="Solde")
|
||||||
|
|
||||||
|
|
||||||
class OptionalMachine(models.Model):
|
class OptionalMachine(models.Model):
|
||||||
|
"""Options pour les machines : maximum de machines ou d'alias par user
|
||||||
|
sans droit, activation de l'ipv6"""
|
||||||
PRETTY_NAME = "Options machines"
|
PRETTY_NAME = "Options machines"
|
||||||
|
|
||||||
password_machine = models.BooleanField(default=False)
|
password_machine = models.BooleanField(default=False)
|
||||||
|
@ -47,21 +59,43 @@ class OptionalMachine(models.Model):
|
||||||
max_lambdauser_aliases = models.IntegerField(default=10)
|
max_lambdauser_aliases = models.IntegerField(default=10)
|
||||||
ipv6 = models.BooleanField(default=False)
|
ipv6 = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
|
||||||
class OptionalTopologie(models.Model):
|
class OptionalTopologie(models.Model):
|
||||||
|
"""Reglages pour la topologie : mode d'accès radius, vlan où placer
|
||||||
|
les machines en accept ou reject"""
|
||||||
PRETTY_NAME = "Options topologie"
|
PRETTY_NAME = "Options topologie"
|
||||||
MACHINE = 'MACHINE'
|
MACHINE = 'MACHINE'
|
||||||
DEFINED = 'DEFINED'
|
DEFINED = 'DEFINED'
|
||||||
CHOICE_RADIUS = (
|
CHOICE_RADIUS = (
|
||||||
(MACHINE, 'Sur le vlan de la plage ip machine'),
|
(MACHINE, 'Sur le vlan de la plage ip machine'),
|
||||||
(DEFINED, 'Prédéfini dans "Vlan où placer les machines après acceptation RADIUS"'),
|
(DEFINED, 'Prédéfini dans "Vlan où placer les machines\
|
||||||
|
après acceptation RADIUS"'),
|
||||||
|
)
|
||||||
|
|
||||||
|
radius_general_policy = models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
choices=CHOICE_RADIUS,
|
||||||
|
default='DEFINED'
|
||||||
|
)
|
||||||
|
vlan_decision_ok = models.OneToOneField(
|
||||||
|
'machines.Vlan',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name='decision_ok',
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
vlan_decision_nok = models.OneToOneField(
|
||||||
|
'machines.Vlan',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name='decision_nok',
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
radius_general_policy = models.CharField(max_length=32, choices=CHOICE_RADIUS, default='DEFINED')
|
|
||||||
vlan_decision_ok = models.OneToOneField('machines.Vlan', on_delete=models.PROTECT, related_name='decision_ok', blank=True, null=True)
|
|
||||||
vlan_decision_nok = models.OneToOneField('machines.Vlan', on_delete=models.PROTECT, related_name='decision_nok', blank=True, null=True)
|
|
||||||
|
|
||||||
class GeneralOption(models.Model):
|
class GeneralOption(models.Model):
|
||||||
|
"""Options générales : nombre de resultats par page, nom du site,
|
||||||
|
temps où les liens sont valides"""
|
||||||
PRETTY_NAME = "Options générales"
|
PRETTY_NAME = "Options générales"
|
||||||
|
|
||||||
search_display_page = models.IntegerField(default=15)
|
search_display_page = models.IntegerField(default=15)
|
||||||
|
@ -71,7 +105,10 @@ class GeneralOption(models.Model):
|
||||||
site_name = models.CharField(max_length=32, default="Re2o")
|
site_name = models.CharField(max_length=32, default="Re2o")
|
||||||
email_from = models.EmailField(default="www-data@serveur.net")
|
email_from = models.EmailField(default="www-data@serveur.net")
|
||||||
|
|
||||||
|
|
||||||
class Service(models.Model):
|
class Service(models.Model):
|
||||||
|
"""Liste des services affichés sur la page d'accueil : url, description,
|
||||||
|
image et nom"""
|
||||||
name = models.CharField(max_length=32)
|
name = models.CharField(max_length=32)
|
||||||
url = models.URLField()
|
url = models.URLField()
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
|
@ -80,21 +117,32 @@ class Service(models.Model):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.name)
|
return str(self.name)
|
||||||
|
|
||||||
|
|
||||||
class AssoOption(models.Model):
|
class AssoOption(models.Model):
|
||||||
|
"""Options générales de l'asso : siret, addresse, nom, etc"""
|
||||||
PRETTY_NAME = "Options de l'association"
|
PRETTY_NAME = "Options de l'association"
|
||||||
|
|
||||||
name = models.CharField(default="Association réseau école machin", max_length=256)
|
name = models.CharField(
|
||||||
|
default="Association réseau école machin",
|
||||||
|
max_length=256
|
||||||
|
)
|
||||||
siret = models.CharField(default="00000000000000", max_length=32)
|
siret = models.CharField(default="00000000000000", max_length=32)
|
||||||
adresse1 = models.CharField(default="1 Rue de exemple", max_length=128)
|
adresse1 = models.CharField(default="1 Rue de exemple", max_length=128)
|
||||||
adresse2 = models.CharField(default="94230 Cachan", max_length=128)
|
adresse2 = models.CharField(default="94230 Cachan", max_length=128)
|
||||||
contact = models.EmailField(default="contact@example.org")
|
contact = models.EmailField(default="contact@example.org")
|
||||||
telephone = models.CharField(max_length=15, default="0000000000")
|
telephone = models.CharField(max_length=15, default="0000000000")
|
||||||
pseudo = models.CharField(default="Asso", max_length=32)
|
pseudo = models.CharField(default="Asso", max_length=32)
|
||||||
utilisateur_asso = models.OneToOneField('users.User', on_delete=models.PROTECT, blank=True, null=True)
|
utilisateur_asso = models.OneToOneField(
|
||||||
|
'users.User',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MailMessageOption(models.Model):
|
class MailMessageOption(models.Model):
|
||||||
|
"""Reglages, mail de bienvenue et autre"""
|
||||||
PRETTY_NAME = "Options de corps de mail"
|
PRETTY_NAME = "Options de corps de mail"
|
||||||
|
|
||||||
welcome_mail_fr = models.TextField(default="")
|
welcome_mail_fr = models.TextField(default="")
|
||||||
welcome_mail_en = models.TextField(default="")
|
welcome_mail_en = models.TextField(default="")
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Urls de l'application preferences, pointant vers les fonctions de views
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
@ -28,15 +31,47 @@ from . import views
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^edit_options/(?P<section>OptionalUser)$', views.edit_options, name='edit-options'),
|
url(
|
||||||
url(r'^edit_options/(?P<section>OptionalMachine)$', views.edit_options, name='edit-options'),
|
r'^edit_options/(?P<section>OptionalUser)$',
|
||||||
url(r'^edit_options/(?P<section>OptionalTopologie)$', views.edit_options, name='edit-options'),
|
views.edit_options,
|
||||||
url(r'^edit_options/(?P<section>GeneralOption)$', views.edit_options, name='edit-options'),
|
name='edit-options'
|
||||||
url(r'^edit_options/(?P<section>AssoOption)$', views.edit_options, name='edit-options'),
|
),
|
||||||
url(r'^edit_options/(?P<section>MailMessageOption)$', views.edit_options, name='edit-options'),
|
url(
|
||||||
|
r'^edit_options/(?P<section>OptionalMachine)$',
|
||||||
|
views.edit_options,
|
||||||
|
name='edit-options'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^edit_options/(?P<section>OptionalTopologie)$',
|
||||||
|
views.edit_options,
|
||||||
|
name='edit-options'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^edit_options/(?P<section>GeneralOption)$',
|
||||||
|
views.edit_options,
|
||||||
|
name='edit-options'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^edit_options/(?P<section>AssoOption)$',
|
||||||
|
views.edit_options,
|
||||||
|
name='edit-options'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^edit_options/(?P<section>MailMessageOption)$',
|
||||||
|
views.edit_options,
|
||||||
|
name='edit-options'
|
||||||
|
),
|
||||||
url(r'^add_services/$', views.add_services, name='add-services'),
|
url(r'^add_services/$', views.add_services, name='add-services'),
|
||||||
url(r'^edit_services/(?P<servicesid>[0-9]+)$', views.edit_services, name='edit-services'),
|
url(
|
||||||
|
r'^edit_services/(?P<servicesid>[0-9]+)$',
|
||||||
|
views.edit_services,
|
||||||
|
name='edit-services'
|
||||||
|
),
|
||||||
url(r'^del_services/$', views.del_services, name='del-services'),
|
url(r'^del_services/$', views.del_services, name='del-services'),
|
||||||
url(r'^history/(?P<object>service)/(?P<id>[0-9]+)$', views.history, name='history'),
|
url(
|
||||||
|
r'^history/(?P<object>service)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
url(r'^$', views.display_options, name='display-options'),
|
url(r'^$', views.display_options, name='display-options'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -23,48 +23,53 @@
|
||||||
# App de gestion des machines pour re2o
|
# App de gestion des machines pour re2o
|
||||||
# Gabriel Détraz, Augustin Lemesle
|
# Gabriel Détraz, Augustin Lemesle
|
||||||
# Gplv2
|
# Gplv2
|
||||||
|
"""
|
||||||
|
Vue d'affichage, et de modification des réglages (réglages machine,
|
||||||
|
topologie, users, service...)
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render, redirect
|
||||||
from django.shortcuts import get_object_or_404, render, redirect
|
|
||||||
from django.template.context_processors import csrf
|
|
||||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||||
from django.template import Context, RequestContext, loader
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.db.models import Max, ProtectedError
|
from django.db.models import ProtectedError
|
||||||
from django.db import IntegrityError
|
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.utils import timezone
|
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from reversion.models import Version
|
from reversion.models import Version
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
|
from re2o.views import form
|
||||||
from .forms import ServiceForm, DelServiceForm
|
from .forms import ServiceForm, DelServiceForm
|
||||||
from .models import Service, OptionalUser, OptionalMachine, AssoOption, MailMessageOption, GeneralOption, OptionalTopologie
|
from .models import Service, OptionalUser, OptionalMachine, AssoOption
|
||||||
|
from .models import MailMessageOption, GeneralOption, OptionalTopologie
|
||||||
from . import models
|
from . import models
|
||||||
from . import forms
|
from . import forms
|
||||||
|
|
||||||
def form(ctx, template, request):
|
|
||||||
c = ctx
|
|
||||||
c.update(csrf(request))
|
|
||||||
return render(request, template, c)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def display_options(request):
|
def display_options(request):
|
||||||
useroptions, created = OptionalUser.objects.get_or_create()
|
"""Vue pour affichage des options (en vrac) classé selon les models
|
||||||
machineoptions, created = OptionalMachine.objects.get_or_create()
|
correspondants dans un tableau"""
|
||||||
topologieoptions, created = OptionalTopologie.objects.get_or_create()
|
useroptions, _created = OptionalUser.objects.get_or_create()
|
||||||
generaloptions, created = GeneralOption.objects.get_or_create()
|
machineoptions, _created = OptionalMachine.objects.get_or_create()
|
||||||
assooptions, created = AssoOption.objects.get_or_create()
|
topologieoptions, _created = OptionalTopologie.objects.get_or_create()
|
||||||
mailmessageoptions, created = MailMessageOption.objects.get_or_create()
|
generaloptions, _created = GeneralOption.objects.get_or_create()
|
||||||
|
assooptions, _created = AssoOption.objects.get_or_create()
|
||||||
|
mailmessageoptions, _created = MailMessageOption.objects.get_or_create()
|
||||||
service_list = Service.objects.all()
|
service_list = Service.objects.all()
|
||||||
return form({'useroptions': useroptions, 'machineoptions': machineoptions, 'topologieoptions': topologieoptions, 'generaloptions': generaloptions, 'assooptions' : assooptions, 'mailmessageoptions' : mailmessageoptions, 'service_list':service_list}, 'preferences/display_preferences.html', request)
|
return form({
|
||||||
|
'useroptions': useroptions,
|
||||||
|
'machineoptions': machineoptions,
|
||||||
|
'topologieoptions': topologieoptions,
|
||||||
|
'generaloptions': generaloptions,
|
||||||
|
'assooptions': assooptions,
|
||||||
|
'mailmessageoptions': mailmessageoptions,
|
||||||
|
'service_list': service_list
|
||||||
|
}, 'preferences/display_preferences.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('admin')
|
@permission_required('admin')
|
||||||
|
@ -73,23 +78,36 @@ def edit_options(request, section):
|
||||||
model = getattr(models, section, None)
|
model = getattr(models, section, None)
|
||||||
form_instance = getattr(forms, 'Edit' + section + 'Form', None)
|
form_instance = getattr(forms, 'Edit' + section + 'Form', None)
|
||||||
if model and form:
|
if model and form:
|
||||||
options_instance, created = model.objects.get_or_create()
|
options_instance, _created = model.objects.get_or_create()
|
||||||
options = form_instance(request.POST or None, instance=options_instance)
|
options = form_instance(
|
||||||
|
request.POST or None,
|
||||||
|
instance=options_instance
|
||||||
|
)
|
||||||
if options.is_valid():
|
if options.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
options.save()
|
options.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in options.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in options.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
messages.success(request, "Préférences modifiées")
|
messages.success(request, "Préférences modifiées")
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
return form({'options': options}, 'preferences/edit_preferences.html', request)
|
return form(
|
||||||
|
{'options': options},
|
||||||
|
'preferences/edit_preferences.html',
|
||||||
|
request
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Objet inconnu")
|
messages.error(request, "Objet inconnu")
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('admin')
|
@permission_required('admin')
|
||||||
def add_services(request):
|
def add_services(request):
|
||||||
|
"""Ajout d'un service de la page d'accueil"""
|
||||||
services = ServiceForm(request.POST or None)
|
services = ServiceForm(request.POST or None)
|
||||||
if services.is_valid():
|
if services.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -98,29 +116,45 @@ def add_services(request):
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
messages.success(request, "Cet enregistrement ns a été ajouté")
|
messages.success(request, "Cet enregistrement ns a été ajouté")
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
return form({'preferenceform': services}, 'preferences/preferences.html', request)
|
return form(
|
||||||
|
{'preferenceform': services},
|
||||||
|
'preferences/preferences.html',
|
||||||
|
request
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('admin')
|
@permission_required('admin')
|
||||||
def edit_services(request, servicesid):
|
def edit_services(request, servicesid):
|
||||||
|
"""Edition des services affichés sur la page d'accueil"""
|
||||||
try:
|
try:
|
||||||
services_instance = Service.objects.get(pk=servicesid)
|
services_instance = Service.objects.get(pk=servicesid)
|
||||||
except Service.DoesNotExist:
|
except Service.DoesNotExist:
|
||||||
messages.error(request, u"Entrée inexistante" )
|
messages.error(request, u"Entrée inexistante")
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
services = ServiceForm(request.POST or None, instance=services_instance)
|
services = ServiceForm(request.POST or None, instance=services_instance)
|
||||||
if services.is_valid():
|
if services.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
services.save()
|
services.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in services.changed_data))
|
reversion.set_comment(
|
||||||
|
"Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in services.changed_data
|
||||||
|
)
|
||||||
|
)
|
||||||
messages.success(request, "Service modifié")
|
messages.success(request, "Service modifié")
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
return form({'preferenceform': services}, 'preferences/preferences.html', request)
|
return form(
|
||||||
|
{'preferenceform': services},
|
||||||
|
'preferences/preferences.html',
|
||||||
|
request
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('admin')
|
@permission_required('admin')
|
||||||
def del_services(request):
|
def del_services(request):
|
||||||
|
"""Suppression d'un service de la page d'accueil"""
|
||||||
services = DelServiceForm(request.POST or None)
|
services = DelServiceForm(request.POST or None)
|
||||||
if services.is_valid():
|
if services.is_valid():
|
||||||
services_dels = services.cleaned_data['services']
|
services_dels = services.cleaned_data['services']
|
||||||
|
@ -131,20 +165,28 @@ def del_services(request):
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
messages.success(request, "Le services a été supprimée")
|
messages.success(request, "Le services a été supprimée")
|
||||||
except ProtectedError:
|
except ProtectedError:
|
||||||
messages.error(request, "Erreur le service suivant %s ne peut être supprimé" % services_del)
|
messages.error(request, "Erreur le service\
|
||||||
|
suivant %s ne peut être supprimé" % services_del)
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
return form({'preferenceform': services}, 'preferences/preferences.html', request)
|
return form(
|
||||||
|
{'preferenceform': services},
|
||||||
|
'preferences/preferences.html',
|
||||||
|
request
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def history(request, object, id):
|
def history(request, object_name, object_id):
|
||||||
if object == 'service':
|
"""Historique de creation et de modification d'un service affiché sur
|
||||||
|
la page d'accueil"""
|
||||||
|
if object_name == 'service':
|
||||||
try:
|
try:
|
||||||
object_instance = Service.objects.get(pk=id)
|
object_instance = Service.objects.get(pk=object_id)
|
||||||
except Service.DoesNotExist:
|
except Service.DoesNotExist:
|
||||||
messages.error(request, "Service inexistant")
|
messages.error(request, "Service inexistant")
|
||||||
return redirect("/preferences/")
|
return redirect("/preferences/")
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
reversions = Version.objects.get_for_object(object_instance)
|
reversions = Version.objects.get_for_object(object_instance)
|
||||||
paginator = Paginator(reversions, pagination_number)
|
paginator = Paginator(reversions, pagination_number)
|
||||||
|
@ -157,4 +199,7 @@ def history(request, object, id):
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
reversions = paginator.page(paginator.num_pages)
|
reversions = paginator.page(paginator.num_pages)
|
||||||
return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance})
|
return render(request, 're2o/history.html', {
|
||||||
|
'reversions': reversions,
|
||||||
|
'object': object_instance
|
||||||
|
})
|
||||||
|
|
|
@ -19,15 +19,19 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""Fonction de context, variables renvoyées à toutes les vues"""
|
||||||
|
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from machines.models import Interface, Machine
|
|
||||||
from preferences.models import GeneralOption, OptionalMachine
|
from preferences.models import GeneralOption, OptionalMachine
|
||||||
|
|
||||||
|
|
||||||
def context_user(request):
|
def context_user(request):
|
||||||
general_options, created = GeneralOption.objects.get_or_create()
|
"""Fonction de context lorsqu'un user est logué (ou non),
|
||||||
machine_options, created = OptionalMachine.objects.get_or_create()
|
renvoie les infos sur l'user, la liste de ses droits, ses machines"""
|
||||||
|
general_options, _created = GeneralOption.objects.get_or_create()
|
||||||
|
machine_options, _created = OptionalMachine.objects.get_or_create()
|
||||||
user = request.user
|
user = request.user
|
||||||
if user.is_authenticated():
|
if user.is_authenticated():
|
||||||
interfaces = user.user_interfaces()
|
interfaces = user.user_interfaces()
|
||||||
|
@ -52,8 +56,8 @@ def context_user(request):
|
||||||
'is_bofh': is_bofh,
|
'is_bofh': is_bofh,
|
||||||
'is_trez': is_trez,
|
'is_trez': is_trez,
|
||||||
'is_infra': is_infra,
|
'is_infra': is_infra,
|
||||||
'is_admin' : is_admin,
|
'is_admin': is_admin,
|
||||||
'interfaces': interfaces,
|
'interfaces': interfaces,
|
||||||
'site_name': general_options.site_name,
|
'site_name': general_options.site_name,
|
||||||
'ipv6_enabled' : machine_options.ipv6,
|
'ipv6_enabled': machine_options.ipv6,
|
||||||
}
|
}
|
||||||
|
|
10
re2o/urls.py
10
re2o/urls.py
|
@ -49,10 +49,16 @@ urlpatterns = [
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
url(r'^users/', include('users.urls', namespace='users')),
|
url(r'^users/', include('users.urls', namespace='users')),
|
||||||
url(r'^search/', include('search.urls', namespace='search')),
|
url(r'^search/', include('search.urls', namespace='search')),
|
||||||
url(r'^cotisations/', include('cotisations.urls', namespace='cotisations')),
|
url(
|
||||||
|
r'^cotisations/',
|
||||||
|
include('cotisations.urls', namespace='cotisations')
|
||||||
|
),
|
||||||
url(r'^machines/', include('machines.urls', namespace='machines')),
|
url(r'^machines/', include('machines.urls', namespace='machines')),
|
||||||
url(r'^topologie/', include('topologie.urls', namespace='topologie')),
|
url(r'^topologie/', include('topologie.urls', namespace='topologie')),
|
||||||
url(r'^logs/', include('logs.urls', namespace='logs')),
|
url(r'^logs/', include('logs.urls', namespace='logs')),
|
||||||
url(r'^preferences/', include('preferences.urls', namespace='preferences')),
|
url(
|
||||||
|
r'^preferences/',
|
||||||
|
include('preferences.urls', namespace='preferences')
|
||||||
|
),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
136
re2o/utils.py
Normal file
136
re2o/utils.py
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
# -*- mode: python; coding: utf-8 -*-
|
||||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
|
||||||
|
# se veut agnostique au réseau considéré, de manière à être installable en
|
||||||
|
# quelques clics.
|
||||||
|
#
|
||||||
|
# Copyright © 2017 Gabriel Détraz
|
||||||
|
# Copyright © 2017 Goulven Kermarec
|
||||||
|
# Copyright © 2017 Augustin Lemesle
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# David Sinquin, Gabriel Détraz, Goulven Kermarec
|
||||||
|
"""
|
||||||
|
Regroupe les fonctions transversales utiles
|
||||||
|
|
||||||
|
Fonction :
|
||||||
|
- récupérer tous les utilisateurs actifs
|
||||||
|
- récupérer toutes les machines
|
||||||
|
- récupérer tous les bans
|
||||||
|
etc
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from cotisations.models import Cotisation, Facture, Paiement, Vente
|
||||||
|
from machines.models import Domain, Interface, Machine
|
||||||
|
from users.models import User, Ban, Whitelist
|
||||||
|
from preferences.models import Service
|
||||||
|
|
||||||
|
DT_NOW = timezone.now()
|
||||||
|
|
||||||
|
|
||||||
|
def all_adherent(search_time=DT_NOW):
|
||||||
|
""" Fonction renvoyant tous les users adherents. Optimisee pour n'est
|
||||||
|
qu'une seule requete sql
|
||||||
|
Inspecte les factures de l'user et ses cotisation, regarde si elles
|
||||||
|
sont posterieur à now (end_time)"""
|
||||||
|
return User.objects.filter(
|
||||||
|
facture__in=Facture.objects.filter(
|
||||||
|
vente__in=Vente.objects.filter(
|
||||||
|
cotisation__in=Cotisation.objects.filter(
|
||||||
|
vente__in=Vente.objects.filter(
|
||||||
|
facture__in=Facture.objects.all().exclude(valid=False)
|
||||||
|
)
|
||||||
|
).filter(date_end__gt=search_time)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
|
||||||
|
def all_baned(search_time=DT_NOW):
|
||||||
|
""" Fonction renvoyant tous les users bannis """
|
||||||
|
return User.objects.filter(
|
||||||
|
ban__in=Ban.objects.filter(
|
||||||
|
date_end__gt=search_time
|
||||||
|
)
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
|
||||||
|
def all_whitelisted(search_time=DT_NOW):
|
||||||
|
""" Fonction renvoyant tous les users whitelistes """
|
||||||
|
return User.objects.filter(
|
||||||
|
whitelist__in=Whitelist.objects.filter(
|
||||||
|
date_end__gt=search_time
|
||||||
|
)
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
|
||||||
|
def all_has_access(search_time=DT_NOW):
|
||||||
|
""" Renvoie tous les users beneficiant d'une connexion
|
||||||
|
: user adherent ou whiteliste et non banni """
|
||||||
|
return User.objects.filter(
|
||||||
|
Q(state=User.STATE_ACTIVE) &
|
||||||
|
~Q(ban__in=Ban.objects.filter(date_end__gt=search_time)) &
|
||||||
|
(Q(whitelist__in=Whitelist.objects.filter(date_end__gt=search_time)) |
|
||||||
|
Q(facture__in=Facture.objects.filter(
|
||||||
|
vente__in=Vente.objects.filter(
|
||||||
|
cotisation__in=Cotisation.objects.filter(
|
||||||
|
vente__in=Vente.objects.filter(
|
||||||
|
facture__in=Facture.objects.all()
|
||||||
|
.exclude(valid=False)
|
||||||
|
)
|
||||||
|
).filter(date_end__gt=search_time)
|
||||||
|
)
|
||||||
|
)))
|
||||||
|
).distinct()
|
||||||
|
|
||||||
|
|
||||||
|
def all_active_interfaces():
|
||||||
|
"""Renvoie l'ensemble des machines autorisées à sortir sur internet """
|
||||||
|
return Interface.objects.filter(
|
||||||
|
machine__in=Machine.objects.filter(
|
||||||
|
user__in=all_has_access()
|
||||||
|
).filter(active=True)
|
||||||
|
).select_related('domain').select_related('machine')\
|
||||||
|
.select_related('type').select_related('ipv4')\
|
||||||
|
.select_related('domain__extension').select_related('ipv4__ip_type')\
|
||||||
|
.distinct()
|
||||||
|
|
||||||
|
|
||||||
|
def all_active_assigned_interfaces():
|
||||||
|
""" Renvoie l'ensemble des machines qui ont une ipv4 assignées et
|
||||||
|
disposant de l'accès internet"""
|
||||||
|
return all_active_interfaces().filter(ipv4__isnull=False)
|
||||||
|
|
||||||
|
|
||||||
|
def all_active_interfaces_count():
|
||||||
|
""" Version light seulement pour compter"""
|
||||||
|
return Interface.objects.filter(
|
||||||
|
machine__in=Machine.objects.filter(
|
||||||
|
user__in=all_has_access()
|
||||||
|
).filter(active=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def all_active_assigned_interfaces_count():
|
||||||
|
""" Version light seulement pour compter"""
|
||||||
|
return all_active_interfaces_count().filter(ipv4__isnull=False)
|
|
@ -19,25 +19,28 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Fonctions de la page d'accueil et diverses fonctions utiles pour tous
|
||||||
|
les views
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from django.template.context_processors import csrf
|
from django.template.context_processors import csrf
|
||||||
from django.template import Context, RequestContext, loader
|
|
||||||
from preferences.models import Service
|
from preferences.models import Service
|
||||||
|
|
||||||
|
|
||||||
def form(ctx, template, request):
|
def form(ctx, template, request):
|
||||||
|
"""Form générique, raccourci importé par les fonctions views du site"""
|
||||||
context = ctx
|
context = ctx
|
||||||
context.update(csrf(request))
|
context.update(csrf(request))
|
||||||
return render(request, template, context)
|
return render(request, template, context)
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
i = 0
|
"""Affiche la liste des services sur la page d'accueil de re2o"""
|
||||||
services = [[], [], []]
|
services = [[], [], []]
|
||||||
for indice, serv in enumerate(Service.objects.all()):
|
for indice, serv in enumerate(Service.objects.all()):
|
||||||
services[indice % 3].append(serv)
|
services[indice % 3].append(serv)
|
||||||
|
|
||||||
return form({'services_urls': services}, 're2o/index.html', request)
|
return form({'services_urls': services}, 're2o/index.html', request)
|
||||||
|
|
|
@ -32,9 +32,10 @@ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from django.core.wsgi import get_wsgi_application
|
|
||||||
from os.path import dirname
|
|
||||||
import sys
|
import sys
|
||||||
|
from os.path import dirname
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
|
||||||
sys.path.append(dirname(dirname(__file__)))
|
sys.path.append(dirname(dirname(__file__)))
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
|
||||||
|
|
|
@ -381,8 +381,20 @@ def new_switch(request):
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
messages.success(request, "Le switch a été créé")
|
messages.success(request, "Le switch a été créé")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
|
<<<<<<< HEAD
|
||||||
i_bft_param = generate_ipv4_mbf_param( interface, False )
|
i_bft_param = generate_ipv4_mbf_param( interface, False )
|
||||||
return form({'topoform':switch, 'machineform': machine, 'interfaceform': interface, 'domainform': domain, 'i_bft_param': i_bft_param}, 'topologie/switch.html', request)
|
return form({'topoform':switch, 'machineform': machine, 'interfaceform': interface, 'domainform': domain, 'i_bft_param': i_bft_param}, 'topologie/switch.html', request)
|
||||||
|
=======
|
||||||
|
i_bft_param = generate_ipv4_bft_param(interface, False)
|
||||||
|
return form({
|
||||||
|
'topoform': switch,
|
||||||
|
'machineform': machine,
|
||||||
|
'interfaceform': interface,
|
||||||
|
'domainform': domain,
|
||||||
|
'i_bft_param': i_bft_param
|
||||||
|
}, 'topologie/switch.html', request)
|
||||||
|
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
|
@ -442,8 +454,20 @@ def edit_switch(request, switch_id):
|
||||||
)
|
)
|
||||||
messages.success(request, "Le switch a bien été modifié")
|
messages.success(request, "Le switch a bien été modifié")
|
||||||
return redirect("/topologie/")
|
return redirect("/topologie/")
|
||||||
|
<<<<<<< HEAD
|
||||||
i_bft_param = generate_ipv4_mbf_param( interface_form, False )
|
i_bft_param = generate_ipv4_mbf_param( interface_form, False )
|
||||||
return form({'topoform':switch_form, 'machineform': machine_form, 'interfaceform': interface_form, 'domainform': domain_form, 'i_bft_param': i_bft_param}, 'topologie/switch.html', request)
|
return form({'topoform':switch_form, 'machineform': machine_form, 'interfaceform': interface_form, 'domainform': domain_form, 'i_bft_param': i_bft_param}, 'topologie/switch.html', request)
|
||||||
|
=======
|
||||||
|
i_bft_param = generate_ipv4_bft_param(interface_form, False)
|
||||||
|
return form({
|
||||||
|
'topoform': switch_form,
|
||||||
|
'machineform': machine_form,
|
||||||
|
'interfaceform': interface_form,
|
||||||
|
'domainform': domain_form,
|
||||||
|
'i_bft_param': i_bft_param
|
||||||
|
}, 'topologie/switch.html', request)
|
||||||
|
|
||||||
|
>>>>>>> master
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
|
|
101
users/admin.py
101
users/admin.py
|
@ -20,6 +20,10 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Definition des vues pour les admin. Classique, sauf pour users,
|
||||||
|
où on fait appel à UserChange et ServiceUserChange, forms custom
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
@ -28,11 +32,15 @@ from django.contrib.auth.models import Group
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
from reversion.admin import VersionAdmin
|
from reversion.admin import VersionAdmin
|
||||||
|
|
||||||
from .models import User, ServiceUser, School, Right, ListRight, ListShell, Ban, Whitelist, Request, LdapUser, LdapServiceUser, LdapServiceUserGroup, LdapUserGroup
|
from .models import User, ServiceUser, School, Right, ListRight, ListShell
|
||||||
from .forms import UserChangeForm, UserCreationForm, ServiceUserChangeForm, ServiceUserCreationForm
|
from .models import Ban, Whitelist, Request, LdapUser, LdapServiceUser
|
||||||
|
from .models import LdapServiceUserGroup, LdapUserGroup
|
||||||
|
from .forms import UserChangeForm, UserCreationForm
|
||||||
|
from .forms import ServiceUserChangeForm, ServiceUserCreationForm
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(admin.ModelAdmin):
|
class UserAdmin(admin.ModelAdmin):
|
||||||
|
"""Administration d'un user"""
|
||||||
list_display = (
|
list_display = (
|
||||||
'name',
|
'name',
|
||||||
'surname',
|
'surname',
|
||||||
|
@ -43,51 +51,73 @@ class UserAdmin(admin.ModelAdmin):
|
||||||
'shell',
|
'shell',
|
||||||
'state'
|
'state'
|
||||||
)
|
)
|
||||||
search_fields = ('name','surname','pseudo','room')
|
search_fields = ('name', 'surname', 'pseudo', 'room')
|
||||||
|
|
||||||
|
|
||||||
class LdapUserAdmin(admin.ModelAdmin):
|
class LdapUserAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name','uidNumber','login_shell')
|
"""Administration du ldapuser"""
|
||||||
exclude = ('user_password','sambat_nt_password')
|
list_display = ('name', 'uidNumber', 'login_shell')
|
||||||
|
exclude = ('user_password', 'sambat_nt_password')
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class LdapServiceUserAdmin(admin.ModelAdmin):
|
class LdapServiceUserAdmin(admin.ModelAdmin):
|
||||||
|
"""Administration du ldapserviceuser"""
|
||||||
list_display = ('name',)
|
list_display = ('name',)
|
||||||
exclude = ('user_password',)
|
exclude = ('user_password',)
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class LdapUserGroupAdmin(admin.ModelAdmin):
|
class LdapUserGroupAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name','members','gid')
|
"""Administration du ldapusergroupe"""
|
||||||
|
list_display = ('name', 'members', 'gid')
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class LdapServiceUserGroupAdmin(admin.ModelAdmin):
|
class LdapServiceUserGroupAdmin(admin.ModelAdmin):
|
||||||
|
"""Administration du ldap serviceusergroup"""
|
||||||
list_display = ('name',)
|
list_display = ('name',)
|
||||||
search_fields = ('name',)
|
search_fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class SchoolAdmin(VersionAdmin):
|
class SchoolAdmin(VersionAdmin):
|
||||||
list_display = ('name',)
|
"""Administration, gestion des écoles"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ListRightAdmin(VersionAdmin):
|
class ListRightAdmin(VersionAdmin):
|
||||||
|
"""Gestion de la liste des droits existants
|
||||||
|
Ne permet pas l'edition du gid (primarykey pour ldap)"""
|
||||||
list_display = ('listright',)
|
list_display = ('listright',)
|
||||||
|
|
||||||
|
|
||||||
class ListShellAdmin(VersionAdmin):
|
class ListShellAdmin(VersionAdmin):
|
||||||
list_display = ('shell',)
|
"""Gestion de la liste des shells coté admin"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RightAdmin(VersionAdmin):
|
class RightAdmin(VersionAdmin):
|
||||||
list_display = ('user', 'right')
|
"""Gestion de la liste des droits affectés"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class RequestAdmin(admin.ModelAdmin):
|
class RequestAdmin(admin.ModelAdmin):
|
||||||
|
"""Gestion des request objet, ticket pour lien de reinit mot de passe"""
|
||||||
list_display = ('user', 'type', 'created_at', 'expires_at')
|
list_display = ('user', 'type', 'created_at', 'expires_at')
|
||||||
|
|
||||||
|
|
||||||
class BanAdmin(VersionAdmin):
|
class BanAdmin(VersionAdmin):
|
||||||
list_display = ('user', 'raison', 'date_start', 'date_end')
|
"""Gestion des bannissements"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class WhitelistAdmin(VersionAdmin):
|
class WhitelistAdmin(VersionAdmin):
|
||||||
list_display = ('user', 'raison', 'date_start', 'date_end')
|
"""Gestion des whitelist"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(VersionAdmin, BaseUserAdmin):
|
class UserAdmin(VersionAdmin, BaseUserAdmin):
|
||||||
|
"""Gestion d'un user : modification des champs perso, mot de passe, etc"""
|
||||||
# The forms to add and change user instances
|
# The forms to add and change user instances
|
||||||
form = UserChangeForm
|
form = UserChangeForm
|
||||||
add_form = UserCreationForm
|
add_form = UserCreationForm
|
||||||
|
@ -95,27 +125,56 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
|
||||||
# The fields to be used in displaying the User model.
|
# The fields to be used in displaying the User model.
|
||||||
# These override the definitions on the base UserAdmin
|
# These override the definitions on the base UserAdmin
|
||||||
# that reference specific fields on auth.User.
|
# that reference specific fields on auth.User.
|
||||||
list_display = ('pseudo', 'name', 'surname', 'email', 'school', 'is_admin', 'shell')
|
list_display = (
|
||||||
|
'pseudo',
|
||||||
|
'name',
|
||||||
|
'surname',
|
||||||
|
'email',
|
||||||
|
'school',
|
||||||
|
'is_admin',
|
||||||
|
'shell'
|
||||||
|
)
|
||||||
list_display = ('pseudo',)
|
list_display = ('pseudo',)
|
||||||
list_filter = ()
|
list_filter = ()
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('pseudo', 'password')}),
|
(None, {'fields': ('pseudo', 'password')}),
|
||||||
('Personal info', {'fields': ('name', 'surname', 'email', 'school','shell', 'uid_number')}),
|
(
|
||||||
|
'Personal info',
|
||||||
|
{
|
||||||
|
'fields':
|
||||||
|
('name', 'surname', 'email', 'school', 'shell', 'uid_number')
|
||||||
|
}
|
||||||
|
),
|
||||||
('Permissions', {'fields': ('is_admin', )}),
|
('Permissions', {'fields': ('is_admin', )}),
|
||||||
)
|
)
|
||||||
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
|
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
|
||||||
# overrides get_fieldsets to use this attribute when creating a user.
|
# overrides get_fieldsets to use this attribute when creating a user.
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
(None, {
|
(
|
||||||
'classes': ('wide',),
|
None,
|
||||||
'fields': ('pseudo', 'name', 'surname', 'email', 'school', 'is_admin', 'password1', 'password2')}
|
{
|
||||||
|
'classes': ('wide',),
|
||||||
|
'fields': (
|
||||||
|
'pseudo',
|
||||||
|
'name',
|
||||||
|
'surname',
|
||||||
|
'email',
|
||||||
|
'school',
|
||||||
|
'is_admin',
|
||||||
|
'password1',
|
||||||
|
'password2'
|
||||||
|
)
|
||||||
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
search_fields = ('pseudo',)
|
search_fields = ('pseudo',)
|
||||||
ordering = ('pseudo',)
|
ordering = ('pseudo',)
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
|
|
||||||
|
|
||||||
class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
|
class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
|
||||||
|
"""Gestion d'un service user admin : champs personnels,
|
||||||
|
mot de passe; etc"""
|
||||||
# The forms to add and change user instances
|
# The forms to add and change user instances
|
||||||
form = ServiceUserChangeForm
|
form = ServiceUserChangeForm
|
||||||
add_form = ServiceUserCreationForm
|
add_form = ServiceUserCreationForm
|
||||||
|
@ -131,15 +190,19 @@ class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
|
||||||
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
|
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
|
||||||
# overrides get_fieldsets to use this attribute when creating a user.
|
# overrides get_fieldsets to use this attribute when creating a user.
|
||||||
add_fieldsets = (
|
add_fieldsets = (
|
||||||
(None, {
|
(
|
||||||
'classes': ('wide',),
|
None,
|
||||||
'fields': ('pseudo', 'password1', 'password2')}
|
{
|
||||||
|
'classes': ('wide',),
|
||||||
|
'fields': ('pseudo', 'password1', 'password2')
|
||||||
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
search_fields = ('pseudo',)
|
search_fields = ('pseudo',)
|
||||||
ordering = ('pseudo',)
|
ordering = ('pseudo',)
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
admin.site.register(ServiceUser, ServiceUserAdmin)
|
admin.site.register(ServiceUser, ServiceUserAdmin)
|
||||||
admin.site.register(LdapUser, LdapUserAdmin)
|
admin.site.register(LdapUser, LdapUserAdmin)
|
||||||
|
|
215
users/forms.py
215
users/forms.py
|
@ -20,8 +20,16 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Definition des forms pour l'application users.
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
Modification, creation de :
|
||||||
|
- un user (informations personnelles)
|
||||||
|
- un bannissement
|
||||||
|
- le mot de passe d'un user
|
||||||
|
- une whiteliste
|
||||||
|
- un user de service
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
@ -29,17 +37,34 @@ from django import forms
|
||||||
from django.forms import ModelForm, Form
|
from django.forms import ModelForm, Form
|
||||||
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
||||||
from django.core.validators import MinLengthValidator
|
from django.core.validators import MinLengthValidator
|
||||||
from preferences.models import OptionalUser
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from .models import User, ServiceUser, Right, School, ListRight, Whitelist, Ban, Request, remove_user_room
|
|
||||||
|
|
||||||
from .models import get_admin_right
|
from preferences.models import OptionalUser
|
||||||
|
from .models import User, ServiceUser, Right, School, ListRight, Whitelist
|
||||||
|
from .models import Ban, remove_user_room
|
||||||
|
|
||||||
|
NOW = timezone.now()
|
||||||
|
|
||||||
|
|
||||||
class PassForm(forms.Form):
|
class PassForm(forms.Form):
|
||||||
passwd1 = forms.CharField(label=u'Nouveau mot de passe', max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput)
|
"""Formulaire de changement de mot de passe. Verifie que les 2
|
||||||
passwd2 = forms.CharField(label=u'Saisir à nouveau le mot de passe', max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput)
|
nouveaux mots de passe renseignés sont identiques et respectent
|
||||||
|
une norme"""
|
||||||
|
passwd1 = forms.CharField(
|
||||||
|
label=u'Nouveau mot de passe',
|
||||||
|
max_length=255,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
widget=forms.PasswordInput
|
||||||
|
)
|
||||||
|
passwd2 = forms.CharField(
|
||||||
|
label=u'Saisir à nouveau le mot de passe',
|
||||||
|
max_length=255,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
widget=forms.PasswordInput
|
||||||
|
)
|
||||||
|
|
||||||
def clean_passwd2(self):
|
def clean_passwd2(self):
|
||||||
|
"""Verifie que passwd1 et 2 sont identiques"""
|
||||||
# Check that the two password entries match
|
# Check that the two password entries match
|
||||||
password1 = self.cleaned_data.get("passwd1")
|
password1 = self.cleaned_data.get("passwd1")
|
||||||
password2 = self.cleaned_data.get("passwd2")
|
password2 = self.cleaned_data.get("passwd2")
|
||||||
|
@ -47,11 +72,26 @@ class PassForm(forms.Form):
|
||||||
raise forms.ValidationError("Passwords don't match")
|
raise forms.ValidationError("Passwords don't match")
|
||||||
return password2
|
return password2
|
||||||
|
|
||||||
|
|
||||||
class UserCreationForm(forms.ModelForm):
|
class UserCreationForm(forms.ModelForm):
|
||||||
"""A form for creating new users. Includes all the required
|
"""A form for creating new users. Includes all the required
|
||||||
fields, plus a repeated password."""
|
fields, plus a repeated password.
|
||||||
password1 = forms.CharField(label='Password', widget=forms.PasswordInput, validators=[MinLengthValidator(8)], max_length=255)
|
|
||||||
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput, validators=[MinLengthValidator(8)], max_length=255)
|
Formulaire pour la création d'un user. N'est utilisé que pour
|
||||||
|
l'admin, lors de la creation d'un user par admin. Inclu tous les
|
||||||
|
champs obligatoires"""
|
||||||
|
password1 = forms.CharField(
|
||||||
|
label='Password',
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
max_length=255
|
||||||
|
)
|
||||||
|
password2 = forms.CharField(
|
||||||
|
label='Password confirmation',
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
max_length=255
|
||||||
|
)
|
||||||
is_admin = forms.BooleanField(label='is admin')
|
is_admin = forms.BooleanField(label='is admin')
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -63,6 +103,7 @@ class UserCreationForm(forms.ModelForm):
|
||||||
fields = ('pseudo', 'name', 'surname', 'email')
|
fields = ('pseudo', 'name', 'surname', 'email')
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean_password2(self):
|
||||||
|
"""Verifie que password1 et 2 sont identiques"""
|
||||||
# Check that the two password entries match
|
# Check that the two password entries match
|
||||||
password1 = self.cleaned_data.get("password1")
|
password1 = self.cleaned_data.get("password1")
|
||||||
password2 = self.cleaned_data.get("password2")
|
password2 = self.cleaned_data.get("password2")
|
||||||
|
@ -78,21 +119,40 @@ class UserCreationForm(forms.ModelForm):
|
||||||
user.is_admin = self.cleaned_data.get("is_admin")
|
user.is_admin = self.cleaned_data.get("is_admin")
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class ServiceUserCreationForm(forms.ModelForm):
|
class ServiceUserCreationForm(forms.ModelForm):
|
||||||
"""A form for creating new users. Includes all the required
|
"""A form for creating new users. Includes all the required
|
||||||
fields, plus a repeated password."""
|
fields, plus a repeated password.
|
||||||
password1 = forms.CharField(label='Password', widget=forms.PasswordInput, min_length=8, max_length=255)
|
|
||||||
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput, min_length=8, max_length=255)
|
Formulaire pour la creation de nouveaux serviceusers.
|
||||||
|
Requiert seulement un mot de passe; et un pseudo"""
|
||||||
|
password1 = forms.CharField(
|
||||||
|
label='Password',
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
min_length=8,
|
||||||
|
max_length=255
|
||||||
|
)
|
||||||
|
password2 = forms.CharField(
|
||||||
|
label='Password confirmation',
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
min_length=8,
|
||||||
|
max_length=255
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(ServiceUserCreationForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(ServiceUserCreationForm, self).__init__(
|
||||||
|
*args,
|
||||||
|
prefix=prefix,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ServiceUser
|
model = ServiceUser
|
||||||
fields = ('pseudo',)
|
fields = ('pseudo',)
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean_password2(self):
|
||||||
|
"""Verifie que password1 et 2 sont indentiques"""
|
||||||
# Check that the two password entries match
|
# Check that the two password entries match
|
||||||
password1 = self.cleaned_data.get("password1")
|
password1 = self.cleaned_data.get("password1")
|
||||||
password2 = self.cleaned_data.get("password2")
|
password2 = self.cleaned_data.get("password2")
|
||||||
|
@ -107,10 +167,13 @@ class ServiceUserCreationForm(forms.ModelForm):
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class UserChangeForm(forms.ModelForm):
|
class UserChangeForm(forms.ModelForm):
|
||||||
"""A form for updating users. Includes all the fields on
|
"""A form for updating users. Includes all the fields on
|
||||||
the user, but replaces the password field with admin's
|
the user, but replaces the password field with admin's
|
||||||
password hash display field.
|
password hash display field.
|
||||||
|
|
||||||
|
Formulaire pour la modification d'un user coté admin
|
||||||
"""
|
"""
|
||||||
password = ReadOnlyPasswordHashField()
|
password = ReadOnlyPasswordHashField()
|
||||||
is_admin = forms.BooleanField(label='is admin', required=False)
|
is_admin = forms.BooleanField(label='is admin', required=False)
|
||||||
|
@ -126,6 +189,7 @@ class UserChangeForm(forms.ModelForm):
|
||||||
self.initial['is_admin'] = kwargs['instance'].is_admin
|
self.initial['is_admin'] = kwargs['instance'].is_admin
|
||||||
|
|
||||||
def clean_password(self):
|
def clean_password(self):
|
||||||
|
"""Dummy fun"""
|
||||||
# Regardless of what the user provides, return the initial value.
|
# Regardless of what the user provides, return the initial value.
|
||||||
# This is done here, rather than on the field, because the
|
# This is done here, rather than on the field, because the
|
||||||
# field does not have access to the initial value
|
# field does not have access to the initial value
|
||||||
|
@ -139,42 +203,59 @@ class UserChangeForm(forms.ModelForm):
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class ServiceUserChangeForm(forms.ModelForm):
|
class ServiceUserChangeForm(forms.ModelForm):
|
||||||
"""A form for updating users. Includes all the fields on
|
"""A form for updating users. Includes all the fields on
|
||||||
the user, but replaces the password field with admin's
|
the user, but replaces the password field with admin's
|
||||||
password hash display field.
|
password hash display field.
|
||||||
|
|
||||||
|
Formulaire pour l'edition des service users coté admin
|
||||||
"""
|
"""
|
||||||
password = ReadOnlyPasswordHashField()
|
password = ReadOnlyPasswordHashField()
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(ServiceUserChangeForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(ServiceUserChangeForm, self).__init__(
|
||||||
|
*args,
|
||||||
|
prefix=prefix,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ServiceUser
|
model = ServiceUser
|
||||||
fields = ('pseudo',)
|
fields = ('pseudo',)
|
||||||
|
|
||||||
def clean_password(self):
|
def clean_password(self):
|
||||||
# Regardless of what the user provides, return the initial value.
|
"""Dummy fun"""
|
||||||
# This is done here, rather than on the field, because the
|
|
||||||
# field does not have access to the initial value
|
|
||||||
return self.initial["password"]
|
return self.initial["password"]
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordForm(forms.Form):
|
class ResetPasswordForm(forms.Form):
|
||||||
|
"""Formulaire de demande de reinitialisation de mot de passe,
|
||||||
|
mdp oublié"""
|
||||||
pseudo = forms.CharField(label=u'Pseudo', max_length=255)
|
pseudo = forms.CharField(label=u'Pseudo', max_length=255)
|
||||||
email = forms.EmailField(max_length=255)
|
email = forms.EmailField(max_length=255)
|
||||||
|
|
||||||
|
|
||||||
class MassArchiveForm(forms.Form):
|
class MassArchiveForm(forms.Form):
|
||||||
|
"""Formulaire d'archivage des users inactif. Prend en argument
|
||||||
|
du formulaire la date de depart avant laquelle archiver les
|
||||||
|
users"""
|
||||||
date = forms.DateTimeField(help_text='%d/%m/%y')
|
date = forms.DateTimeField(help_text='%d/%m/%y')
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data=super(MassArchiveForm, self).clean()
|
cleaned_data = super(MassArchiveForm, self).clean()
|
||||||
date = cleaned_data.get("date")
|
date = cleaned_data.get("date")
|
||||||
if date:
|
if date:
|
||||||
if date>timezone.now():
|
if date > NOW:
|
||||||
raise forms.ValidationError("Impossible d'archiver des utilisateurs dont la fin d'accès se situe dans le futur !")
|
raise forms.ValidationError("Impossible d'archiver des\
|
||||||
|
utilisateurs dont la fin d'accès se situe dans le futur !")
|
||||||
|
|
||||||
|
|
||||||
class BaseInfoForm(ModelForm):
|
class BaseInfoForm(ModelForm):
|
||||||
|
"""Formulaire de base d'edition d'un user. Formulaire de base, utilisé
|
||||||
|
pour l'edition de self par self ou un cableur. On formate les champs
|
||||||
|
avec des label plus jolis"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(BaseInfoForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(BaseInfoForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
@ -200,13 +281,21 @@ class BaseInfoForm(ModelForm):
|
||||||
]
|
]
|
||||||
|
|
||||||
def clean_telephone(self):
|
def clean_telephone(self):
|
||||||
|
"""Verifie que le tel est présent si 'option est validée
|
||||||
|
dans preferences"""
|
||||||
telephone = self.cleaned_data['telephone']
|
telephone = self.cleaned_data['telephone']
|
||||||
preferences, created = OptionalUser.objects.get_or_create()
|
preferences, _created = OptionalUser.objects.get_or_create()
|
||||||
if not telephone and preferences.is_tel_mandatory:
|
if not telephone and preferences.is_tel_mandatory:
|
||||||
raise forms.ValidationError("Un numéro de téléphone valide est requis")
|
raise forms.ValidationError(
|
||||||
|
"Un numéro de téléphone valide est requis"
|
||||||
|
)
|
||||||
return telephone
|
return telephone
|
||||||
|
|
||||||
|
|
||||||
class EditInfoForm(BaseInfoForm):
|
class EditInfoForm(BaseInfoForm):
|
||||||
|
"""Edition complète d'un user. Utilisé par admin,
|
||||||
|
permet d'editer normalement la chambre, ou le shell
|
||||||
|
Herite de la base"""
|
||||||
class Meta(BaseInfoForm.Meta):
|
class Meta(BaseInfoForm.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'name',
|
'name',
|
||||||
|
@ -220,22 +309,33 @@ class EditInfoForm(BaseInfoForm):
|
||||||
'telephone',
|
'telephone',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class InfoForm(EditInfoForm):
|
class InfoForm(EditInfoForm):
|
||||||
""" Utile pour forcer un déménagement quand il y a déjà un user en place"""
|
""" Utile pour forcer un déménagement quand il y a déjà un user en place
|
||||||
force = forms.BooleanField(label="Forcer le déménagement ?", initial=False, required=False)
|
Formuaire utilisé pour la creation initiale"""
|
||||||
|
force = forms.BooleanField(
|
||||||
|
label="Forcer le déménagement ?",
|
||||||
|
initial=False,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
def clean_force(self):
|
def clean_force(self):
|
||||||
|
"""On supprime l'ancien user de la chambre si et seulement si la
|
||||||
|
case est cochée"""
|
||||||
if self.cleaned_data.get('force', False):
|
if self.cleaned_data.get('force', False):
|
||||||
remove_user_room(self.cleaned_data.get('room'))
|
remove_user_room(self.cleaned_data.get('room'))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class UserForm(InfoForm):
|
class UserForm(InfoForm):
|
||||||
""" Model form general"""
|
""" Model form general"""
|
||||||
class Meta(InfoForm.Meta):
|
class Meta(InfoForm.Meta):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
class PasswordForm(ModelForm):
|
class PasswordForm(ModelForm):
|
||||||
""" Formulaire de changement brut de mot de passe. Ne pas utiliser sans traitement"""
|
""" Formulaire de changement brut de mot de passe.
|
||||||
|
Ne pas utiliser sans traitement"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ['password', 'pwd_ntlm']
|
fields = ['password', 'pwd_ntlm']
|
||||||
|
@ -244,21 +344,32 @@ class PasswordForm(ModelForm):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ServiceUserForm(ModelForm):
|
class ServiceUserForm(ModelForm):
|
||||||
""" Modification d'un service user"""
|
""" Modification d'un service user"""
|
||||||
password = forms.CharField(label=u'Nouveau mot de passe', max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput, required=False)
|
password = forms.CharField(
|
||||||
|
label=u'Nouveau mot de passe',
|
||||||
|
max_length=255,
|
||||||
|
validators=[MinLengthValidator(8)],
|
||||||
|
widget=forms.PasswordInput,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ServiceUser
|
model = ServiceUser
|
||||||
fields = ('pseudo','access_group')
|
fields = ('pseudo', 'access_group')
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class EditServiceUserForm(ServiceUserForm):
|
class EditServiceUserForm(ServiceUserForm):
|
||||||
|
"""Formulaire d'edition de base d'un service user. Ne permet
|
||||||
|
d'editer que son group d'acl et son commentaire"""
|
||||||
class Meta(ServiceUserForm.Meta):
|
class Meta(ServiceUserForm.Meta):
|
||||||
fields = ['access_group','comment']
|
fields = ['access_group', 'comment']
|
||||||
|
|
||||||
|
|
||||||
class StateForm(ModelForm):
|
class StateForm(ModelForm):
|
||||||
""" Changement de l'état d'un user"""
|
""" Changement de l'état d'un user"""
|
||||||
|
@ -272,6 +383,7 @@ class StateForm(ModelForm):
|
||||||
|
|
||||||
|
|
||||||
class SchoolForm(ModelForm):
|
class SchoolForm(ModelForm):
|
||||||
|
"""Edition, creation d'un école"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = School
|
model = School
|
||||||
fields = ['name']
|
fields = ['name']
|
||||||
|
@ -281,7 +393,10 @@ class SchoolForm(ModelForm):
|
||||||
super(SchoolForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(SchoolForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
self.fields['name'].label = 'Établissement'
|
self.fields['name'].label = 'Établissement'
|
||||||
|
|
||||||
|
|
||||||
class ListRightForm(ModelForm):
|
class ListRightForm(ModelForm):
|
||||||
|
"""Edition, d'un groupe , équivalent à un droit
|
||||||
|
Ne peremet pas d'editer le gid, car il sert de primary key"""
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ListRight
|
model = ListRight
|
||||||
fields = ['listright', 'details']
|
fields = ['listright', 'details']
|
||||||
|
@ -291,21 +406,38 @@ class ListRightForm(ModelForm):
|
||||||
super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
self.fields['listright'].label = 'Nom du droit/groupe'
|
self.fields['listright'].label = 'Nom du droit/groupe'
|
||||||
|
|
||||||
|
|
||||||
class NewListRightForm(ListRightForm):
|
class NewListRightForm(ListRightForm):
|
||||||
|
"""Ajout d'un groupe/list de droit """
|
||||||
class Meta(ListRightForm.Meta):
|
class Meta(ListRightForm.Meta):
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(NewListRightForm, self).__init__(*args, **kwargs)
|
super(NewListRightForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['gid'].label = 'Gid, attention, cet attribut ne doit pas être modifié après création'
|
self.fields['gid'].label = 'Gid, attention, cet attribut ne doit\
|
||||||
|
pas être modifié après création'
|
||||||
|
|
||||||
|
|
||||||
class DelListRightForm(Form):
|
class DelListRightForm(Form):
|
||||||
listrights = forms.ModelMultipleChoiceField(queryset=ListRight.objects.all(), label="Droits actuels", widget=forms.CheckboxSelectMultiple)
|
"""Suppression d'un ou plusieurs groupes"""
|
||||||
|
listrights = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=ListRight.objects.all(),
|
||||||
|
label="Droits actuels",
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DelSchoolForm(Form):
|
class DelSchoolForm(Form):
|
||||||
schools = forms.ModelMultipleChoiceField(queryset=School.objects.all(), label="Etablissements actuels", widget=forms.CheckboxSelectMultiple)
|
"""Suppression d'une ou plusieurs écoles"""
|
||||||
|
schools = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=School.objects.all(),
|
||||||
|
label="Etablissements actuels",
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RightForm(ModelForm):
|
class RightForm(ModelForm):
|
||||||
|
"""Assignation d'un droit à un user"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(RightForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(RightForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
@ -318,13 +450,19 @@ class RightForm(ModelForm):
|
||||||
|
|
||||||
|
|
||||||
class DelRightForm(Form):
|
class DelRightForm(Form):
|
||||||
rights = forms.ModelMultipleChoiceField(queryset=Right.objects.all(), widget=forms.CheckboxSelectMultiple)
|
"""Suppression d'un droit d'un user"""
|
||||||
|
rights = forms.ModelMultipleChoiceField(
|
||||||
|
queryset=Right.objects.all(),
|
||||||
|
widget=forms.CheckboxSelectMultiple
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, right, *args, **kwargs):
|
def __init__(self, right, *args, **kwargs):
|
||||||
super(DelRightForm, self).__init__(*args, **kwargs)
|
super(DelRightForm, self).__init__(*args, **kwargs)
|
||||||
self.fields['rights'].queryset = Right.objects.filter(right=right)
|
self.fields['rights'].queryset = Right.objects.filter(right=right)
|
||||||
|
|
||||||
|
|
||||||
class BanForm(ModelForm):
|
class BanForm(ModelForm):
|
||||||
|
"""Creation, edition d'un objet bannissement"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(BanForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(BanForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
@ -335,13 +473,16 @@ class BanForm(ModelForm):
|
||||||
exclude = ['user']
|
exclude = ['user']
|
||||||
|
|
||||||
def clean_date_end(self):
|
def clean_date_end(self):
|
||||||
|
"""Verification que date_end est après now"""
|
||||||
date_end = self.cleaned_data['date_end']
|
date_end = self.cleaned_data['date_end']
|
||||||
if date_end < timezone.now():
|
if date_end < NOW:
|
||||||
raise forms.ValidationError("Triple buse, la date de fin ne peut pas être avant maintenant... Re2o ne voyage pas dans le temps")
|
raise forms.ValidationError("Triple buse, la date de fin ne peut\
|
||||||
|
pas être avant maintenant... Re2o ne voyage pas dans le temps")
|
||||||
return date_end
|
return date_end
|
||||||
|
|
||||||
|
|
||||||
class WhitelistForm(ModelForm):
|
class WhitelistForm(ModelForm):
|
||||||
|
"""Creation, edition d'un objet whitelist"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
|
||||||
super(WhitelistForm, self).__init__(*args, prefix=prefix, **kwargs)
|
super(WhitelistForm, self).__init__(*args, prefix=prefix, **kwargs)
|
||||||
|
@ -352,7 +493,9 @@ class WhitelistForm(ModelForm):
|
||||||
exclude = ['user']
|
exclude = ['user']
|
||||||
|
|
||||||
def clean_date_end(self):
|
def clean_date_end(self):
|
||||||
|
"""Verification que la date_end est posterieur à now"""
|
||||||
date_end = self.cleaned_data['date_end']
|
date_end = self.cleaned_data['date_end']
|
||||||
if date_end < timezone.now():
|
if date_end < NOW:
|
||||||
raise forms.ValidationError("Triple buse, la date de fin ne peut pas être avant maintenant... Re2o ne voyage pas dans le temps")
|
raise forms.ValidationError("Triple buse, la date de fin ne peut pas\
|
||||||
|
être avant maintenant... Re2o ne voyage pas dans le temps")
|
||||||
return date_end
|
return date_end
|
||||||
|
|
584
users/models.py
584
users/models.py
File diff suppressed because it is too large
Load diff
|
@ -19,6 +19,9 @@
|
||||||
# You should have received a copy of the GNU General Public License along
|
# You should have received a copy of the GNU General Public License along
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
"""
|
||||||
|
Definition des urls, pointant vers les views
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
@ -32,39 +35,88 @@ urlpatterns = [
|
||||||
url(r'^state/(?P<userid>[0-9]+)$', views.state, name='state'),
|
url(r'^state/(?P<userid>[0-9]+)$', views.state, name='state'),
|
||||||
url(r'^password/(?P<userid>[0-9]+)$', views.password, name='password'),
|
url(r'^password/(?P<userid>[0-9]+)$', views.password, name='password'),
|
||||||
url(r'^new_serviceuser/$', views.new_serviceuser, name='new-serviceuser'),
|
url(r'^new_serviceuser/$', views.new_serviceuser, name='new-serviceuser'),
|
||||||
url(r'^edit_serviceuser/(?P<userid>[0-9]+)$', views.edit_serviceuser, name='edit-serviceuser'),
|
url(
|
||||||
url(r'^del_serviceuser/(?P<userid>[0-9]+)$', views.del_serviceuser, name='del-serviceuser'),
|
r'^edit_serviceuser/(?P<userid>[0-9]+)$',
|
||||||
|
views.edit_serviceuser,
|
||||||
|
name='edit-serviceuser'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^del_serviceuser/(?P<userid>[0-9]+)$',
|
||||||
|
views.del_serviceuser,
|
||||||
|
name='del-serviceuser'
|
||||||
|
),
|
||||||
url(r'^add_ban/(?P<userid>[0-9]+)$', views.add_ban, name='add-ban'),
|
url(r'^add_ban/(?P<userid>[0-9]+)$', views.add_ban, name='add-ban'),
|
||||||
url(r'^edit_ban/(?P<banid>[0-9]+)$', views.edit_ban, name='edit-ban'),
|
url(r'^edit_ban/(?P<banid>[0-9]+)$', views.edit_ban, name='edit-ban'),
|
||||||
url(r'^add_whitelist/(?P<userid>[0-9]+)$', views.add_whitelist, name='add-whitelist'),
|
url(
|
||||||
url(r'^edit_whitelist/(?P<whitelistid>[0-9]+)$', views.edit_whitelist, name='edit-whitelist'),
|
r'^add_whitelist/(?P<userid>[0-9]+)$',
|
||||||
|
views.add_whitelist,
|
||||||
|
name='add-whitelist'
|
||||||
|
),
|
||||||
|
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'^add_right/(?P<userid>[0-9]+)$', views.add_right, name='add-right'),
|
||||||
url(r'^del_right/$', views.del_right, name='del-right'),
|
url(r'^del_right/$', views.del_right, name='del-right'),
|
||||||
url(r'^add_school/$', views.add_school, name='add-school'),
|
url(r'^add_school/$', views.add_school, name='add-school'),
|
||||||
url(r'^edit_school/(?P<schoolid>[0-9]+)$', views.edit_school, name='edit-school'),
|
url(
|
||||||
|
r'^edit_school/(?P<schoolid>[0-9]+)$',
|
||||||
|
views.edit_school,
|
||||||
|
name='edit-school'
|
||||||
|
),
|
||||||
url(r'^del_school/$', views.del_school, name='del-school'),
|
url(r'^del_school/$', views.del_school, name='del-school'),
|
||||||
url(r'^add_listright/$', views.add_listright, name='add-listright'),
|
url(r'^add_listright/$', views.add_listright, name='add-listright'),
|
||||||
url(r'^edit_listright/(?P<listrightid>[0-9]+)$', views.edit_listright, name='edit-listright'),
|
url(
|
||||||
|
r'^edit_listright/(?P<listrightid>[0-9]+)$',
|
||||||
|
views.edit_listright,
|
||||||
|
name='edit-listright'
|
||||||
|
),
|
||||||
url(r'^del_listright/$', views.del_listright, name='del-listright'),
|
url(r'^del_listright/$', views.del_listright, name='del-listright'),
|
||||||
url(r'^profil/(?P<userid>[0-9]+)$', views.profil, name='profil'),
|
url(r'^profil/(?P<userid>[0-9]+)$', views.profil, name='profil'),
|
||||||
url(r'^index_ban/$', views.index_ban, name='index-ban'),
|
url(r'^index_ban/$', views.index_ban, name='index-ban'),
|
||||||
url(r'^index_white/$', views.index_white, name='index-white'),
|
url(r'^index_white/$', views.index_white, name='index-white'),
|
||||||
url(r'^index_school/$', views.index_school, name='index-school'),
|
url(r'^index_school/$', views.index_school, name='index-school'),
|
||||||
url(r'^index_listright/$', views.index_listright, name='index-listright'),
|
url(r'^index_listright/$', views.index_listright, name='index-listright'),
|
||||||
url(r'^index_serviceusers/$', views.index_serviceusers, name='index-serviceusers'),
|
url(
|
||||||
|
r'^index_serviceusers/$',
|
||||||
|
views.index_serviceusers,
|
||||||
|
name='index-serviceusers'
|
||||||
|
),
|
||||||
url(r'^mon_profil/$', views.mon_profil, name='mon-profil'),
|
url(r'^mon_profil/$', views.mon_profil, name='mon-profil'),
|
||||||
url(r'^process/(?P<token>[a-z0-9]{32})/$', views.process, name='process'),
|
url(r'^process/(?P<token>[a-z0-9]{32})/$', views.process, name='process'),
|
||||||
url(r'^reset_password/$', views.reset_password, name='reset-password'),
|
url(r'^reset_password/$', views.reset_password, name='reset-password'),
|
||||||
url(r'^mass_archive/$', views.mass_archive, name='mass-archive'),
|
url(r'^mass_archive/$', views.mass_archive, name='mass-archive'),
|
||||||
url(r'^history/(?P<object>user)/(?P<id>[0-9]+)$', views.history, name='history'),
|
url(
|
||||||
url(r'^history/(?P<object>ban)/(?P<id>[0-9]+)$', views.history, name='history'),
|
r'^history/(?P<object>user)/(?P<id>[0-9]+)$',
|
||||||
url(r'^history/(?P<object>whitelist)/(?P<id>[0-9]+)$', views.history, name='history'),
|
views.history,
|
||||||
url(r'^history/(?P<object>school)/(?P<id>[0-9]+)$', views.history, name='history'),
|
name='history'
|
||||||
url(r'^history/(?P<object>listright)/(?P<id>[0-9]+)$', views.history, name='history'),
|
),
|
||||||
url(r'^history/(?P<object>serviceuser)/(?P<id>[0-9]+)$', views.history, name='history'),
|
url(
|
||||||
|
r'^history/(?P<object>ban)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^history/(?P<object>whitelist)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^history/(?P<object>school)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^history/(?P<object>listright)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^history/(?P<object>serviceuser)/(?P<id>[0-9]+)$',
|
||||||
|
views.history,
|
||||||
|
name='history'
|
||||||
|
),
|
||||||
url(r'^$', views.index, name='index'),
|
url(r'^$', views.index, name='index'),
|
||||||
url(r'^rest/mailing/$', views.mailing, name='mailing'),
|
url(r'^rest/mailing/$', views.mailing, name='mailing'),
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
363
users/views.py
363
users/views.py
|
@ -23,20 +23,25 @@
|
||||||
# App de gestion des users pour re2o
|
# App de gestion des users pour re2o
|
||||||
# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin
|
# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin
|
||||||
# Gplv2
|
# Gplv2
|
||||||
|
"""
|
||||||
|
Module des views.
|
||||||
|
|
||||||
|
On définit les vues pour l'ajout, l'edition des users : infos personnelles,
|
||||||
|
mot de passe, etc
|
||||||
|
|
||||||
|
Permet aussi l'ajout, edition et suppression des droits, des bannissements,
|
||||||
|
des whitelist, des services users et des écoles
|
||||||
|
"""
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render, redirect
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
from django.template.context_processors import csrf
|
|
||||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||||
from django.template import Context, RequestContext, loader
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required, permission_required
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
from django.db.models import Max, ProtectedError
|
from django.db.models import ProtectedError
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.core.urlresolvers import reverse
|
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
@ -47,21 +52,20 @@ from rest_framework.renderers import JSONRenderer
|
||||||
from reversion.models import Version
|
from reversion.models import Version
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
from users.serializers import MailSerializer
|
from users.serializers import MailSerializer
|
||||||
from users.models import User, Right, Ban, Whitelist, School, ListRight, Request, ServiceUser, all_has_access
|
from users.models import User, Right, Ban, Whitelist, School, ListRight
|
||||||
from users.forms import DelRightForm, BanForm, WhitelistForm, DelSchoolForm, DelListRightForm, NewListRightForm
|
from users.models import Request, ServiceUser
|
||||||
from users.forms import EditInfoForm, InfoForm, BaseInfoForm, StateForm, RightForm, SchoolForm, EditServiceUserForm, ServiceUserForm, ListRightForm
|
from users.forms import DelRightForm, BanForm, WhitelistForm, DelSchoolForm
|
||||||
from cotisations.models import Facture
|
from users.forms import DelListRightForm, NewListRightForm
|
||||||
from machines.models import Machine, Interface
|
from users.forms import InfoForm, BaseInfoForm, StateForm
|
||||||
|
from users.forms import RightForm, SchoolForm, EditServiceUserForm
|
||||||
|
from users.forms import ServiceUserForm, ListRightForm
|
||||||
from users.forms import MassArchiveForm, PassForm, ResetPasswordForm
|
from users.forms import MassArchiveForm, PassForm, ResetPasswordForm
|
||||||
from preferences.models import OptionalUser, AssoOption, GeneralOption
|
from cotisations.models import Facture
|
||||||
|
from machines.models import Machine
|
||||||
|
from preferences.models import OptionalUser, GeneralOption
|
||||||
|
|
||||||
from re2o.login import hashNT
|
from re2o.views import form
|
||||||
|
from re2o.utils import all_has_access
|
||||||
|
|
||||||
def form(ctx, template, request):
|
|
||||||
c = ctx
|
|
||||||
c.update(csrf(request))
|
|
||||||
return render(request, template, c)
|
|
||||||
|
|
||||||
def password_change_action(u_form, user, request, req=False):
|
def password_change_action(u_form, user, request, req=False):
|
||||||
""" Fonction qui effectue le changeemnt de mdp bdd"""
|
""" Fonction qui effectue le changeemnt de mdp bdd"""
|
||||||
|
@ -75,10 +79,12 @@ def password_change_action(u_form, user, request, req=False):
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
return redirect("/users/profil/" + str(user.id))
|
return redirect("/users/profil/" + str(user.id))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def new_user(request):
|
def new_user(request):
|
||||||
""" Vue de création d'un nouvel utilisateur, envoie un mail pour le mot de passe"""
|
""" Vue de création d'un nouvel utilisateur,
|
||||||
|
envoie un mail pour le mot de passe"""
|
||||||
user = InfoForm(request.POST or None)
|
user = InfoForm(request.POST or None)
|
||||||
if user.is_valid():
|
if user.is_valid():
|
||||||
user = user.save(commit=False)
|
user = user.save(commit=False)
|
||||||
|
@ -87,21 +93,25 @@ def new_user(request):
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
user.reset_passwd_mail(request)
|
user.reset_passwd_mail(request)
|
||||||
messages.success(request, "L'utilisateur %s a été crée, un mail pour l'initialisation du mot de passe a été envoyé" % user.pseudo)
|
messages.success(request, "L'utilisateur %s a été crée, un mail\
|
||||||
|
pour l'initialisation du mot de passe a été envoyé" % user.pseudo)
|
||||||
return redirect("/users/profil/" + str(user.id))
|
return redirect("/users/profil/" + str(user.id))
|
||||||
return form({'userform': user}, 'users/user.html', request)
|
return form({'userform': user}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def edit_info(request, userid):
|
def edit_info(request, userid):
|
||||||
""" Edite un utilisateur à partir de son id,
|
""" Edite un utilisateur à partir de son id,
|
||||||
si l'id est différent de request.user, vérifie la possession du droit cableur """
|
si l'id est différent de request.user, vérifie la
|
||||||
|
possession du droit cableur """
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pk=userid)
|
user = User.objects.get(pk=userid)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
messages.error(request, "Utilisateur inexistant")
|
messages.error(request, "Utilisateur inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if not request.user.has_perms(('cableur',)) and user != request.user:
|
if not request.user.has_perms(('cableur',)) and user != request.user:
|
||||||
messages.error(request, "Vous ne pouvez pas modifier un autre user que vous sans droit cableur")
|
messages.error(request, "Vous ne pouvez pas modifier un autre\
|
||||||
|
user que vous sans droit cableur")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
if not request.user.has_perms(('cableur',)):
|
if not request.user.has_perms(('cableur',)):
|
||||||
user = BaseInfoForm(request.POST or None, instance=user)
|
user = BaseInfoForm(request.POST or None, instance=user)
|
||||||
|
@ -111,15 +121,19 @@ def edit_info(request, userid):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
user.save()
|
user.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in user.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in user.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "L'user a bien été modifié")
|
messages.success(request, "L'user a bien été modifié")
|
||||||
return redirect("/users/profil/" + userid)
|
return redirect("/users/profil/" + userid)
|
||||||
return form({'userform': user}, 'users/user.html', request)
|
return form({'userform': user}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
def state(request, userid):
|
def state(request, userid):
|
||||||
""" Changer l'etat actif/desactivé/archivé d'un user, need droit bureau """
|
""" Changer l'etat actif/desactivé/archivé d'un user,
|
||||||
|
need droit bureau """
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pk=userid)
|
user = User.objects.get(pk=userid)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
|
@ -135,12 +149,15 @@ def state(request, userid):
|
||||||
elif state.cleaned_data['state'] == User.STATE_DISABLED:
|
elif state.cleaned_data['state'] == User.STATE_DISABLED:
|
||||||
user.state = User.STATE_DISABLED
|
user.state = User.STATE_DISABLED
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in state.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in state.changed_data
|
||||||
|
))
|
||||||
user.save()
|
user.save()
|
||||||
messages.success(request, "Etat changé avec succès")
|
messages.success(request, "Etat changé avec succès")
|
||||||
return redirect("/users/profil/" + userid)
|
return redirect("/users/profil/" + userid)
|
||||||
return form({'userform': state}, 'users/user.html', request)
|
return form({'userform': state}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def password(request, userid):
|
def password(request, userid):
|
||||||
""" Reinitialisation d'un mot de passe à partir de l'userid,
|
""" Reinitialisation d'un mot de passe à partir de l'userid,
|
||||||
|
@ -152,16 +169,20 @@ def password(request, userid):
|
||||||
messages.error(request, "Utilisateur inexistant")
|
messages.error(request, "Utilisateur inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if not request.user.has_perms(('cableur',)) and user != request.user:
|
if not request.user.has_perms(('cableur',)) and user != request.user:
|
||||||
messages.error(request, "Vous ne pouvez pas modifier un autre user que vous sans droit cableur")
|
messages.error(request, "Vous ne pouvez pas modifier un\
|
||||||
|
autre user que vous sans droit cableur")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
if not request.user.has_perms(('bureau',)) and user != request.user and Right.objects.filter(user=user):
|
if not request.user.has_perms(('bureau',)) and user != request.user\
|
||||||
messages.error(request, "Il faut les droits bureau pour modifier le mot de passe d'un membre actif")
|
and Right.objects.filter(user=user):
|
||||||
|
messages.error(request, "Il faut les droits bureau pour modifier le\
|
||||||
|
mot de passe d'un membre actif")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
u_form = PassForm(request.POST or None)
|
u_form = PassForm(request.POST or None)
|
||||||
if u_form.is_valid():
|
if u_form.is_valid():
|
||||||
return password_change_action(u_form, user, request)
|
return password_change_action(u_form, user, request)
|
||||||
return form({'userform': u_form}, 'users/user.html', request)
|
return form({'userform': u_form}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def new_serviceuser(request):
|
def new_serviceuser(request):
|
||||||
|
@ -174,15 +195,20 @@ def new_serviceuser(request):
|
||||||
user_object.save()
|
user_object.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
messages.success(request, "L'utilisateur %s a été crée" % user_object.pseudo)
|
messages.success(
|
||||||
|
request,
|
||||||
|
"L'utilisateur %s a été crée" % user_object.pseudo
|
||||||
|
)
|
||||||
return redirect("/users/index_serviceusers/")
|
return redirect("/users/index_serviceusers/")
|
||||||
return form({'userform': user}, 'users/user.html', request)
|
return form({'userform': user}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def edit_serviceuser(request, userid):
|
def edit_serviceuser(request, userid):
|
||||||
""" Edite un utilisateur à partir de son id,
|
""" Edite un utilisateur à partir de son id,
|
||||||
si l'id est différent de request.user, vérifie la possession du droit cableur """
|
si l'id est différent de request.user,
|
||||||
|
vérifie la possession du droit cableur """
|
||||||
try:
|
try:
|
||||||
user = ServiceUser.objects.get(pk=userid)
|
user = ServiceUser.objects.get(pk=userid)
|
||||||
except ServiceUser.DoesNotExist:
|
except ServiceUser.DoesNotExist:
|
||||||
|
@ -196,18 +222,22 @@ def edit_serviceuser(request, userid):
|
||||||
user_object.set_password(user.cleaned_data['password'])
|
user_object.set_password(user.cleaned_data['password'])
|
||||||
user_object.save()
|
user_object.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in user.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in user.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "L'user a bien été modifié")
|
messages.success(request, "L'user a bien été modifié")
|
||||||
return redirect("/users/index_serviceusers")
|
return redirect("/users/index_serviceusers")
|
||||||
return form({'userform': user}, 'users/user.html', request)
|
return form({'userform': user}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('infra')
|
@permission_required('infra')
|
||||||
def del_serviceuser(request, userid):
|
def del_serviceuser(request, userid):
|
||||||
|
"""Suppression d'un ou plusieurs serviceusers"""
|
||||||
try:
|
try:
|
||||||
user = ServiceUser.objects.get(pk=userid)
|
user = ServiceUser.objects.get(pk=userid)
|
||||||
except ServiceUser.DoesNotExist:
|
except ServiceUser.DoesNotExist:
|
||||||
messages.error(request, u"Utilisateur inexistant" )
|
messages.error(request, u"Utilisateur inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -215,7 +245,12 @@ def del_serviceuser(request, userid):
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
messages.success(request, "L'user a été détruite")
|
messages.success(request, "L'user a été détruite")
|
||||||
return redirect("/users/index_serviceusers/")
|
return redirect("/users/index_serviceusers/")
|
||||||
return form({'objet': user, 'objet_name': 'serviceuser'}, 'users/delete.html', request)
|
return form(
|
||||||
|
{'objet': user, 'objet_name': 'serviceuser'},
|
||||||
|
'users/delete.html',
|
||||||
|
request
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
|
@ -241,28 +276,33 @@ def add_right(request, userid):
|
||||||
return redirect("/users/profil/" + userid)
|
return redirect("/users/profil/" + userid)
|
||||||
return form({'userform': right}, 'users/user.html', request)
|
return form({'userform': right}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
def del_right(request):
|
def del_right(request):
|
||||||
""" Supprimer un droit à un user, need droit bureau """
|
""" Supprimer un droit à un user, need droit bureau """
|
||||||
user_right_list = dict()
|
user_right_list = dict()
|
||||||
for right in ListRight.objects.all():
|
for right in ListRight.objects.all():
|
||||||
user_right_list[right]= DelRightForm(right, request.POST or None)
|
user_right_list[right] = DelRightForm(right, request.POST or None)
|
||||||
for keys, right_item in user_right_list.items():
|
for _keys, right_item in user_right_list.items():
|
||||||
if right_item.is_valid():
|
if right_item.is_valid():
|
||||||
right_del = right_item.cleaned_data['rights']
|
right_del = right_item.cleaned_data['rights']
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Retrait des droit %s" % ','.join(str(deleted_right) for deleted_right in right_del))
|
reversion.set_comment("Retrait des droit %s" % ','.join(
|
||||||
|
str(deleted_right) for deleted_right in right_del
|
||||||
|
))
|
||||||
right_del.delete()
|
right_del.delete()
|
||||||
messages.success(request, "Droit retiré avec succès")
|
messages.success(request, "Droit retiré avec succès")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
return form({'userform': user_right_list}, 'users/del_right.html', request)
|
return form({'userform': user_right_list}, 'users/del_right.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bofh')
|
@permission_required('bofh')
|
||||||
def add_ban(request, userid):
|
def add_ban(request, userid):
|
||||||
""" Ajouter un banissement, nécessite au moins le droit bofh (a fortiori bureau)
|
""" Ajouter un banissement, nécessite au moins le droit bofh
|
||||||
|
(a fortiori bureau)
|
||||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
|
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pk=userid)
|
user = User.objects.get(pk=userid)
|
||||||
|
@ -273,7 +313,7 @@ def add_ban(request, userid):
|
||||||
ban = BanForm(request.POST or None, instance=ban_instance)
|
ban = BanForm(request.POST or None, instance=ban_instance)
|
||||||
if ban.is_valid():
|
if ban.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
ban_object = ban.save()
|
_ban_object = ban.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Création")
|
reversion.set_comment("Création")
|
||||||
messages.success(request, "Bannissement ajouté")
|
messages.success(request, "Bannissement ajouté")
|
||||||
|
@ -285,10 +325,12 @@ def add_ban(request, userid):
|
||||||
)
|
)
|
||||||
return form({'userform': ban}, 'users/user.html', request)
|
return form({'userform': ban}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bofh')
|
@permission_required('bofh')
|
||||||
def edit_ban(request, banid):
|
def edit_ban(request, banid):
|
||||||
""" Editer un bannissement, nécessite au moins le droit bofh (a fortiori bureau)
|
""" Editer un bannissement, nécessite au moins le droit bofh
|
||||||
|
(a fortiori bureau)
|
||||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
|
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement"""
|
||||||
try:
|
try:
|
||||||
ban_instance = Ban.objects.get(pk=banid)
|
ban_instance = Ban.objects.get(pk=banid)
|
||||||
|
@ -300,23 +342,31 @@ def edit_ban(request, banid):
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
ban.save()
|
ban.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in ban.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in ban.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "Bannissement modifié")
|
messages.success(request, "Bannissement modifié")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
return form({'userform': ban}, 'users/user.html', request)
|
return form({'userform': ban}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def add_whitelist(request, userid):
|
def add_whitelist(request, userid):
|
||||||
""" Accorder un accès gracieux, temporaire ou permanent. Need droit cableur
|
""" Accorder un accès gracieux, temporaire ou permanent.
|
||||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement, raison obligatoire"""
|
Need droit cableur
|
||||||
|
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement,
|
||||||
|
raison obligatoire"""
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pk=userid)
|
user = User.objects.get(pk=userid)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
messages.error(request, "Utilisateur inexistant")
|
messages.error(request, "Utilisateur inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
whitelist_instance = Whitelist(user=user)
|
whitelist_instance = Whitelist(user=user)
|
||||||
whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance)
|
whitelist = WhitelistForm(
|
||||||
|
request.POST or None,
|
||||||
|
instance=whitelist_instance
|
||||||
|
)
|
||||||
if whitelist.is_valid():
|
if whitelist.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
whitelist.save()
|
whitelist.save()
|
||||||
|
@ -331,30 +381,40 @@ def add_whitelist(request, userid):
|
||||||
)
|
)
|
||||||
return form({'userform': whitelist}, 'users/user.html', request)
|
return form({'userform': whitelist}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def edit_whitelist(request, whitelistid):
|
def edit_whitelist(request, whitelistid):
|
||||||
""" Editer un accès gracieux, temporaire ou permanent. Need droit cableur
|
""" Editer un accès gracieux, temporaire ou permanent.
|
||||||
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement, raison obligatoire"""
|
Need droit cableur
|
||||||
|
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement,
|
||||||
|
raison obligatoire"""
|
||||||
try:
|
try:
|
||||||
whitelist_instance = Whitelist.objects.get(pk=whitelistid)
|
whitelist_instance = Whitelist.objects.get(pk=whitelistid)
|
||||||
except Whitelist.DoesNotExist:
|
except Whitelist.DoesNotExist:
|
||||||
messages.error(request, "Entrée inexistante")
|
messages.error(request, "Entrée inexistante")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
whitelist = WhitelistForm(request.POST or None, instance=whitelist_instance)
|
whitelist = WhitelistForm(
|
||||||
|
request.POST or None,
|
||||||
|
instance=whitelist_instance
|
||||||
|
)
|
||||||
if whitelist.is_valid():
|
if whitelist.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
whitelist.save()
|
whitelist.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in whitelist.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in whitelist.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "Whitelist modifiée")
|
messages.success(request, "Whitelist modifiée")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
return form({'userform': whitelist}, 'users/user.html', request)
|
return form({'userform': whitelist}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def add_school(request):
|
def add_school(request):
|
||||||
""" Ajouter un établissement d'enseignement à la base de donnée, need cableur"""
|
""" Ajouter un établissement d'enseignement à la base de donnée,
|
||||||
|
need cableur"""
|
||||||
school = SchoolForm(request.POST or None)
|
school = SchoolForm(request.POST or None)
|
||||||
if school.is_valid():
|
if school.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -365,30 +425,37 @@ def add_school(request):
|
||||||
return redirect("/users/index_school/")
|
return redirect("/users/index_school/")
|
||||||
return form({'userform': school}, 'users/user.html', request)
|
return form({'userform': school}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def edit_school(request, schoolid):
|
def edit_school(request, schoolid):
|
||||||
""" Editer un établissement d'enseignement à partir du schoolid dans la base de donnée, need cableur"""
|
""" Editer un établissement d'enseignement à partir du schoolid dans
|
||||||
|
la base de donnée, need cableur"""
|
||||||
try:
|
try:
|
||||||
school_instance = School.objects.get(pk=schoolid)
|
school_instance = School.objects.get(pk=schoolid)
|
||||||
except School.DoesNotExist:
|
except School.DoesNotExist:
|
||||||
messages.error(request, u"Entrée inexistante" )
|
messages.error(request, u"Entrée inexistante")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
school = SchoolForm(request.POST or None, instance=school_instance)
|
school = SchoolForm(request.POST or None, instance=school_instance)
|
||||||
if school.is_valid():
|
if school.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
school.save()
|
school.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in school.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in school.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "Établissement modifié")
|
messages.success(request, "Établissement modifié")
|
||||||
return redirect("/users/index_school/")
|
return redirect("/users/index_school/")
|
||||||
return form({'userform': school}, 'users/user.html', request)
|
return form({'userform': school}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def del_school(request):
|
def del_school(request):
|
||||||
""" Supprimer un établissement d'enseignement à la base de donnée, need cableur
|
""" Supprimer un établissement d'enseignement à la base de donnée,
|
||||||
Objet protégé, possible seulement si aucun user n'est affecté à l'établissement """
|
need cableur
|
||||||
|
Objet protégé, possible seulement si aucun user n'est affecté à
|
||||||
|
l'établissement """
|
||||||
school = DelSchoolForm(request.POST or None)
|
school = DelSchoolForm(request.POST or None)
|
||||||
if school.is_valid():
|
if school.is_valid():
|
||||||
school_dels = school.cleaned_data['schools']
|
school_dels = school.cleaned_data['schools']
|
||||||
|
@ -406,6 +473,7 @@ def del_school(request):
|
||||||
return redirect("/users/index_school/")
|
return redirect("/users/index_school/")
|
||||||
return form({'userform': school}, 'users/user.html', request)
|
return form({'userform': school}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
def add_listright(request):
|
def add_listright(request):
|
||||||
|
@ -421,29 +489,38 @@ def add_listright(request):
|
||||||
return redirect("/users/index_listright/")
|
return redirect("/users/index_listright/")
|
||||||
return form({'userform': listright}, 'users/user.html', request)
|
return form({'userform': listright}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
def edit_listright(request, listrightid):
|
def edit_listright(request, listrightid):
|
||||||
""" Editer un groupe/droit, necessite droit bureau, à partir du listright id """
|
""" Editer un groupe/droit, necessite droit bureau,
|
||||||
|
à partir du listright id """
|
||||||
try:
|
try:
|
||||||
listright_instance = ListRight.objects.get(pk=listrightid)
|
listright_instance = ListRight.objects.get(pk=listrightid)
|
||||||
except ListRight.DoesNotExist:
|
except ListRight.DoesNotExist:
|
||||||
messages.error(request, u"Entrée inexistante" )
|
messages.error(request, u"Entrée inexistante")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
listright = ListRightForm(request.POST or None, instance=listright_instance)
|
listright = ListRightForm(
|
||||||
|
request.POST or None,
|
||||||
|
instance=listright_instance
|
||||||
|
)
|
||||||
if listright.is_valid():
|
if listright.is_valid():
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
listright.save()
|
listright.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in listright.changed_data))
|
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(
|
||||||
|
field for field in listright.changed_data
|
||||||
|
))
|
||||||
messages.success(request, "Droit modifié")
|
messages.success(request, "Droit modifié")
|
||||||
return redirect("/users/index_listright/")
|
return redirect("/users/index_listright/")
|
||||||
return form({'userform': listright}, 'users/user.html', request)
|
return form({'userform': listright}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
def del_listright(request):
|
def del_listright(request):
|
||||||
""" Supprimer un ou plusieurs groupe, possible si il est vide, need droit bureau """
|
""" Supprimer un ou plusieurs groupe, possible si il est vide, need droit
|
||||||
|
bureau """
|
||||||
listright = DelListRightForm(request.POST or None)
|
listright = DelListRightForm(request.POST or None)
|
||||||
if listright.is_valid():
|
if listright.is_valid():
|
||||||
listright_dels = listright.cleaned_data['listrights']
|
listright_dels = listright.cleaned_data['listrights']
|
||||||
|
@ -461,6 +538,7 @@ def del_listright(request):
|
||||||
return redirect("/users/index_listright/")
|
return redirect("/users/index_listright/")
|
||||||
return form({'userform': listright}, 'users/user.html', request)
|
return form({'userform': listright}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('bureau')
|
@permission_required('bureau')
|
||||||
def mass_archive(request):
|
def mass_archive(request):
|
||||||
|
@ -469,7 +547,10 @@ def mass_archive(request):
|
||||||
to_archive_list = []
|
to_archive_list = []
|
||||||
if to_archive_date.is_valid():
|
if to_archive_date.is_valid():
|
||||||
date = to_archive_date.cleaned_data['date']
|
date = to_archive_date.cleaned_data['date']
|
||||||
to_archive_list = [user for user in User.objects.exclude(state=User.STATE_ARCHIVE) if not user.end_access() or user.end_access() < date]
|
to_archive_list = [user for user in
|
||||||
|
User.objects.exclude(state=User.STATE_ARCHIVE)
|
||||||
|
if not user.end_access()
|
||||||
|
or user.end_access() < date]
|
||||||
if "valider" in request.POST:
|
if "valider" in request.POST:
|
||||||
for user in to_archive_list:
|
for user in to_archive_list:
|
||||||
with transaction.atomic(), reversion.create_revision():
|
with transaction.atomic(), reversion.create_revision():
|
||||||
|
@ -477,15 +558,22 @@ def mass_archive(request):
|
||||||
user.save()
|
user.save()
|
||||||
reversion.set_user(request.user)
|
reversion.set_user(request.user)
|
||||||
reversion.set_comment("Archivage")
|
reversion.set_comment("Archivage")
|
||||||
messages.success(request, "%s users ont été archivés" % len(to_archive_list))
|
messages.success(request, "%s users ont été archivés" % len(
|
||||||
|
to_archive_list
|
||||||
|
))
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
return form({'userform': to_archive_date, 'to_archive_list': to_archive_list}, 'users/mass_archive.html', request)
|
return form(
|
||||||
|
{'userform': to_archive_date, 'to_archive_list': to_archive_list},
|
||||||
|
'users/mass_archive.html',
|
||||||
|
request
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index(request):
|
def index(request):
|
||||||
""" Affiche l'ensemble des users, need droit cableur """
|
""" Affiche l'ensemble des users, need droit cableur """
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
users_list = User.objects.select_related('room').order_by('state', 'name')
|
users_list = User.objects.select_related('room').order_by('state', 'name')
|
||||||
paginator = Paginator(users_list, pagination_number)
|
paginator = Paginator(users_list, pagination_number)
|
||||||
|
@ -500,13 +588,15 @@ def index(request):
|
||||||
users_list = paginator.page(paginator.num_pages)
|
users_list = paginator.page(paginator.num_pages)
|
||||||
return render(request, 'users/index.html', {'users_list': users_list})
|
return render(request, 'users/index.html', {'users_list': users_list})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_ban(request):
|
def index_ban(request):
|
||||||
""" Affiche l'ensemble des ban, need droit cableur """
|
""" Affiche l'ensemble des ban, need droit cableur """
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
ban_list = Ban.objects.order_by('date_start').select_related('user').reverse()
|
ban_list = Ban.objects.order_by('date_start')\
|
||||||
|
.select_related('user').reverse()
|
||||||
paginator = Paginator(ban_list, pagination_number)
|
paginator = Paginator(ban_list, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
try:
|
try:
|
||||||
|
@ -519,13 +609,15 @@ def index_ban(request):
|
||||||
ban_list = paginator.page(paginator.num_pages)
|
ban_list = paginator.page(paginator.num_pages)
|
||||||
return render(request, 'users/index_ban.html', {'ban_list': ban_list})
|
return render(request, 'users/index_ban.html', {'ban_list': ban_list})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_white(request):
|
def index_white(request):
|
||||||
""" Affiche l'ensemble des whitelist, need droit cableur """
|
""" Affiche l'ensemble des whitelist, need droit cableur """
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
white_list = Whitelist.objects.select_related('user').order_by('date_start')
|
white_list = Whitelist.objects.select_related('user')\
|
||||||
|
.order_by('date_start')
|
||||||
paginator = Paginator(white_list, pagination_number)
|
paginator = Paginator(white_list, pagination_number)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
try:
|
try:
|
||||||
|
@ -542,84 +634,106 @@ def index_white(request):
|
||||||
{'white_list': white_list}
|
{'white_list': white_list}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_school(request):
|
def index_school(request):
|
||||||
""" Affiche l'ensemble des établissement, need droit cableur """
|
""" Affiche l'ensemble des établissement, need droit cableur """
|
||||||
school_list = School.objects.order_by('name')
|
school_list = School.objects.order_by('name')
|
||||||
return render(request, 'users/index_schools.html', {'school_list':school_list})
|
return render(
|
||||||
|
request,
|
||||||
|
'users/index_schools.html',
|
||||||
|
{'school_list': school_list}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_listright(request):
|
def index_listright(request):
|
||||||
""" Affiche l'ensemble des droits , need droit cableur """
|
""" Affiche l'ensemble des droits , need droit cableur """
|
||||||
listright_list = ListRight.objects.order_by('listright')
|
listright_list = ListRight.objects.order_by('listright')
|
||||||
return render(request, 'users/index_listright.html', {'listright_list':listright_list})
|
return render(
|
||||||
|
request,
|
||||||
|
'users/index_listright.html',
|
||||||
|
{'listright_list': listright_list}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('cableur')
|
@permission_required('cableur')
|
||||||
def index_serviceusers(request):
|
def index_serviceusers(request):
|
||||||
""" Affiche les users de services (pour les accès ldap)"""
|
""" Affiche les users de services (pour les accès ldap)"""
|
||||||
serviceusers_list = ServiceUser.objects.order_by('pseudo')
|
serviceusers_list = ServiceUser.objects.order_by('pseudo')
|
||||||
return render(request, 'users/index_serviceusers.html', {'serviceusers_list':serviceusers_list})
|
return render(
|
||||||
|
request,
|
||||||
|
'users/index_serviceusers.html',
|
||||||
|
{'serviceusers_list': serviceusers_list}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def history(request, object, id):
|
def history(request, object_name, object_id):
|
||||||
""" Affichage de l'historique : (acl, argument)
|
""" Affichage de l'historique : (acl, argument)
|
||||||
user : self or cableur, userid,
|
user : self or cableur, userid,
|
||||||
ban : self or cableur, banid,
|
ban : self or cableur, banid,
|
||||||
whitelist : self or cableur, whitelistid,
|
whitelist : self or cableur, whitelistid,
|
||||||
school : cableur, schoolid,
|
school : cableur, schoolid,
|
||||||
listright : cableur, listrightid """
|
listright : cableur, listrightid """
|
||||||
if object == 'user':
|
if object_name == 'user':
|
||||||
try:
|
try:
|
||||||
object_instance = User.objects.get(pk=id)
|
object_instance = User.objects.get(pk=object_id)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
messages.error(request, "Utilisateur inexistant")
|
messages.error(request, "Utilisateur inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if not request.user.has_perms(('cableur',)) and object_instance != request.user:
|
if not request.user.has_perms(('cableur',)) and\
|
||||||
messages.error(request, "Vous ne pouvez pas afficher l'historique d'un autre user que vous sans droit cableur")
|
object_instance != request.user:
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
messages.error(request, "Vous ne pouvez pas afficher\
|
||||||
elif object == 'serviceuser' and request.user.has_perms(('cableur',)):
|
l'historique d'un autre user que vous sans droit cableur")
|
||||||
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
|
elif object_name == 'serviceuser' and request.user.has_perms(('cableur',)):
|
||||||
try:
|
try:
|
||||||
object_instance = ServiceUser.objects.get(pk=id)
|
object_instance = ServiceUser.objects.get(pk=object_id)
|
||||||
except ServiceUser.DoesNotExist:
|
except ServiceUser.DoesNotExist:
|
||||||
messages.error(request, "User service inexistant")
|
messages.error(request, "User service inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
elif object == 'ban':
|
elif object_name == 'ban':
|
||||||
try:
|
try:
|
||||||
object_instance = Ban.objects.get(pk=id)
|
object_instance = Ban.objects.get(pk=object_id)
|
||||||
except Ban.DoesNotExist:
|
except Ban.DoesNotExist:
|
||||||
messages.error(request, "Bannissement inexistant")
|
messages.error(request, "Bannissement inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if not request.user.has_perms(('cableur',)) and object_instance.user != request.user:
|
if not request.user.has_perms(('cableur',)) and\
|
||||||
messages.error(request, "Vous ne pouvez pas afficher les bans d'un autre user que vous sans droit cableur")
|
object_instance.user != request.user:
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
messages.error(request, "Vous ne pouvez pas afficher les bans\
|
||||||
elif object == 'whitelist':
|
d'un autre user que vous sans droit cableur")
|
||||||
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
|
elif object_name == 'whitelist':
|
||||||
try:
|
try:
|
||||||
object_instance = Whitelist.objects.get(pk=id)
|
object_instance = Whitelist.objects.get(pk=object_id)
|
||||||
except Whiltelist.DoesNotExist:
|
except Whitelist.DoesNotExist:
|
||||||
messages.error(request, "Whitelist inexistant")
|
messages.error(request, "Whitelist inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if not request.user.has_perms(('cableur',)) and object_instance.user != request.user:
|
if not request.user.has_perms(('cableur',)) and\
|
||||||
messages.error(request, "Vous ne pouvez pas afficher les whitelist d'un autre user que vous sans droit cableur")
|
object_instance.user != request.user:
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
messages.error(request, "Vous ne pouvez pas afficher les\
|
||||||
elif object == 'school' and request.user.has_perms(('cableur',)):
|
whitelist d'un autre user que vous sans droit cableur")
|
||||||
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
|
elif object_name == 'school' and request.user.has_perms(('cableur',)):
|
||||||
try:
|
try:
|
||||||
object_instance = School.objects.get(pk=id)
|
object_instance = School.objects.get(pk=object_id)
|
||||||
except School.DoesNotExist:
|
except School.DoesNotExist:
|
||||||
messages.error(request, "Ecole inexistante")
|
messages.error(request, "Ecole inexistante")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
elif object == 'listright' and request.user.has_perms(('cableur',)):
|
elif object_name == 'listright' and request.user.has_perms(('cableur',)):
|
||||||
try:
|
try:
|
||||||
object_instance = ListRight.objects.get(pk=id)
|
object_instance = ListRight.objects.get(pk=object_id)
|
||||||
except ListRight.DoesNotExist:
|
except ListRight.DoesNotExist:
|
||||||
messages.error(request, "Droit inexistant")
|
messages.error(request, "Droit inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Objet inconnu")
|
messages.error(request, "Objet inconnu")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
options, created = GeneralOption.objects.get_or_create()
|
options, _created = GeneralOption.objects.get_or_create()
|
||||||
pagination_number = options.pagination_number
|
pagination_number = options.pagination_number
|
||||||
reversions = Version.objects.get_for_object(object_instance)
|
reversions = Version.objects.get_for_object(object_instance)
|
||||||
paginator = Paginator(reversions, pagination_number)
|
paginator = Paginator(reversions, pagination_number)
|
||||||
|
@ -632,7 +746,11 @@ def history(request, object, id):
|
||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
# If page is out of range (e.g. 9999), deliver last page of results.
|
# If page is out of range (e.g. 9999), deliver last page of results.
|
||||||
reversions = paginator.page(paginator.num_pages)
|
reversions = paginator.page(paginator.num_pages)
|
||||||
return render(request, 're2o/history.html', {'reversions': reversions, 'object': object_instance})
|
return render(
|
||||||
|
request,
|
||||||
|
're2o/history.html',
|
||||||
|
{'reversions': reversions, 'object': object_instance}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -640,6 +758,7 @@ def mon_profil(request):
|
||||||
""" Lien vers profil, renvoie request.id à la fonction """
|
""" Lien vers profil, renvoie request.id à la fonction """
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def profil(request, userid):
|
def profil(request, userid):
|
||||||
""" Affiche un profil, self or cableur, prend un userid en argument """
|
""" Affiche un profil, self or cableur, prend un userid en argument """
|
||||||
|
@ -649,14 +768,19 @@ def profil(request, userid):
|
||||||
messages.error(request, "Utilisateur inexistant")
|
messages.error(request, "Utilisateur inexistant")
|
||||||
return redirect("/users/")
|
return redirect("/users/")
|
||||||
if not request.user.has_perms(('cableur',)) and users != request.user:
|
if not request.user.has_perms(('cableur',)) and users != request.user:
|
||||||
messages.error(request, "Vous ne pouvez pas afficher un autre user que vous sans droit cableur")
|
messages.error(request, "Vous ne pouvez pas afficher un autre user\
|
||||||
|
que vous sans droit cableur")
|
||||||
return redirect("/users/profil/" + str(request.user.id))
|
return redirect("/users/profil/" + str(request.user.id))
|
||||||
machines = Machine.objects.filter(user=users).select_related('user').prefetch_related('interface_set__domain__extension').prefetch_related('interface_set__ipv4__ip_type__extension').prefetch_related('interface_set__type').prefetch_related('interface_set__domain__related_domain__extension')
|
machines = Machine.objects.filter(user=users).select_related('user')\
|
||||||
|
.prefetch_related('interface_set__domain__extension')\
|
||||||
|
.prefetch_related('interface_set__ipv4__ip_type__extension')\
|
||||||
|
.prefetch_related('interface_set__type')\
|
||||||
|
.prefetch_related('interface_set__domain__related_domain__extension')
|
||||||
factures = Facture.objects.filter(user=users)
|
factures = Facture.objects.filter(user=users)
|
||||||
bans = Ban.objects.filter(user=users)
|
bans = Ban.objects.filter(user=users)
|
||||||
whitelists = Whitelist.objects.filter(user=users)
|
whitelists = Whitelist.objects.filter(user=users)
|
||||||
list_droits = Right.objects.filter(user=users)
|
list_droits = Right.objects.filter(user=users)
|
||||||
options, created = OptionalUser.objects.get_or_create()
|
options, _created = OptionalUser.objects.get_or_create()
|
||||||
user_solde = options.user_solde
|
user_solde = options.user_solde
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
|
@ -672,46 +796,56 @@ def profil(request, userid):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def reset_password(request):
|
def reset_password(request):
|
||||||
""" Reintialisation du mot de passe si mdp oublié """
|
""" Reintialisation du mot de passe si mdp oublié """
|
||||||
userform = ResetPasswordForm(request.POST or None)
|
userform = ResetPasswordForm(request.POST or None)
|
||||||
if userform.is_valid():
|
if userform.is_valid():
|
||||||
try:
|
try:
|
||||||
user = User.objects.get(pseudo=userform.cleaned_data['pseudo'],email=userform.cleaned_data['email'])
|
user = User.objects.get(
|
||||||
|
pseudo=userform.cleaned_data['pseudo'],
|
||||||
|
email=userform.cleaned_data['email']
|
||||||
|
)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
messages.error(request, "Cet utilisateur n'existe pas")
|
messages.error(request, "Cet utilisateur n'existe pas")
|
||||||
return form({'userform': userform}, 'users/user.html', request)
|
return form({'userform': userform}, 'users/user.html', request)
|
||||||
user.reset_passwd_mail(request)
|
user.reset_passwd_mail(request)
|
||||||
messages.success(request, "Un mail pour l'initialisation du mot de passe a été envoyé")
|
messages.success(request, "Un mail pour l'initialisation du mot\
|
||||||
|
de passe a été envoyé")
|
||||||
redirect("/")
|
redirect("/")
|
||||||
return form({'userform': userform}, 'users/user.html', request)
|
return form({'userform': userform}, 'users/user.html', request)
|
||||||
|
|
||||||
|
|
||||||
def process(request, token):
|
def process(request, token):
|
||||||
|
"""Process, lien pour la reinitialisation du mot de passe"""
|
||||||
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
|
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
|
||||||
req = get_object_or_404(valid_reqs, token=token)
|
req = get_object_or_404(valid_reqs, token=token)
|
||||||
|
|
||||||
if req.type == Request.PASSWD:
|
if req.type == Request.PASSWD:
|
||||||
return process_passwd(request, req)
|
return process_passwd(request, req)
|
||||||
elif req.type == Request.EMAIL:
|
|
||||||
return process_email(request, req=req)
|
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Entrée incorrecte, contactez un admin")
|
messages.error(request, "Entrée incorrecte, contactez un admin")
|
||||||
redirect("/")
|
redirect("/")
|
||||||
|
|
||||||
|
|
||||||
def process_passwd(request, req):
|
def process_passwd(request, req):
|
||||||
|
"""Process le changeemnt de mot de passe, renvoie le formulaire
|
||||||
|
demandant le nouveau password"""
|
||||||
u_form = PassForm(request.POST or None)
|
u_form = PassForm(request.POST or None)
|
||||||
user = req.user
|
user = req.user
|
||||||
if u_form.is_valid():
|
if u_form.is_valid():
|
||||||
return password_change_action(u_form, user, request, req=req)
|
return password_change_action(u_form, user, request, req=req)
|
||||||
return form({'userform': u_form}, 'users/user.html', request)
|
return form({'userform': u_form}, 'users/user.html', request)
|
||||||
""" Framework Rest """
|
|
||||||
|
|
||||||
class JSONResponse(HttpResponse):
|
class JSONResponse(HttpResponse):
|
||||||
|
""" Framework Rest """
|
||||||
def __init__(self, data, **kwargs):
|
def __init__(self, data, **kwargs):
|
||||||
content = JSONRenderer().render(data)
|
content = JSONRenderer().render(data)
|
||||||
kwargs['content_type'] = 'application/json'
|
kwargs['content_type'] = 'application/json'
|
||||||
super(JSONResponse, self).__init__(content, **kwargs)
|
super(JSONResponse, self).__init__(content, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@login_required
|
@login_required
|
||||||
@permission_required('serveur')
|
@permission_required('serveur')
|
||||||
|
@ -721,4 +855,3 @@ def mailing(request):
|
||||||
mails = all_has_access().values('email').distinct()
|
mails = all_has_access().values('email').distinct()
|
||||||
seria = MailSerializer(mails, many=True)
|
seria = MailSerializer(mails, many=True)
|
||||||
return JSONResponse(seria.data)
|
return JSONResponse(seria.data)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue