8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-26 00:43:46 +00:00

Merge branch 'master' into massive_use_bft_tag

This commit is contained in:
Maël Kervella 2017-10-15 15:05:40 +00:00
commit 25d460cb91
19 changed files with 1719 additions and 619 deletions

View file

@ -19,7 +19,10 @@
# 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.
"""
Urls de l'application logs, pointe vers les fonctions de views.
Inclu dans le re2o.urls
"""
from __future__ import unicode_literals
from django.conf.urls import url
@ -29,7 +32,9 @@ from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
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_models/$', views.stats_models, name='stats-models'),
url(r'^stats_users/$', views.stats_users, name='stats-users'),

View file

@ -23,62 +23,67 @@
# App de gestion des statistiques pour re2o
# Gabriel Détraz
# 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 django.http import HttpResponse
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.template import Context, RequestContext, loader
from django.contrib import messages
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 reversion.models import Revision
from reversion.models import Version, ContentType
from users.models import User, ServiceUser, Right, School, ListRight, ListShell, Ban, Whitelist
from users.models import all_has_access, all_whitelisted, all_baned, all_adherent
from cotisations.models import Facture, Vente, Article, Banque, Paiement, Cotisation
from machines.models import Machine, MachineType, IpType, Extension, Interface, Domain, IpList
from machines.views import all_active_assigned_interfaces_count, all_active_interfaces_count
from users.models import User, ServiceUser, Right, School, ListRight, ListShell
from users.models import Ban, Whitelist
from cotisations.models import Facture, Vente, Article, Banque, Paiement
from cotisations.models import Cotisation
from machines.models import Machine, MachineType, IpType, Extension, Interface
from machines.models import Domain, IpList
from topologie.models import Switch, Port, Room
from preferences.models import GeneralOption
from django.utils import timezone
from dateutil.relativedelta import relativedelta
from re2o.views import form
from re2o.utils import all_whitelisted, all_baned, all_has_access, all_adherent
from re2o.utils import all_active_assigned_interfaces_count
from re2o.utils import all_active_interfaces_count
STATS_DICT = {
0 : ["Tout", 36],
1 : ["1 mois", 1],
2 : ["2 mois", 2],
3 : ["6 mois", 6],
4 : ["1 an", 12],
5 : ["2 an", 24],
0: ["Tout", 36],
1: ["1 mois", 1],
2: ["2 mois", 2],
3: ["6 mois", 6],
4: ["1 an", 12],
5: ["2 an", 24],
}
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
@login_required
@permission_required('cableur')
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
# The types of content kept for display
content_type_filter = ['ban', 'whitelist', 'vente', 'interface', 'user']
# 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)
page = request.GET.get('page')
try:
@ -95,30 +100,38 @@ def index(request):
# Items to remove later because invalid
to_remove = []
# Parse every item (max = pagination_number)
for i in range( len( versions.object_list ) ):
if versions.object_list[i].object :
v = versions.object_list[i]
for i in range(len(versions.object_list)):
if versions.object_list[i].object:
version = versions.object_list[i]
versions.object_list[i] = {
'rev_id' : v.revision.id,
'comment': v.revision.comment,
'datetime': v.revision.date_created.strftime('%d/%m/%y %H:%M:%S'),
'username': v.revision.user.get_username() if v.revision.user else '?',
'user_id': v.revision.user_id,
'version': v }
else :
to_remove.insert(0,i)
'rev_id': version.revision.id,
'comment': version.revision.comment,
'datetime': version.revision.date_created.strftime(
'%d/%m/%y %H:%M:%S'
),
'username':
version.revision.user.get_username()
if version.revision.user else '?',
'user_id': version.revision.user_id,
'version': version}
else:
to_remove.insert(0, i)
# Remove all tagged invalid items
for i in to_remove :
for i in to_remove:
versions.object_list.pop(i)
return render(request, 'logs/index.html', {'versions_list': versions})
@login_required
@permission_required('cableur')
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
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)
page = request.GET.get('page')
try:
@ -129,7 +142,10 @@ def stats_logs(request):
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
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
@permission_required('bureau')
@ -138,36 +154,64 @@ def revert_action(request, revision_id):
try:
revision = Revision.objects.get(id=revision_id)
except Revision.DoesNotExist:
messages.error(request, u"Revision inexistante" )
messages.error(request, u"Revision inexistante")
if request.method == "POST":
revision.revert()
messages.success(request, "L'action a été supprimée")
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
@permission_required('cableur')
def stats_general(request):
all_active_users = User.objects.filter(state=User.STATE_ACTIVE)
ip = dict()
"""Statistiques générales affinées sur les ip, activées, utilisées par
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():
all_ip = IpList.objects.filter(ip_type=ip_range)
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()
ip[ip_range] = [ip_range, all_ip.count(), used_ip, active_ip, all_ip.count()-used_ip]
active_ip = all_active_assigned_interfaces_count().filter(
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 = [
[["Categorie", "Nombre d'utilisateurs"], {
'active_users' : ["Users actifs", User.objects.filter(state=User.STATE_ACTIVE).count()],
'inactive_users' : ["Users désactivés", User.objects.filter(state=User.STATE_DISABLED).count()],
'archive_users' : ["Users archivés", User.objects.filter(state=User.STATE_ARCHIVE).count()],
'adherent_users' : ["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()]
'active_users': [
"Users actifs",
User.objects.filter(state=User.STATE_ACTIVE).count()],
'inactive_users': [
"Users désactivés",
User.objects.filter(state=User.STATE_DISABLED).count()],
'archive_users': [
"Users archivés",
User.objects.filter(state=User.STATE_ARCHIVE).count()],
'adherent_users': [
"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]
[["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})
@ -175,84 +219,117 @@ def stats_general(request):
@login_required
@permission_required('cableur')
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 = {
'Users' : {
'users' : [User.PRETTY_NAME, User.objects.count()],
'serviceuser' : [ServiceUser.PRETTY_NAME, ServiceUser.objects.count()],
'right' : [Right.PRETTY_NAME, Right.objects.count()],
'school' : [School.PRETTY_NAME, School.objects.count()],
'listright' : [ListRight.PRETTY_NAME, ListRight.objects.count()],
'listshell' : [ListShell.PRETTY_NAME, ListShell.objects.count()],
'ban' : [Ban.PRETTY_NAME, Ban.objects.count()],
'whitelist' : [Whitelist.PRETTY_NAME, Whitelist.objects.count()]
'Users': {
'users': [User.PRETTY_NAME, User.objects.count()],
'serviceuser': [ServiceUser.PRETTY_NAME,
ServiceUser.objects.count()],
'right': [Right.PRETTY_NAME, Right.objects.count()],
'school': [School.PRETTY_NAME, School.objects.count()],
'listright': [ListRight.PRETTY_NAME, ListRight.objects.count()],
'listshell': [ListShell.PRETTY_NAME, ListShell.objects.count()],
'ban': [Ban.PRETTY_NAME, Ban.objects.count()],
'whitelist': [Whitelist.PRETTY_NAME, Whitelist.objects.count()]
},
'Cotisations' : {
'factures' : [Facture.PRETTY_NAME, Facture.objects.count()],
'vente' : [Vente.PRETTY_NAME, Vente.objects.count()],
'cotisation' : [Cotisation.PRETTY_NAME, Cotisation.objects.count()],
'article' : [Article.PRETTY_NAME, Article.objects.count()],
'banque' : [Banque.PRETTY_NAME, Banque.objects.count()],
'cotisation' : [Cotisation.PRETTY_NAME, Cotisation.objects.count()],
'Cotisations': {
'factures': [Facture.PRETTY_NAME, Facture.objects.count()],
'vente': [Vente.PRETTY_NAME, Vente.objects.count()],
'cotisation': [Cotisation.PRETTY_NAME, Cotisation.objects.count()],
'article': [Article.PRETTY_NAME, Article.objects.count()],
'banque': [Banque.PRETTY_NAME, Banque.objects.count()],
},
'Machines' : {
'machine' : [Machine.PRETTY_NAME, Machine.objects.count()],
'typemachine' : [MachineType.PRETTY_NAME, MachineType.objects.count()],
'typeip' : [IpType.PRETTY_NAME, IpType.objects.count()],
'extension' : [Extension.PRETTY_NAME, Extension.objects.count()],
'interface' : [Interface.PRETTY_NAME, Interface.objects.count()],
'alias' : [Domain.PRETTY_NAME, Domain.objects.exclude(cname=None).count()],
'iplist' : [IpList.PRETTY_NAME, IpList.objects.count()],
'Machines': {
'machine': [Machine.PRETTY_NAME, Machine.objects.count()],
'typemachine': [MachineType.PRETTY_NAME,
MachineType.objects.count()],
'typeip': [IpType.PRETTY_NAME, IpType.objects.count()],
'extension': [Extension.PRETTY_NAME, Extension.objects.count()],
'interface': [Interface.PRETTY_NAME, Interface.objects.count()],
'alias': [Domain.PRETTY_NAME,
Domain.objects.exclude(cname=None).count()],
'iplist': [IpList.PRETTY_NAME, IpList.objects.count()],
},
'Topologie' : {
'switch' : [Switch.PRETTY_NAME, Switch.objects.count()],
'port' : [Port.PRETTY_NAME, Port.objects.count()],
'chambre' : [Room.PRETTY_NAME, Room.objects.count()],
'Topologie': {
'switch': [Switch.PRETTY_NAME, Switch.objects.count()],
'port': [Port.PRETTY_NAME, Port.objects.count()],
'chambre': [Room.PRETTY_NAME, Room.objects.count()],
},
'Actions effectuées sur la base' :
'Actions effectuées sur la base':
{
'revision' : ["Nombre d'actions", Revision.objects.count()],
'revision': ["Nombre d'actions", Revision.objects.count()],
},
}
return render(request, 'logs/stats_models.html', {'stats_list': stats})
@login_required
@permission_required('cableur')
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')
try:
search_field = STATS_DICT[onglet]
except:
search_field = STATS_DICT[0]
_search_field = STATS_DICT[onglet]
except KeyError:
_search_field = STATS_DICT[0]
onglet = 0
start_date = timezone.now() + relativedelta(months=-search_field[1])
stats = {
'Utilisateur' : {
'Machines' : User.objects.annotate(num=Count('machine')).order_by('-num')[:10],
'Facture' : User.objects.annotate(num=Count('facture')).order_by('-num')[:10],
'Bannissement' : User.objects.annotate(num=Count('ban')).order_by('-num')[:10],
'Accès gracieux' : User.objects.annotate(num=Count('whitelist')).order_by('-num')[:10],
'Droits' : User.objects.annotate(num=Count('right')).order_by('-num')[:10],
'Utilisateur': {
'Machines': User.objects.annotate(
num=Count('machine')
).order_by('-num')[:10],
'Facture': User.objects.annotate(
num=Count('facture')
).order_by('-num')[:10],
'Bannissement': User.objects.annotate(
num=Count('ban')
).order_by('-num')[:10],
'Accès gracieux': User.objects.annotate(
num=Count('whitelist')
).order_by('-num')[:10],
'Droits': User.objects.annotate(
num=Count('right')
).order_by('-num')[:10],
},
'Etablissement' : {
'Utilisateur' : School.objects.annotate(num=Count('user')).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],
'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],
'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
@permission_required('cableur')
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 = {
'Utilisateur' : {
'Action' : User.objects.annotate(num=Count('revision')).order_by('-num')[:40],
'Utilisateur': {
'Action': User.objects.annotate(
num=Count('revision')
).order_by('-num')[:40],
},
}
return render(request, 'logs/stats_users.html', {'stats_list': stats})

View file

@ -53,30 +53,10 @@ from .forms import EditIpTypeForm, IpTypeForm, DelIpTypeForm, DomainForm, AliasF
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 users.models import User
from users.models import all_has_access
from preferences.models import GeneralOption, OptionalMachine
from re2o.templatetags.massive_bootstrap_form import hidden_id, input_id
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)
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
from re2o.utils import all_active_assigned_interfaces, all_has_access
from re2o.views import form
def f_type_id( is_type_tt ):
""" The id that will be used in HTML to store the value of the field

View file

@ -20,35 +20,53 @@
# 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.
"""
Classes admin pour les models de preferences
"""
from __future__ import unicode_literals
from django.contrib import admin
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 admin options user"""
pass
class OptionalTopologieAdmin(VersionAdmin):
"""Class admin options topologie"""
pass
class OptionalMachineAdmin(VersionAdmin):
"""Class admin options machines"""
pass
class GeneralOptionAdmin(VersionAdmin):
"""Class admin options générales"""
pass
class ServiceAdmin(VersionAdmin):
"""Class admin gestion des services de la page d'accueil"""
pass
class AssoOptionAdmin(VersionAdmin):
"""Class admin options de l'asso"""
pass
class MailMessageOptionAdmin(VersionAdmin):
"""Class admin options mail"""
pass
admin.site.register(OptionalUser, OptionalUserAdmin)
admin.site.register(OptionalMachine, OptionalMachineAdmin)
admin.site.register(OptionalTopologie, OptionalTopologieAdmin)

View file

@ -19,71 +19,116 @@
# 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.
"""
Formulaire d'edition des réglages : user, machine, topologie, asso...
"""
from __future__ import unicode_literals
from django.forms import ModelForm, Form, ValidationError
from django.forms import ModelForm, Form
from django import forms
from .models import OptionalUser, OptionalMachine, OptionalTopologie, GeneralOption, AssoOption, MailMessageOption, Service
from django.db.models import Q
from .models import OptionalUser, OptionalMachine, OptionalTopologie
from .models import GeneralOption, AssoOption, MailMessageOption, Service
class EditOptionalUserForm(ModelForm):
"""Formulaire d'édition des options de l'user. (solde, telephone..)"""
class Meta:
model = OptionalUser
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditOptionalUserForm, self).__init__(*args, 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'
super(EditOptionalUserForm, self).__init__(
*args,
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):
"""Options machines (max de machines, etc)"""
class Meta:
model = OptionalMachine
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditOptionalMachineForm, self).__init__(*args, prefix=prefix, **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"
super(EditOptionalMachineForm, self).__init__(
*args,
prefix=prefix,
**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):
"""Options de topologie, formulaire d'edition (vlan par default etc)"""
class Meta:
model = OptionalTopologie
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditOptionalTopologieForm, self).__init__(*args, 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"
super(EditOptionalTopologieForm, self).__init__(
*args,
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):
"""Options générales (affichages de résultats de recherche, etc)"""
class Meta:
model = GeneralOption
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditGeneralOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
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)'
super(EditGeneralOptionForm, self).__init__(
*args,
prefix=prefix,
**kwargs
)
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['email_from'].label = 'Adresse mail d\'expedition automatique'
self.fields['email_from'].label = "Adresse mail d\
'expedition automatique"
class EditAssoOptionForm(ModelForm):
"""Options de l'asso (addresse, telephone, etc)"""
class Meta:
model = AssoOption
fields = '__all__'
def __init__(self, *args, **kwargs):
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['siret'].label = 'SIRET'
self.fields['adresse1'].label = 'Adresse (ligne 1)'
@ -91,20 +136,31 @@ class EditAssoOptionForm(ModelForm):
self.fields['contact'].label = 'Email de contact'
self.fields['telephone'].label = 'Numéro de téléphone'
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):
"""Formulaire d'edition des messages de bienvenue personnalisés"""
class Meta:
model = MailMessageOption
fields = '__all__'
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(EditMailMessageOptionForm, self).__init__(*args, 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'
super(EditMailMessageOptionForm, self).__init__(
*args,
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):
"""Edition, ajout de services sur la page d'accueil"""
class Meta:
model = Service
fields = '__all__'
@ -113,6 +169,11 @@ class ServiceForm(ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
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
)

View file

@ -20,26 +20,38 @@
# 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.
"""
Reglages généraux, machines, utilisateurs, mail, general pour l'application.
"""
from __future__ import unicode_literals
from django.db import models
from cotisations.models import Paiement
from machines.models import Vlan
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"
is_tel_mandatory = models.BooleanField(default=True)
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)
def clean(self):
"""Creation du mode de paiement par solde"""
if self.user_solde:
Paiement.objects.get_or_create(moyen="Solde")
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"
password_machine = models.BooleanField(default=False)
@ -47,21 +59,43 @@ class OptionalMachine(models.Model):
max_lambdauser_aliases = models.IntegerField(default=10)
ipv6 = models.BooleanField(default=False)
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"
MACHINE = 'MACHINE'
DEFINED = 'DEFINED'
CHOICE_RADIUS = (
(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):
"""Options générales : nombre de resultats par page, nom du site,
temps les liens sont valides"""
PRETTY_NAME = "Options générales"
search_display_page = models.IntegerField(default=15)
@ -71,7 +105,10 @@ class GeneralOption(models.Model):
site_name = models.CharField(max_length=32, default="Re2o")
email_from = models.EmailField(default="www-data@serveur.net")
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)
url = models.URLField()
description = models.TextField()
@ -80,21 +117,32 @@ class Service(models.Model):
def __str__(self):
return str(self.name)
class AssoOption(models.Model):
"""Options générales de l'asso : siret, addresse, nom, etc"""
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)
adresse1 = models.CharField(default="1 Rue de exemple", max_length=128)
adresse2 = models.CharField(default="94230 Cachan", max_length=128)
contact = models.EmailField(default="contact@example.org")
telephone = models.CharField(max_length=15, default="0000000000")
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):
"""Reglages, mail de bienvenue et autre"""
PRETTY_NAME = "Options de corps de mail"
welcome_mail_fr = models.TextField(default="")
welcome_mail_en = models.TextField(default="")

View file

@ -19,6 +19,9 @@
# 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.
"""
Urls de l'application preferences, pointant vers les fonctions de views
"""
from __future__ import unicode_literals
@ -28,15 +31,47 @@ from . import views
urlpatterns = [
url(r'^edit_options/(?P<section>OptionalUser)$', 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'^edit_options/(?P<section>OptionalUser)$',
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'^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'^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'),
]

View file

@ -23,48 +23,53 @@
# App de gestion des machines pour re2o
# Gabriel Détraz, Augustin Lemesle
# Gplv2
"""
Vue d'affichage, et de modification des réglages (réglages machine,
topologie, users, service...)
"""
from __future__ import unicode_literals
from django.shortcuts import render
from django.shortcuts import get_object_or_404, render, redirect
from django.template.context_processors import csrf
from django.shortcuts import render, redirect
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.template import Context, RequestContext, loader
from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.db.models import Max, 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.models import ProtectedError
from django.db import transaction
from reversion.models import Version
from reversion import revisions as reversion
from re2o.views import form
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 forms
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
@login_required
@permission_required('cableur')
def display_options(request):
useroptions, created = OptionalUser.objects.get_or_create()
machineoptions, created = OptionalMachine.objects.get_or_create()
topologieoptions, created = OptionalTopologie.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()
"""Vue pour affichage des options (en vrac) classé selon les models
correspondants dans un tableau"""
useroptions, _created = OptionalUser.objects.get_or_create()
machineoptions, _created = OptionalMachine.objects.get_or_create()
topologieoptions, _created = OptionalTopologie.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()
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
@permission_required('admin')
@ -73,23 +78,36 @@ def edit_options(request, section):
model = getattr(models, section, None)
form_instance = getattr(forms, 'Edit' + section + 'Form', None)
if model and form:
options_instance, created = model.objects.get_or_create()
options = form_instance(request.POST or None, instance=options_instance)
options_instance, _created = model.objects.get_or_create()
options = form_instance(
request.POST or None,
instance=options_instance
)
if options.is_valid():
with transaction.atomic(), reversion.create_revision():
options.save()
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")
return redirect("/preferences/")
return form({'options': options}, 'preferences/edit_preferences.html', request)
return form(
{'options': options},
'preferences/edit_preferences.html',
request
)
else:
messages.error(request, "Objet inconnu")
return redirect("/preferences/")
@login_required
@permission_required('admin')
def add_services(request):
"""Ajout d'un service de la page d'accueil"""
services = ServiceForm(request.POST or None)
if services.is_valid():
with transaction.atomic(), reversion.create_revision():
@ -98,29 +116,45 @@ def add_services(request):
reversion.set_comment("Création")
messages.success(request, "Cet enregistrement ns a été ajouté")
return redirect("/preferences/")
return form({'preferenceform': services}, 'preferences/preferences.html', request)
return form(
{'preferenceform': services},
'preferences/preferences.html',
request
)
@login_required
@permission_required('admin')
def edit_services(request, servicesid):
"""Edition des services affichés sur la page d'accueil"""
try:
services_instance = Service.objects.get(pk=servicesid)
except Service.DoesNotExist:
messages.error(request, u"Entrée inexistante" )
messages.error(request, u"Entrée inexistante")
return redirect("/preferences/")
services = ServiceForm(request.POST or None, instance=services_instance)
if services.is_valid():
with transaction.atomic(), reversion.create_revision():
services.save()
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é")
return redirect("/preferences/")
return form({'preferenceform': services}, 'preferences/preferences.html', request)
return form(
{'preferenceform': services},
'preferences/preferences.html',
request
)
@login_required
@permission_required('admin')
def del_services(request):
"""Suppression d'un service de la page d'accueil"""
services = DelServiceForm(request.POST or None)
if services.is_valid():
services_dels = services.cleaned_data['services']
@ -131,20 +165,28 @@ def del_services(request):
reversion.set_user(request.user)
messages.success(request, "Le services a été supprimée")
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 form({'preferenceform': services}, 'preferences/preferences.html', request)
return form(
{'preferenceform': services},
'preferences/preferences.html',
request
)
@login_required
@permission_required('cableur')
def history(request, object, id):
if object == 'service':
def history(request, object_name, object_id):
"""Historique de creation et de modification d'un service affiché sur
la page d'accueil"""
if object_name == 'service':
try:
object_instance = Service.objects.get(pk=id)
object_instance = Service.objects.get(pk=object_id)
except Service.DoesNotExist:
messages.error(request, "Service inexistant")
return redirect("/preferences/")
options, created = GeneralOption.objects.get_or_create()
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
reversions = Version.objects.get_for_object(object_instance)
paginator = Paginator(reversions, pagination_number)
@ -157,4 +199,7 @@ def history(request, object, id):
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
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
})

View file

@ -19,15 +19,19 @@
# 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.
"""Fonction de context, variables renvoyées à toutes les vues"""
from __future__ import unicode_literals
from machines.models import Interface, Machine
from preferences.models import GeneralOption, OptionalMachine
def context_user(request):
general_options, created = GeneralOption.objects.get_or_create()
machine_options, created = OptionalMachine.objects.get_or_create()
"""Fonction de context lorsqu'un user est logué (ou non),
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
if user.is_authenticated():
interfaces = user.user_interfaces()
@ -52,8 +56,8 @@ def context_user(request):
'is_bofh': is_bofh,
'is_trez': is_trez,
'is_infra': is_infra,
'is_admin' : is_admin,
'is_admin': is_admin,
'interfaces': interfaces,
'site_name': general_options.site_name,
'ipv6_enabled' : machine_options.ipv6,
'ipv6_enabled': machine_options.ipv6,
}

View file

@ -49,10 +49,16 @@ urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^users/', include('users.urls', namespace='users')),
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'^topologie/', include('topologie.urls', namespace='topologie')),
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
View 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)

View file

@ -19,25 +19,28 @@
# 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.
"""
Fonctions de la page d'accueil et diverses fonctions utiles pour tous
les views
"""
from __future__ import unicode_literals
from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.template.context_processors import csrf
from django.template import Context, RequestContext, loader
from preferences.models import Service
def form(ctx, template, request):
"""Form générique, raccourci importé par les fonctions views du site"""
context = ctx
context.update(csrf(request))
return render(request, template, context)
def index(request):
i = 0
"""Affiche la liste des services sur la page d'accueil de re2o"""
services = [[], [], []]
for indice, serv in enumerate(Service.objects.all()):
services[indice % 3].append(serv)
return form({'services_urls': services}, 're2o/index.html', request)

View file

@ -32,9 +32,10 @@ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
from __future__ import unicode_literals
import os
from django.core.wsgi import get_wsgi_application
from os.path import dirname
import sys
from os.path import dirname
from django.core.wsgi import get_wsgi_application
sys.path.append(dirname(dirname(__file__)))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")

View file

@ -381,8 +381,20 @@ def new_switch(request):
reversion.set_comment("Création")
messages.success(request, "Le switch a été créé")
return redirect("/topologie/")
<<<<<<< HEAD
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)
=======
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
@permission_required('infra')
@ -442,8 +454,20 @@ def edit_switch(request, switch_id):
)
messages.success(request, "Le switch a bien été modifié")
return redirect("/topologie/")
<<<<<<< HEAD
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)
=======
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
@permission_required('infra')

View file

@ -20,6 +20,10 @@
# 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.
"""
Definition des vues pour les admin. Classique, sauf pour users,
on fait appel à UserChange et ServiceUserChange, forms custom
"""
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 reversion.admin import VersionAdmin
from .models import User, ServiceUser, School, Right, ListRight, ListShell, Ban, Whitelist, Request, LdapUser, LdapServiceUser, LdapServiceUserGroup, LdapUserGroup
from .forms import UserChangeForm, UserCreationForm, ServiceUserChangeForm, ServiceUserCreationForm
from .models import User, ServiceUser, School, Right, ListRight, ListShell
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):
"""Administration d'un user"""
list_display = (
'name',
'surname',
@ -43,51 +51,73 @@ class UserAdmin(admin.ModelAdmin):
'shell',
'state'
)
search_fields = ('name','surname','pseudo','room')
search_fields = ('name', 'surname', 'pseudo', 'room')
class LdapUserAdmin(admin.ModelAdmin):
list_display = ('name','uidNumber','login_shell')
exclude = ('user_password','sambat_nt_password')
"""Administration du ldapuser"""
list_display = ('name', 'uidNumber', 'login_shell')
exclude = ('user_password', 'sambat_nt_password')
search_fields = ('name',)
class LdapServiceUserAdmin(admin.ModelAdmin):
"""Administration du ldapserviceuser"""
list_display = ('name',)
exclude = ('user_password',)
search_fields = ('name',)
class LdapUserGroupAdmin(admin.ModelAdmin):
list_display = ('name','members','gid')
"""Administration du ldapusergroupe"""
list_display = ('name', 'members', 'gid')
search_fields = ('name',)
class LdapServiceUserGroupAdmin(admin.ModelAdmin):
"""Administration du ldap serviceusergroup"""
list_display = ('name',)
search_fields = ('name',)
class SchoolAdmin(VersionAdmin):
list_display = ('name',)
"""Administration, gestion des écoles"""
pass
class ListRightAdmin(VersionAdmin):
"""Gestion de la liste des droits existants
Ne permet pas l'edition du gid (primarykey pour ldap)"""
list_display = ('listright',)
class ListShellAdmin(VersionAdmin):
list_display = ('shell',)
"""Gestion de la liste des shells coté admin"""
pass
class RightAdmin(VersionAdmin):
list_display = ('user', 'right')
"""Gestion de la liste des droits affectés"""
pass
class RequestAdmin(admin.ModelAdmin):
"""Gestion des request objet, ticket pour lien de reinit mot de passe"""
list_display = ('user', 'type', 'created_at', 'expires_at')
class BanAdmin(VersionAdmin):
list_display = ('user', 'raison', 'date_start', 'date_end')
"""Gestion des bannissements"""
pass
class WhitelistAdmin(VersionAdmin):
list_display = ('user', 'raison', 'date_start', 'date_end')
"""Gestion des whitelist"""
pass
class UserAdmin(VersionAdmin, BaseUserAdmin):
"""Gestion d'un user : modification des champs perso, mot de passe, etc"""
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
@ -95,27 +125,56 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# 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_filter = ()
fieldsets = (
(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', )}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
(
None,
{
'classes': ('wide',),
'fields': ('pseudo', 'name', 'surname', 'email', 'school', 'is_admin', 'password1', 'password2')}
'fields': (
'pseudo',
'name',
'surname',
'email',
'school',
'is_admin',
'password1',
'password2'
)
}
),
)
search_fields = ('pseudo',)
ordering = ('pseudo',)
filter_horizontal = ()
class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
"""Gestion d'un service user admin : champs personnels,
mot de passe; etc"""
# The forms to add and change user instances
form = ServiceUserChangeForm
add_form = ServiceUserCreationForm
@ -131,15 +190,19 @@ class ServiceUserAdmin(VersionAdmin, BaseUserAdmin):
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
(
None,
{
'classes': ('wide',),
'fields': ('pseudo', 'password1', 'password2')}
'fields': ('pseudo', 'password1', 'password2')
}
),
)
search_fields = ('pseudo',)
ordering = ('pseudo',)
filter_horizontal = ()
admin.site.register(User, UserAdmin)
admin.site.register(ServiceUser, ServiceUserAdmin)
admin.site.register(LdapUser, LdapUserAdmin)

View file

@ -20,8 +20,16 @@
# 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.
"""
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
@ -29,17 +37,34 @@ from django import forms
from django.forms import ModelForm, Form
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.validators import MinLengthValidator
from preferences.models import OptionalUser
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):
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)
"""Formulaire de changement de mot de passe. Verifie que les 2
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):
"""Verifie que passwd1 et 2 sont identiques"""
# Check that the two password entries match
password1 = self.cleaned_data.get("passwd1")
password2 = self.cleaned_data.get("passwd2")
@ -47,11 +72,26 @@ class PassForm(forms.Form):
raise forms.ValidationError("Passwords don't match")
return password2
class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
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)
fields, plus a repeated password.
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')
def __init__(self, *args, **kwargs):
@ -63,6 +103,7 @@ class UserCreationForm(forms.ModelForm):
fields = ('pseudo', 'name', 'surname', 'email')
def clean_password2(self):
"""Verifie que password1 et 2 sont identiques"""
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
@ -78,21 +119,40 @@ class UserCreationForm(forms.ModelForm):
user.is_admin = self.cleaned_data.get("is_admin")
return user
class ServiceUserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
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)
fields, plus a repeated password.
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):
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:
model = ServiceUser
fields = ('pseudo',)
def clean_password2(self):
"""Verifie que password1 et 2 sont indentiques"""
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
@ -107,10 +167,13 @@ class ServiceUserCreationForm(forms.ModelForm):
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
Formulaire pour la modification d'un user coté admin
"""
password = ReadOnlyPasswordHashField()
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
def clean_password(self):
"""Dummy fun"""
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
@ -139,42 +203,59 @@ class UserChangeForm(forms.ModelForm):
user.save()
return user
class ServiceUserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
Formulaire pour l'edition des service users coté admin
"""
password = ReadOnlyPasswordHashField()
def __init__(self, *args, **kwargs):
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:
model = ServiceUser
fields = ('pseudo',)
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
"""Dummy fun"""
return self.initial["password"]
class ResetPasswordForm(forms.Form):
"""Formulaire de demande de reinitialisation de mot de passe,
mdp oublié"""
pseudo = forms.CharField(label=u'Pseudo', max_length=255)
email = forms.EmailField(max_length=255)
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')
def clean(self):
cleaned_data=super(MassArchiveForm, self).clean()
cleaned_data = super(MassArchiveForm, self).clean()
date = cleaned_data.get("date")
if date:
if date>timezone.now():
raise forms.ValidationError("Impossible d'archiver des utilisateurs dont la fin d'accès se situe dans le futur !")
if date > NOW:
raise forms.ValidationError("Impossible d'archiver des\
utilisateurs dont la fin d'accès se situe dans le futur !")
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):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(BaseInfoForm, self).__init__(*args, prefix=prefix, **kwargs)
@ -200,13 +281,21 @@ class BaseInfoForm(ModelForm):
]
def clean_telephone(self):
"""Verifie que le tel est présent si 'option est validée
dans preferences"""
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:
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
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):
fields = [
'name',
@ -220,22 +309,33 @@ class EditInfoForm(BaseInfoForm):
'telephone',
]
class InfoForm(EditInfoForm):
""" 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)
""" Utile pour forcer un déménagement quand il y a déjà un user en place
Formuaire utilisé pour la creation initiale"""
force = forms.BooleanField(
label="Forcer le déménagement ?",
initial=False,
required=False
)
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):
remove_user_room(self.cleaned_data.get('room'))
return
class UserForm(InfoForm):
""" Model form general"""
class Meta(InfoForm.Meta):
fields = '__all__'
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:
model = User
fields = ['password', 'pwd_ntlm']
@ -244,21 +344,32 @@ class PasswordForm(ModelForm):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(PasswordForm, self).__init__(*args, prefix=prefix, **kwargs)
class ServiceUserForm(ModelForm):
""" 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:
model = ServiceUser
fields = ('pseudo','access_group')
fields = ('pseudo', 'access_group')
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ServiceUserForm, self).__init__(*args, prefix=prefix, **kwargs)
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):
fields = ['access_group','comment']
fields = ['access_group', 'comment']
class StateForm(ModelForm):
""" Changement de l'état d'un user"""
@ -272,6 +383,7 @@ class StateForm(ModelForm):
class SchoolForm(ModelForm):
"""Edition, creation d'un école"""
class Meta:
model = School
fields = ['name']
@ -281,7 +393,10 @@ class SchoolForm(ModelForm):
super(SchoolForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = 'Établissement'
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:
model = ListRight
fields = ['listright', 'details']
@ -291,21 +406,38 @@ class ListRightForm(ModelForm):
super(ListRightForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['listright'].label = 'Nom du droit/groupe'
class NewListRightForm(ListRightForm):
"""Ajout d'un groupe/list de droit """
class Meta(ListRightForm.Meta):
fields = '__all__'
def __init__(self, *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):
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):
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):
"""Assignation d'un droit à un user"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(RightForm, self).__init__(*args, prefix=prefix, **kwargs)
@ -318,13 +450,19 @@ class RightForm(ModelForm):
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):
super(DelRightForm, self).__init__(*args, **kwargs)
self.fields['rights'].queryset = Right.objects.filter(right=right)
class BanForm(ModelForm):
"""Creation, edition d'un objet bannissement"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(BanForm, self).__init__(*args, prefix=prefix, **kwargs)
@ -335,13 +473,16 @@ class BanForm(ModelForm):
exclude = ['user']
def clean_date_end(self):
"""Verification que date_end est après now"""
date_end = self.cleaned_data['date_end']
if date_end < timezone.now():
raise forms.ValidationError("Triple buse, la date de fin ne peut pas être avant maintenant... Re2o ne voyage pas dans le temps")
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")
return date_end
class WhitelistForm(ModelForm):
"""Creation, edition d'un objet whitelist"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(WhitelistForm, self).__init__(*args, prefix=prefix, **kwargs)
@ -352,7 +493,9 @@ class WhitelistForm(ModelForm):
exclude = ['user']
def clean_date_end(self):
"""Verification que la date_end est posterieur à now"""
date_end = self.cleaned_data['date_end']
if date_end < timezone.now():
raise forms.ValidationError("Triple buse, la date de fin ne peut pas être avant maintenant... Re2o ne voyage pas dans le temps")
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")
return date_end

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,9 @@
# 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.
"""
Definition des urls, pointant vers les views
"""
from __future__ import unicode_literals
@ -32,39 +35,88 @@ urlpatterns = [
url(r'^state/(?P<userid>[0-9]+)$', views.state, name='state'),
url(r'^password/(?P<userid>[0-9]+)$', views.password, name='password'),
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(r'^del_serviceuser/(?P<userid>[0-9]+)$', views.del_serviceuser, name='del-serviceuser'),
url(
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'^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(r'^edit_whitelist/(?P<whitelistid>[0-9]+)$', views.edit_whitelist, name='edit-whitelist'),
url(
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'^del_right/$', views.del_right, name='del-right'),
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'^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'^profil/(?P<userid>[0-9]+)$', views.profil, name='profil'),
url(r'^index_ban/$', views.index_ban, name='index-ban'),
url(r'^index_white/$', views.index_white, name='index-white'),
url(r'^index_school/$', views.index_school, name='index-school'),
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'^process/(?P<token>[a-z0-9]{32})/$', views.process, name='process'),
url(r'^reset_password/$', views.reset_password, name='reset-password'),
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(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'^history/(?P<object>user)/(?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'^rest/mailing/$', views.mailing, name='mailing'),
]

View file

@ -23,20 +23,25 @@
# App de gestion des users pour re2o
# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin
# 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 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.template import Context, RequestContext, loader
from django.contrib import messages
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.http import HttpResponse
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 import revisions as reversion
from users.serializers import MailSerializer
from users.models import User, Right, Ban, Whitelist, School, ListRight, Request, ServiceUser, all_has_access
from users.forms import DelRightForm, BanForm, WhitelistForm, DelSchoolForm, DelListRightForm, NewListRightForm
from users.forms import EditInfoForm, InfoForm, BaseInfoForm, StateForm, RightForm, SchoolForm, EditServiceUserForm, ServiceUserForm, ListRightForm
from cotisations.models import Facture
from machines.models import Machine, Interface
from users.models import User, Right, Ban, Whitelist, School, ListRight
from users.models import Request, ServiceUser
from users.forms import DelRightForm, BanForm, WhitelistForm, DelSchoolForm
from users.forms import DelListRightForm, NewListRightForm
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 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
def form(ctx, template, request):
c = ctx
c.update(csrf(request))
return render(request, template, c)
from re2o.views import form
from re2o.utils import all_has_access
def password_change_action(u_form, user, request, req=False):
""" 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("/users/profil/" + str(user.id))
@login_required
@permission_required('cableur')
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)
if user.is_valid():
user = user.save(commit=False)
@ -87,21 +93,25 @@ def new_user(request):
reversion.set_user(request.user)
reversion.set_comment("Création")
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 form({'userform': user}, 'users/user.html', request)
@login_required
def edit_info(request, userid):
""" 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:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
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))
if not request.user.has_perms(('cableur',)):
user = BaseInfoForm(request.POST or None, instance=user)
@ -111,15 +121,19 @@ def edit_info(request, userid):
with transaction.atomic(), reversion.create_revision():
user.save()
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é")
return redirect("/users/profil/" + userid)
return form({'userform': user}, 'users/user.html', request)
@login_required
@permission_required('bureau')
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:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
@ -135,12 +149,15 @@ def state(request, userid):
elif state.cleaned_data['state'] == User.STATE_DISABLED:
user.state = User.STATE_DISABLED
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()
messages.success(request, "Etat changé avec succès")
return redirect("/users/profil/" + userid)
return form({'userform': state}, 'users/user.html', request)
@login_required
def password(request, userid):
""" Reinitialisation d'un mot de passe à partir de l'userid,
@ -152,16 +169,20 @@ def password(request, userid):
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
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))
if not request.user.has_perms(('bureau',)) and user != request.user and Right.objects.filter(user=user):
messages.error(request, "Il faut les droits bureau pour modifier le mot de passe d'un membre actif")
if not request.user.has_perms(('bureau',)) and user != request.user\
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))
u_form = PassForm(request.POST or None)
if u_form.is_valid():
return password_change_action(u_form, user, request)
return form({'userform': u_form}, 'users/user.html', request)
@login_required
@permission_required('infra')
def new_serviceuser(request):
@ -174,15 +195,20 @@ def new_serviceuser(request):
user_object.save()
reversion.set_user(request.user)
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 form({'userform': user}, 'users/user.html', request)
@login_required
@permission_required('infra')
def edit_serviceuser(request, userid):
""" 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:
user = ServiceUser.objects.get(pk=userid)
except ServiceUser.DoesNotExist:
@ -196,18 +222,22 @@ def edit_serviceuser(request, userid):
user_object.set_password(user.cleaned_data['password'])
user_object.save()
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é")
return redirect("/users/index_serviceusers")
return form({'userform': user}, 'users/user.html', request)
@login_required
@permission_required('infra')
def del_serviceuser(request, userid):
"""Suppression d'un ou plusieurs serviceusers"""
try:
user = ServiceUser.objects.get(pk=userid)
except ServiceUser.DoesNotExist:
messages.error(request, u"Utilisateur inexistant" )
messages.error(request, u"Utilisateur inexistant")
return redirect("/users/")
if request.method == "POST":
with transaction.atomic(), reversion.create_revision():
@ -215,7 +245,12 @@ def del_serviceuser(request, userid):
reversion.set_user(request.user)
messages.success(request, "L'user a été détruite")
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
@permission_required('bureau')
@ -241,28 +276,33 @@ def add_right(request, userid):
return redirect("/users/profil/" + userid)
return form({'userform': right}, 'users/user.html', request)
@login_required
@permission_required('bureau')
def del_right(request):
""" Supprimer un droit à un user, need droit bureau """
user_right_list = dict()
for right in ListRight.objects.all():
user_right_list[right]= DelRightForm(right, request.POST or None)
for keys, right_item in user_right_list.items():
user_right_list[right] = DelRightForm(right, request.POST or None)
for _keys, right_item in user_right_list.items():
if right_item.is_valid():
right_del = right_item.cleaned_data['rights']
with transaction.atomic(), reversion.create_revision():
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()
messages.success(request, "Droit retiré avec succès")
return redirect("/users/")
return form({'userform': user_right_list}, 'users/del_right.html', request)
@login_required
@permission_required('bofh')
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"""
try:
user = User.objects.get(pk=userid)
@ -273,7 +313,7 @@ def add_ban(request, userid):
ban = BanForm(request.POST or None, instance=ban_instance)
if ban.is_valid():
with transaction.atomic(), reversion.create_revision():
ban_object = ban.save()
_ban_object = ban.save()
reversion.set_user(request.user)
reversion.set_comment("Création")
messages.success(request, "Bannissement ajouté")
@ -285,10 +325,12 @@ def add_ban(request, userid):
)
return form({'userform': ban}, 'users/user.html', request)
@login_required
@permission_required('bofh')
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"""
try:
ban_instance = Ban.objects.get(pk=banid)
@ -300,23 +342,31 @@ def edit_ban(request, banid):
with transaction.atomic(), reversion.create_revision():
ban.save()
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é")
return redirect("/users/")
return form({'userform': ban}, 'users/user.html', request)
@login_required
@permission_required('cableur')
def add_whitelist(request, userid):
""" Accorder un accès gracieux, temporaire ou permanent. Need droit cableur
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement, raison obligatoire"""
""" Accorder un accès gracieux, temporaire ou permanent.
Need droit cableur
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement,
raison obligatoire"""
try:
user = User.objects.get(pk=userid)
except User.DoesNotExist:
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
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():
with transaction.atomic(), reversion.create_revision():
whitelist.save()
@ -331,30 +381,40 @@ def add_whitelist(request, userid):
)
return form({'userform': whitelist}, 'users/user.html', request)
@login_required
@permission_required('cableur')
def edit_whitelist(request, whitelistid):
""" Editer un accès gracieux, temporaire ou permanent. Need droit cableur
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement, raison obligatoire"""
""" Editer un accès gracieux, temporaire ou permanent.
Need droit cableur
Syntaxe : JJ/MM/AAAA , heure optionnelle, prend effet immédiatement,
raison obligatoire"""
try:
whitelist_instance = Whitelist.objects.get(pk=whitelistid)
except Whitelist.DoesNotExist:
messages.error(request, "Entrée inexistante")
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():
with transaction.atomic(), reversion.create_revision():
whitelist.save()
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")
return redirect("/users/")
return form({'userform': whitelist}, 'users/user.html', request)
@login_required
@permission_required('cableur')
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)
if school.is_valid():
with transaction.atomic(), reversion.create_revision():
@ -365,30 +425,37 @@ def add_school(request):
return redirect("/users/index_school/")
return form({'userform': school}, 'users/user.html', request)
@login_required
@permission_required('cableur')
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:
school_instance = School.objects.get(pk=schoolid)
except School.DoesNotExist:
messages.error(request, u"Entrée inexistante" )
messages.error(request, u"Entrée inexistante")
return redirect("/users/")
school = SchoolForm(request.POST or None, instance=school_instance)
if school.is_valid():
with transaction.atomic(), reversion.create_revision():
school.save()
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é")
return redirect("/users/index_school/")
return form({'userform': school}, 'users/user.html', request)
@login_required
@permission_required('cableur')
def del_school(request):
""" Supprimer un établissement d'enseignement à la base de donnée, need cableur
Objet protégé, possible seulement si aucun user n'est affecté à l'établissement """
""" Supprimer un établissement d'enseignement à la base de donnée,
need cableur
Objet protégé, possible seulement si aucun user n'est affecté à
l'établissement """
school = DelSchoolForm(request.POST or None)
if school.is_valid():
school_dels = school.cleaned_data['schools']
@ -406,6 +473,7 @@ def del_school(request):
return redirect("/users/index_school/")
return form({'userform': school}, 'users/user.html', request)
@login_required
@permission_required('bureau')
def add_listright(request):
@ -421,29 +489,38 @@ def add_listright(request):
return redirect("/users/index_listright/")
return form({'userform': listright}, 'users/user.html', request)
@login_required
@permission_required('bureau')
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:
listright_instance = ListRight.objects.get(pk=listrightid)
except ListRight.DoesNotExist:
messages.error(request, u"Entrée inexistante" )
messages.error(request, u"Entrée inexistante")
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():
with transaction.atomic(), reversion.create_revision():
listright.save()
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é")
return redirect("/users/index_listright/")
return form({'userform': listright}, 'users/user.html', request)
@login_required
@permission_required('bureau')
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)
if listright.is_valid():
listright_dels = listright.cleaned_data['listrights']
@ -461,6 +538,7 @@ def del_listright(request):
return redirect("/users/index_listright/")
return form({'userform': listright}, 'users/user.html', request)
@login_required
@permission_required('bureau')
def mass_archive(request):
@ -469,7 +547,10 @@ def mass_archive(request):
to_archive_list = []
if to_archive_date.is_valid():
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:
for user in to_archive_list:
with transaction.atomic(), reversion.create_revision():
@ -477,15 +558,22 @@ def mass_archive(request):
user.save()
reversion.set_user(request.user)
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 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
@permission_required('cableur')
def index(request):
""" 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
users_list = User.objects.select_related('room').order_by('state', 'name')
paginator = Paginator(users_list, pagination_number)
@ -500,13 +588,15 @@ def index(request):
users_list = paginator.page(paginator.num_pages)
return render(request, 'users/index.html', {'users_list': users_list})
@login_required
@permission_required('cableur')
def index_ban(request):
""" 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
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)
page = request.GET.get('page')
try:
@ -519,13 +609,15 @@ def index_ban(request):
ban_list = paginator.page(paginator.num_pages)
return render(request, 'users/index_ban.html', {'ban_list': ban_list})
@login_required
@permission_required('cableur')
def index_white(request):
""" 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
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)
page = request.GET.get('page')
try:
@ -542,84 +634,106 @@ def index_white(request):
{'white_list': white_list}
)
@login_required
@permission_required('cableur')
def index_school(request):
""" Affiche l'ensemble des établissement, need droit cableur """
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
@permission_required('cableur')
def index_listright(request):
""" Affiche l'ensemble des droits , need droit cableur """
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
@permission_required('cableur')
def index_serviceusers(request):
""" Affiche les users de services (pour les accès ldap)"""
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
def history(request, object, id):
def history(request, object_name, object_id):
""" Affichage de l'historique : (acl, argument)
user : self or cableur, userid,
ban : self or cableur, banid,
whitelist : self or cableur, whitelistid,
school : cableur, schoolid,
listright : cableur, listrightid """
if object == 'user':
if object_name == 'user':
try:
object_instance = User.objects.get(pk=id)
object_instance = User.objects.get(pk=object_id)
except User.DoesNotExist:
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
if not request.user.has_perms(('cableur',)) and object_instance != request.user:
messages.error(request, "Vous ne pouvez pas afficher l'historique d'un autre user que vous sans droit cableur")
if not request.user.has_perms(('cableur',)) and\
object_instance != request.user:
messages.error(request, "Vous ne pouvez pas afficher\
l'historique d'un autre user que vous sans droit cableur")
return redirect("/users/profil/" + str(request.user.id))
elif object == 'serviceuser' and request.user.has_perms(('cableur',)):
elif object_name == 'serviceuser' and request.user.has_perms(('cableur',)):
try:
object_instance = ServiceUser.objects.get(pk=id)
object_instance = ServiceUser.objects.get(pk=object_id)
except ServiceUser.DoesNotExist:
messages.error(request, "User service inexistant")
return redirect("/users/")
elif object == 'ban':
elif object_name == 'ban':
try:
object_instance = Ban.objects.get(pk=id)
object_instance = Ban.objects.get(pk=object_id)
except Ban.DoesNotExist:
messages.error(request, "Bannissement inexistant")
return redirect("/users/")
if not request.user.has_perms(('cableur',)) and object_instance.user != request.user:
messages.error(request, "Vous ne pouvez pas afficher les bans d'un autre user que vous sans droit cableur")
if not request.user.has_perms(('cableur',)) and\
object_instance.user != request.user:
messages.error(request, "Vous ne pouvez pas afficher les bans\
d'un autre user que vous sans droit cableur")
return redirect("/users/profil/" + str(request.user.id))
elif object == 'whitelist':
elif object_name == 'whitelist':
try:
object_instance = Whitelist.objects.get(pk=id)
except Whiltelist.DoesNotExist:
object_instance = Whitelist.objects.get(pk=object_id)
except Whitelist.DoesNotExist:
messages.error(request, "Whitelist inexistant")
return redirect("/users/")
if not request.user.has_perms(('cableur',)) and object_instance.user != request.user:
messages.error(request, "Vous ne pouvez pas afficher les whitelist d'un autre user que vous sans droit cableur")
if not request.user.has_perms(('cableur',)) and\
object_instance.user != request.user:
messages.error(request, "Vous ne pouvez pas afficher les\
whitelist d'un autre user que vous sans droit cableur")
return redirect("/users/profil/" + str(request.user.id))
elif object == 'school' and request.user.has_perms(('cableur',)):
elif object_name == 'school' and request.user.has_perms(('cableur',)):
try:
object_instance = School.objects.get(pk=id)
object_instance = School.objects.get(pk=object_id)
except School.DoesNotExist:
messages.error(request, "Ecole inexistante")
return redirect("/users/")
elif object == 'listright' and request.user.has_perms(('cableur',)):
elif object_name == 'listright' and request.user.has_perms(('cableur',)):
try:
object_instance = ListRight.objects.get(pk=id)
object_instance = ListRight.objects.get(pk=object_id)
except ListRight.DoesNotExist:
messages.error(request, "Droit inexistant")
return redirect("/users/")
else:
messages.error(request, "Objet inconnu")
return redirect("/users/")
options, created = GeneralOption.objects.get_or_create()
options, _created = GeneralOption.objects.get_or_create()
pagination_number = options.pagination_number
reversions = Version.objects.get_for_object(object_instance)
paginator = Paginator(reversions, pagination_number)
@ -632,7 +746,11 @@ def history(request, object, id):
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
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
@ -640,6 +758,7 @@ def mon_profil(request):
""" Lien vers profil, renvoie request.id à la fonction """
return redirect("/users/profil/" + str(request.user.id))
@login_required
def profil(request, userid):
""" Affiche un profil, self or cableur, prend un userid en argument """
@ -649,14 +768,19 @@ def profil(request, userid):
messages.error(request, "Utilisateur inexistant")
return redirect("/users/")
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))
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)
bans = Ban.objects.filter(user=users)
whitelists = Whitelist.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
return render(
request,
@ -672,46 +796,56 @@ def profil(request, userid):
}
)
def reset_password(request):
""" Reintialisation du mot de passe si mdp oublié """
userform = ResetPasswordForm(request.POST or None)
if userform.is_valid():
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:
messages.error(request, "Cet utilisateur n'existe pas")
return form({'userform': userform}, 'users/user.html', 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("/")
return form({'userform': userform}, 'users/user.html', request)
def process(request, token):
"""Process, lien pour la reinitialisation du mot de passe"""
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
req = get_object_or_404(valid_reqs, token=token)
if req.type == Request.PASSWD:
return process_passwd(request, req)
elif req.type == Request.EMAIL:
return process_email(request, req=req)
else:
messages.error(request, "Entrée incorrecte, contactez un admin")
redirect("/")
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)
user = req.user
if u_form.is_valid():
return password_change_action(u_form, user, request, req=req)
return form({'userform': u_form}, 'users/user.html', request)
""" Framework Rest """
class JSONResponse(HttpResponse):
""" Framework Rest """
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
@csrf_exempt
@login_required
@permission_required('serveur')
@ -721,4 +855,3 @@ def mailing(request):
mails = all_has_access().values('email').distinct()
seria = MailSerializer(mails, many=True)
return JSONResponse(seria.data)