Massive cleanup (1)

This commit is contained in:
Alexandre Iooss 2019-08-02 14:57:53 +02:00
parent ca394afe20
commit c5f98991aa
No known key found for this signature in database
GPG Key ID: 6C79278F3FCDCC02
38 changed files with 479 additions and 729 deletions

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,29 +1,12 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django import template from django import template
register = template.Library() register = template.Library()
@register.filter @register.filter
def classname(obj): def classname(obj):
return obj.__class__.__name__ return obj.__class__.__name__

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,24 +1,6 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.conf.urls import url from django.conf.urls import url

View File

@ -1,58 +1,30 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
# App de gestion des statistiques pour re2o
# Gabriel Détraz
# Gplv2
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 import messages
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.db.models import ProtectedError from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.forms import ValidationError
from django.db import transaction
from django.db.models import Count from django.db.models import Count
from django.shortcuts import redirect, render
from django.template.context_processors import csrf
from reversion.models import Revision from reversion.models import Revision
from reversion.models import Version
from users.models import User
from med.settings import PAGINATION_NUMBER as pagination_number from med.settings import PAGINATION_NUMBER as pagination_number
from users.models import User
from django.utils import timezone
def form(ctx, template, request): def form(ctx, template, request):
c = ctx c = ctx
c.update(csrf(request)) c.update(csrf(request))
return render(request, template, c) return render(request, template, c)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def index(request): def index(request):
revisions = Revision.objects.all().order_by('date_created').reverse().select_related('user').prefetch_related('version_set__object') revisions = Revision.objects.all().order_by('date_created').reverse().select_related('user').prefetch_related(
'version_set__object')
paginator = Paginator(revisions, pagination_number) paginator = Paginator(revisions, pagination_number)
page = request.GET.get('page') page = request.GET.get('page')
try: try:
@ -61,10 +33,11 @@ def index(request):
# If page is not an integer, deliver first page. # If page is not an integer, deliver first page.
revisions = paginator.page(1) revisions = paginator.page(1)
except EmptyPage: except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results. # If page is out of range (e.g. 9999), deliver last page of results.
revisions = paginator.page(paginator.num_pages) revisions = paginator.page(paginator.num_pages)
return render(request, 'logs/index.html', {'revisions_list': revisions}) return render(request, 'logs/index.html', {'revisions_list': revisions})
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def revert_action(request, revision_id): def revert_action(request, revision_id):
@ -72,20 +45,20 @@ def revert_action(request, revision_id):
try: try:
revision = Revision.objects.get(id=revision_id) revision = Revision.objects.get(id=revision_id)
except Revision.DoesNotExist: except Revision.DoesNotExist:
messages.error(request, u"Revision inexistante" ) messages.error(request, u"Revision inexistante")
if request.method == "POST": if request.method == "POST":
revision.revert() revision.revert()
messages.success(request, "L'action a été supprimée") messages.success(request, "L'action a été supprimée")
return redirect("/logs/") return redirect("/logs/")
return form({'objet': revision, 'objet_name': revision.__class__.__name__ }, 'logs/delete.html', request) return form({'objet': revision, 'objet_name': revision.__class__.__name__}, 'logs/delete.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def stats_actions(request): def stats_actions(request):
onglet = request.GET.get('onglet')
stats = { stats = {
'Utilisateur' : { 'Utilisateur': {
'Action' : User.objects.annotate(num=Count('revision')).order_by('-num')[:40], 'Action': User.objects.annotate(num=Count('revision')).order_by('-num')[:40],
}, },
} }
return render(request, 'logs/stats_users.html', {'stats_list': stats}) return render(request, 'logs/stats_users.html', {'stats_list': stats})

View File

@ -1,22 +0,0 @@
# 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.

View File

@ -1,33 +1,16 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from .settings import SITE_NAME from .settings import SITE_NAME
def context_user(request): def context_user(request):
user = request.user user = request.user
is_perm = user.has_perms(['perm']) is_perm = user.has_perms(['perm'])
is_bureau = user.has_perms(['bureau']) is_bureau = user.has_perms(['bureau'])
return { return {
'is_perm' : is_perm, 'is_perm': is_perm,
'is_bureau': is_bureau, 'is_bureau': is_bureau,
'request_user': user, 'request_user': user,
'site_name': SITE_NAME, 'site_name': SITE_NAME,

View File

@ -1,18 +1,17 @@
# -*- coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Module d'authentification # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# David Sinquin, Gabriel Détraz, Goulven Kermarec # SPDX-License-Identifier: GPL-3.0-or-later
import hashlib
import binascii import binascii
import hashlib
import os import os
from base64 import encodestring
from base64 import decodestring from base64 import decodestring
from base64 import encodestring
from collections import OrderedDict from collections import OrderedDict
from django.contrib.auth import hashers from django.contrib.auth import hashers
ALGO_NAME = "{SSHA}" ALGO_NAME = "{SSHA}"
ALGO_LEN = len(ALGO_NAME + "$") ALGO_LEN = len(ALGO_NAME + "$")
DIGEST_LEN = 20 DIGEST_LEN = 20
@ -24,6 +23,7 @@ def makeSecret(password):
h.update(salt) h.update(salt)
return ALGO_NAME + "$" + encodestring(h.digest() + salt).decode()[:-1] return ALGO_NAME + "$" + encodestring(h.digest() + salt).decode()[:-1]
def checkPassword(challenge_password, password): def checkPassword(challenge_password, password):
challenge_bytes = decodestring(challenge_password[ALGO_LEN:].encode()) challenge_bytes = decodestring(challenge_password[ALGO_LEN:].encode())
digest = challenge_bytes[:DIGEST_LEN] digest = challenge_bytes[:DIGEST_LEN]
@ -37,6 +37,7 @@ def checkPassword(challenge_password, password):
valid_password &= i == j valid_password &= i == j
return valid_password return valid_password
class SSHAPasswordHasher(hashers.BasePasswordHasher): class SSHAPasswordHasher(hashers.BasePasswordHasher):
""" """
SSHA password hashing to allow for LDAP auth compatibility SSHA password hashing to allow for LDAP auth compatibility
@ -70,8 +71,8 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher):
return OrderedDict([ return OrderedDict([
('algorithm', self.algorithm), ('algorithm', self.algorithm),
('iterations', 0), ('iterations', 0),
('salt', hashers.mask_hash(hash[2*DIGEST_LEN:], show=2)), ('salt', hashers.mask_hash(hash[2 * DIGEST_LEN:], show=2)),
('hash', hashers.mask_hash(hash[:2*DIGEST_LEN])), ('hash', hashers.mask_hash(hash[:2 * DIGEST_LEN])),
]) ])
def harden_runtime(self, password, encoded): def harden_runtime(self, password, encoded):
@ -81,4 +82,3 @@ class SSHAPasswordHasher(hashers.BasePasswordHasher):
As we are not using multiple iterations the method is pretty useless As we are not using multiple iterations the method is pretty useless
""" """
pass pass

View File

@ -1,5 +1,5 @@
# -*- mode: python; coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
import os import os
@ -103,16 +103,20 @@ DATABASES = {
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 'NAME': 'django.contrib.auth.'
'password_validation.UserAttributeSimilarityValidator',
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 'NAME': 'django.contrib.auth.'
'password_validation.MinimumLengthValidator',
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 'NAME': 'django.contrib.auth.'
'password_validation.CommonPasswordValidator',
}, },
{ {
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 'NAME': 'django.contrib.auth.'
'password_validation.NumericPasswordValidator',
}, },
] ]

View File

@ -1,5 +1,5 @@
# -*- mode: python; coding: utf-8 -*- # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2018-2019 by BDE ENS Paris-Saclay # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# Needed to filter which host are trusted # Needed to filter which host are trusted

View File

@ -1 +0,0 @@
create allowed_guests bitmap:ip range 10.231.137.0-10.231.137.255

View File

@ -1,39 +1,7 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
"""med URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.8/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import include, url from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views

View File

@ -1,36 +1,19 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.shortcuts import render from django.shortcuts import render
from django.shortcuts import get_object_or_404
from django.template.context_processors import csrf from django.template.context_processors import csrf
from django.template import Context, RequestContext, loader
from med.settings import services_urls from med.settings import services_urls
def form(ctx, template, request): def form(ctx, template, request):
c = ctx c = ctx
c.update(csrf(request)) c.update(csrf(request))
return render(request, template, c) return render(request, template, c)
def index(request): def index(request):
i = 0 i = 0
services = [{}] services = [{}]

View File

@ -1,24 +1,6 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
""" """
WSGI config for med project. WSGI config for med project.
@ -30,10 +12,10 @@ https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
""" """
import os import os
from django.core.wsgi import get_wsgi_application
from os.path import dirname
import sys import sys
from os.path import dirname
from django.core.wsgi import get_wsgi_application
sys.path.append(dirname(dirname(__file__))) sys.path.append(dirname(dirname(__file__)))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "med.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "med.settings")

View File

@ -1,21 +1,28 @@
# -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from reversion.admin import VersionAdmin
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import Group from reversion.admin import VersionAdmin
from .models import Auteur, Emprunt, Media, Jeu from .models import Auteur, Emprunt, Media, Jeu
class AuteurAdmin(VersionAdmin): class AuteurAdmin(VersionAdmin):
list_display = ('nom',) list_display = ('nom',)
class MediaAdmin(VersionAdmin): class MediaAdmin(VersionAdmin):
list_display = ('titre','cote') list_display = ('titre', 'cote')
class EmpruntAdmin(VersionAdmin): class EmpruntAdmin(VersionAdmin):
list_display = ('media','user','date_emprunt', 'date_rendu', 'permanencier_emprunt', 'permanencier_rendu') list_display = ('media', 'user', 'date_emprunt', 'date_rendu', 'permanencier_emprunt', 'permanencier_rendu')
class JeuAdmin(VersionAdmin): class JeuAdmin(VersionAdmin):
list_display = ('nom','proprietaire', 'duree', 'nombre_joueurs_min', 'nombre_joueurs_max', 'comment') list_display = ('nom', 'proprietaire', 'duree', 'nombre_joueurs_min', 'nombre_joueurs_max', 'comment')
admin.site.register(Auteur, AuteurAdmin) admin.site.register(Auteur, AuteurAdmin)
admin.site.register(Media, MediaAdmin) admin.site.register(Media, MediaAdmin)

View File

@ -1,34 +1,19 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.forms import ModelForm, Form, ValidationError
from django import forms from django import forms
from django.forms import ModelForm
from .models import Auteur, Media, Jeu, Emprunt from .models import Auteur, Media, Jeu, Emprunt
class AuteurForm(ModelForm): class AuteurForm(ModelForm):
class Meta: class Meta:
model = Auteur model = Auteur
fields = '__all__' fields = '__all__'
class MediaForm(ModelForm): class MediaForm(ModelForm):
auteur = forms.ModelMultipleChoiceField(Auteur.objects.all(), widget=forms.CheckboxSelectMultiple, required=False) auteur = forms.ModelMultipleChoiceField(Auteur.objects.all(), widget=forms.CheckboxSelectMultiple, required=False)
@ -36,6 +21,7 @@ class MediaForm(ModelForm):
model = Media model = Media
fields = '__all__' fields = '__all__'
class JeuForm(ModelForm): class JeuForm(ModelForm):
class Meta: class Meta:
model = Jeu model = Jeu
@ -46,11 +32,13 @@ class JeuForm(ModelForm):
raise forms.ValidationError("Max ne peut être inférieur à min") raise forms.ValidationError("Max ne peut être inférieur à min")
return self.cleaned_data['nombre_joueurs_max'] return self.cleaned_data['nombre_joueurs_max']
class EmpruntForm(ModelForm): class EmpruntForm(ModelForm):
class Meta: class Meta:
model = Emprunt model = Emprunt
fields = ['media'] fields = ['media']
class EditEmpruntForm(ModelForm): class EditEmpruntForm(ModelForm):
class Meta: class Meta:
model = Emprunt model = Emprunt

View File

@ -0,0 +1,46 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-02 14:47+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: models.py:13
msgid "author"
msgstr ""
#: models.py:14
msgid "authors"
msgstr ""
#: models.py:26
msgid "medium"
msgstr ""
#: models.py:27
msgid "media"
msgstr ""
#: models.py:44
msgid "borrowed item"
msgstr ""
#: models.py:45
msgid "borrowed items"
msgstr ""
#: models.py:68
msgid "game"
msgstr ""
#: models.py:69
msgid "games"
msgstr ""

View File

@ -1,5 +1,11 @@
from django.db import models # -*- mode: python; coding: utf-8 -*-
# Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.db import models
from django.utils.translation import gettext_lazy as _
class Auteur(models.Model): class Auteur(models.Model):
nom = models.CharField(max_length=255, unique=True) nom = models.CharField(max_length=255, unique=True)
@ -7,39 +13,53 @@ class Auteur(models.Model):
def __str__(self): def __str__(self):
return self.nom return self.nom
class Meta:
verbose_name = _("author")
verbose_name_plural = _("authors")
class Media(models.Model): class Media(models.Model):
titre = models.CharField(max_length=255) titre = models.CharField(max_length=255)
cote = models.CharField(max_length=31) cote = models.CharField(max_length=31)
auteur = models.ManyToManyField('Auteur') auteur = models.ManyToManyField('Auteur')
# type = TODO
def __str__(self): def __str__(self):
return str(self.titre) + ' - ' + str(self.auteur.all().first()) return str(self.titre) + ' - ' + str(self.auteur.all().first())
class Meta:
verbose_name = _("medium")
verbose_name_plural = _("media")
class Emprunt(models.Model): class Emprunt(models.Model):
media = models.ForeignKey('Media', on_delete=models.PROTECT) media = models.ForeignKey('Media', on_delete=models.PROTECT)
user = models.ForeignKey('users.User', on_delete=models.PROTECT) user = models.ForeignKey('users.User', on_delete=models.PROTECT)
date_emprunt = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S') date_emprunt = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S')
date_rendu = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S', blank=True, null=True) date_rendu = models.DateTimeField(help_text='%d/%m/%y %H:%M:%S', blank=True, null=True)
permanencier_emprunt = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='user_permanencier_emprunt') permanencier_emprunt = models.ForeignKey('users.User', on_delete=models.PROTECT,
permanencier_rendu = models.ForeignKey('users.User', on_delete=models.PROTECT, related_name='user_permanencier_rendu', blank=True, null=True) related_name='user_permanencier_emprunt')
permanencier_rendu = models.ForeignKey('users.User', on_delete=models.PROTECT,
related_name='user_permanencier_rendu', blank=True, null=True)
def __str__(self): def __str__(self):
return str(self.media) + str(self.user) return str(self.media) + str(self.user)
class Meta:
verbose_name = _("borrowed item")
verbose_name_plural = _("borrowed items")
class Jeu(models.Model): class Jeu(models.Model):
DUREE = ( DUREE = (
('-1h', '-1h'), ('-1h', '-1h'),
('1-2h', '1-2h'), ('1-2h', '1-2h'),
('2-3h', '2-3h'), ('2-3h', '2-3h'),
('3-4h', '3-4h'), ('3-4h', '3-4h'),
('4h+', '4h+'), ('4h+', '4h+'),
) )
nom = models.CharField(max_length=255) nom = models.CharField(max_length=255)
proprietaire = models.ForeignKey('users.User', on_delete=models.PROTECT) proprietaire = models.ForeignKey('users.User', on_delete=models.PROTECT)
duree = models.CharField(choices=DUREE, max_length=255) duree = models.CharField(choices=DUREE, max_length=255)
nombre_joueurs_min = models.IntegerField(validators=[MinValueValidator(1)]) nombre_joueurs_min = models.IntegerField(validators=[MinValueValidator(1)])
nombre_joueurs_max = models.IntegerField(validators=[MinValueValidator(1)]) nombre_joueurs_max = models.IntegerField(validators=[MinValueValidator(1)])
@ -47,3 +67,7 @@ class Jeu(models.Model):
def __str__(self): def __str__(self):
return str(self.nom) return str(self.nom)
class Meta:
verbose_name = _("game")
verbose_name_plural = _("games")

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,24 +1,6 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.conf.urls import url from django.conf.urls import url

View File

@ -1,28 +1,29 @@
from django.shortcuts import render, redirect # -*- mode: python; coding: utf-8 -*-
from django.http import HttpResponse # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
from django.shortcuts import get_object_or_404 # SPDX-License-Identifier: GPL-3.0-or-later
from django.template.context_processors import csrf
from django.template import Context, RequestContext, loader
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.contrib.auth import authenticate, login
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from .forms import AuteurForm, MediaForm, JeuForm, EmpruntForm, EditEmpruntForm
from .models import Auteur, Media, Jeu, Emprunt
from users.models import User
from django.db import transaction from django.db import transaction
from django.shortcuts import render, redirect
from django.template.context_processors import csrf
from django.utils import timezone
from reversion import revisions as reversion from reversion import revisions as reversion
from reversion.models import Version from reversion.models import Version
from med.settings import PAGINATION_NUMBER from med.settings import PAGINATION_NUMBER
from users.models import User
from .forms import AuteurForm, MediaForm, JeuForm, EmpruntForm, EditEmpruntForm
from .models import Auteur, Media, Jeu, Emprunt
def form(ctx, template, request): def form(ctx, template, request):
c = ctx c = ctx
c.update(csrf(request)) c.update(csrf(request))
return render(request, template, c) return render(request, template, c)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def add_auteur(request): def add_auteur(request):
@ -36,13 +37,14 @@ def add_auteur(request):
return redirect("/media/index_auteurs/") return redirect("/media/index_auteurs/")
return form({'mediaform': auteur}, 'media/media.html', request) return form({'mediaform': auteur}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def edit_auteur(request, auteurid): def edit_auteur(request, auteurid):
try: try:
auteur_instance = Auteur.objects.get(pk=auteurid) auteur_instance = Auteur.objects.get(pk=auteurid)
except Auteur.DoesNotExist: except Auteur.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_auteurs/") return redirect("/media/index_auteurs/")
auteur = AuteurForm(request.POST or None, instance=auteur_instance) auteur = AuteurForm(request.POST or None, instance=auteur_instance)
if auteur.is_valid(): if auteur.is_valid():
@ -54,13 +56,14 @@ def edit_auteur(request, auteurid):
return redirect("/media/index_auteurs/") return redirect("/media/index_auteurs/")
return form({'mediaform': auteur}, 'media/media.html', request) return form({'mediaform': auteur}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def del_auteur(request, auteurid): def del_auteur(request, auteurid):
try: try:
auteur_instance = Auteur.objects.get(pk=auteurid) auteur_instance = Auteur.objects.get(pk=auteurid)
except Auteur.DoesNotExist: except Auteur.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_auteurs/") return redirect("/media/index_auteurs/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
@ -84,13 +87,14 @@ def add_media(request):
return redirect("/media/index_medias/") return redirect("/media/index_medias/")
return form({'mediaform': media}, 'media/media.html', request) return form({'mediaform': media}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def edit_media(request, mediaid): def edit_media(request, mediaid):
try: try:
media_instance = Media.objects.get(pk=mediaid) media_instance = Media.objects.get(pk=mediaid)
except Media.DoesNotExist: except Media.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_medias/") return redirect("/media/index_medias/")
media = MediaForm(request.POST or None, instance=media_instance) media = MediaForm(request.POST or None, instance=media_instance)
if media.is_valid(): if media.is_valid():
@ -102,13 +106,14 @@ def edit_media(request, mediaid):
return redirect("/media/index_medias/") return redirect("/media/index_medias/")
return form({'mediaform': media}, 'media/media.html', request) return form({'mediaform': media}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def del_media(request, mediaid): def del_media(request, mediaid):
try: try:
media_instance = Media.objects.get(pk=mediaid) media_instance = Media.objects.get(pk=mediaid)
except Media.DoesNotExist: except Media.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_medias/") return redirect("/media/index_medias/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
@ -118,6 +123,7 @@ def del_media(request, mediaid):
return redirect("/media/index_medias") return redirect("/media/index_medias")
return form({'objet': media_instance, 'objet_name': 'media'}, 'media/delete.html', request) return form({'objet': media_instance, 'objet_name': 'media'}, 'media/delete.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def add_jeu(request): def add_jeu(request):
@ -131,13 +137,14 @@ def add_jeu(request):
return redirect("/media/index_jeux/") return redirect("/media/index_jeux/")
return form({'mediaform': jeu}, 'media/media.html', request) return form({'mediaform': jeu}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def edit_jeu(request, jeuid): def edit_jeu(request, jeuid):
try: try:
jeu_instance = Jeu.objects.get(pk=jeuid) jeu_instance = Jeu.objects.get(pk=jeuid)
except Jeu.DoesNotExist: except Jeu.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_jeux/") return redirect("/media/index_jeux/")
jeu = JeuForm(request.POST or None, instance=jeu_instance) jeu = JeuForm(request.POST or None, instance=jeu_instance)
if jeu.is_valid(): if jeu.is_valid():
@ -149,13 +156,14 @@ def edit_jeu(request, jeuid):
return redirect("/media/index_jeux/") return redirect("/media/index_jeux/")
return form({'mediaform': jeu}, 'media/media.html', request) return form({'mediaform': jeu}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def del_jeu(request, jeuid): def del_jeu(request, jeuid):
try: try:
jeu_instance = Jeu.objects.get(pk=jeuid) jeu_instance = Jeu.objects.get(pk=jeuid)
except Jeu.DoesNotExist: except Jeu.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_jeux/") return redirect("/media/index_jeux/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
@ -165,13 +173,14 @@ def del_jeu(request, jeuid):
return redirect("/media/index_jeux") return redirect("/media/index_jeux")
return form({'objet': jeu_instance, 'objet_name': 'jeu'}, 'media/delete.html', request) return form({'objet': jeu_instance, 'objet_name': 'jeu'}, 'media/delete.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def add_emprunt(request, userid): def add_emprunt(request, userid):
try: try:
user = User.objects.get(pk=userid) user = User.objects.get(pk=userid)
except User.DoesNotExist: except User.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
emprunts_en_cours = Emprunt.objects.filter(date_rendu=None, user=user).count() emprunts_en_cours = Emprunt.objects.filter(date_rendu=None, user=user).count()
if emprunts_en_cours >= user.maxemprunt: if emprunts_en_cours >= user.maxemprunt:
@ -191,13 +200,14 @@ def add_emprunt(request, userid):
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
return form({'mediaform': emprunt}, 'media/media.html', request) return form({'mediaform': emprunt}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def edit_emprunt(request, empruntid): def edit_emprunt(request, empruntid):
try: try:
emprunt_instance = Emprunt.objects.get(pk=empruntid) emprunt_instance = Emprunt.objects.get(pk=empruntid)
except Emprunt.DoesNotExist: except Emprunt.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
emprunt = EditEmpruntForm(request.POST or None, instance=emprunt_instance) emprunt = EditEmpruntForm(request.POST or None, instance=emprunt_instance)
if emprunt.is_valid(): if emprunt.is_valid():
@ -209,13 +219,14 @@ def edit_emprunt(request, empruntid):
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
return form({'mediaform': emprunt}, 'media/media.html', request) return form({'mediaform': emprunt}, 'media/media.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def retour_emprunt(request, empruntid): def retour_emprunt(request, empruntid):
try: try:
emprunt_instance = Emprunt.objects.get(pk=empruntid) emprunt_instance = Emprunt.objects.get(pk=empruntid)
except Emprunt.DoesNotExist: except Emprunt.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
emprunt_instance.permanencier_rendu = request.user emprunt_instance.permanencier_rendu = request.user
@ -225,13 +236,14 @@ def retour_emprunt(request, empruntid):
messages.success(request, "Retour enregistré") messages.success(request, "Retour enregistré")
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def del_emprunt(request, empruntid): def del_emprunt(request, empruntid):
try: try:
emprunt_instance = Emprunt.objects.get(pk=empruntid) emprunt_instance = Emprunt.objects.get(pk=empruntid)
except Emprunt.DoesNotExist: except Emprunt.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/media/index_emprunts/") return redirect("/media/index_emprunts/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
@ -242,8 +254,6 @@ def del_emprunt(request, empruntid):
return form({'objet': emprunt_instance, 'objet_name': 'emprunt'}, 'media/delete.html', request) return form({'objet': emprunt_instance, 'objet_name': 'emprunt'}, 'media/delete.html', request)
@login_required @login_required
def index_jeux(request): def index_jeux(request):
jeux_list = Jeu.objects.all() jeux_list = Jeu.objects.all()
@ -257,7 +267,8 @@ def index_jeux(request):
except EmptyPage: except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results. # If page is out of range (e.g. 9999), deliver last page of results.
jeux_list = paginator.page(paginator.num_pages) jeux_list = paginator.page(paginator.num_pages)
return render(request, 'media/index_jeux.html', {'jeux_list':jeux_list}) return render(request, 'media/index_jeux.html', {'jeux_list': jeux_list})
@login_required @login_required
def index_auteurs(request): def index_auteurs(request):
@ -272,7 +283,8 @@ def index_auteurs(request):
except EmptyPage: except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results. # If page is out of range (e.g. 9999), deliver last page of results.
auteurs_list = paginator.page(paginator.num_pages) auteurs_list = paginator.page(paginator.num_pages)
return render(request, 'media/index_auteurs.html', {'auteurs_list':auteurs_list}) return render(request, 'media/index_auteurs.html', {'auteurs_list': auteurs_list})
@login_required @login_required
def index_medias(request): def index_medias(request):
@ -287,7 +299,7 @@ def index_medias(request):
except EmptyPage: except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results. # If page is out of range (e.g. 9999), deliver last page of results.
medias_list = paginator.page(paginator.num_pages) medias_list = paginator.page(paginator.num_pages)
return render(request, 'media/index_medias.html', {'medias_list':medias_list}) return render(request, 'media/index_medias.html', {'medias_list': medias_list})
@login_required @login_required
@ -306,35 +318,35 @@ def index(request):
except EmptyPage: except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results. # If page is out of range (e.g. 9999), deliver last page of results.
emprunts_list = paginator.page(paginator.num_pages) emprunts_list = paginator.page(paginator.num_pages)
return render(request, 'media/index_emprunts.html', {'emprunts_list':emprunts_list}) return render(request, 'media/index_emprunts.html', {'emprunts_list': emprunts_list})
@login_required @login_required
def history(request, object, id): def history(request, object, id):
if object == 'auteur': if object == 'auteur':
try: try:
object_instance = Auteur.objects.get(pk=id) object_instance = Auteur.objects.get(pk=id)
except Auteur.DoesNotExist: except Auteur.DoesNotExist:
messages.error(request, "Auteur inexistant") messages.error(request, "Auteur inexistant")
return redirect("/media/index_auteurs") return redirect("/media/index_auteurs")
elif object == 'media': elif object == 'media':
try: try:
object_instance = Media.objects.get(pk=id) object_instance = Media.objects.get(pk=id)
except Media.DoesNotExist: except Media.DoesNotExist:
messages.error(request, "Media inexistant") messages.error(request, "Media inexistant")
return redirect("/media/index_medias") return redirect("/media/index_medias")
elif object == 'emprunt': elif object == 'emprunt':
try: try:
object_instance = Emprunt.objects.get(pk=id) object_instance = Emprunt.objects.get(pk=id)
except Emprunt.DoesNotExist: except Emprunt.DoesNotExist:
messages.error(request, "Emprunt inexistant") messages.error(request, "Emprunt inexistant")
return redirect("/media/index_emprunts") return redirect("/media/index_emprunts")
elif object == 'jeu': elif object == 'jeu':
try: try:
object_instance = Jeu.objects.get(pk=id) object_instance = Jeu.objects.get(pk=id)
except Jeu.DoesNotExist: except Jeu.DoesNotExist:
messages.error(request, "Jeu inexistant") messages.error(request, "Jeu inexistant")
return redirect("/media/index_jeux") return redirect("/media/index_jeux")
reversions = Version.objects.get_for_object(object_instance) reversions = Version.objects.get_for_object(object_instance)
paginator = Paginator(reversions, PAGINATION_NUMBER) paginator = Paginator(reversions, PAGINATION_NUMBER)
page = request.GET.get('page') page = request.GET.get('page')
@ -347,4 +359,3 @@ def history(request, object, id):
# If page is out of range (e.g. 9999), deliver last page of results. # If page is out of range (e.g. 9999), deliver last page of results.
reversions = paginator.page(paginator.num_pages) reversions = paginator.page(paginator.num_pages)
return render(request, 'med/history.html', {'reversions': reversions, 'object': object_instance}) return render(request, 'med/history.html', {'reversions': reversions, 'object': object_instance})

View File

@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.

View File

@ -1,29 +1,9 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.db import models
from django import forms from django import forms
from django.forms import Form from django.forms import Form
from django.forms import ModelForm
CHOICES = ( CHOICES = (
('0', 'Actifs'), ('0', 'Actifs'),
@ -37,14 +17,18 @@ CHOICES2 = (
('2', 'Emprunts'), ('2', 'Emprunts'),
('3', 'Jeu'), ('3', 'Jeu'),
) )
class SearchForm(Form): class SearchForm(Form):
search_field = forms.CharField(label = 'Search', max_length = 100) search_field = forms.CharField(label='Search', max_length=100)
class SearchFormPlus(Form): class SearchFormPlus(Form):
search_field = forms.CharField(label = 'Search', max_length = 100, required=False) search_field = forms.CharField(label='Search', max_length=100, required=False)
filtre = forms.MultipleChoiceField(label="Filtre utilisateurs", required=False, widget =forms.CheckboxSelectMultiple,choices=CHOICES) filtre = forms.MultipleChoiceField(label="Filtre utilisateurs", required=False, widget=forms.CheckboxSelectMultiple,
affichage = forms.MultipleChoiceField(label="Filtre affichage", required=False, widget =forms.CheckboxSelectMultiple,choices=CHOICES2) choices=CHOICES)
date_deb = forms.DateField(required=False, label="Date de début", help_text='DD/MM/YYYY', input_formats=['%d/%m/%Y']) affichage = forms.MultipleChoiceField(label="Filtre affichage", required=False, widget=forms.CheckboxSelectMultiple,
choices=CHOICES2)
date_deb = forms.DateField(required=False, label="Date de début", help_text='DD/MM/YYYY',
input_formats=['%d/%m/%Y'])
date_fin = forms.DateField(required=False, help_text='DD/MM/YYYY', input_formats=['%d/%m/%Y'], label="Date de fin") date_fin = forms.DateField(required=False, help_text='DD/MM/YYYY', input_formats=['%d/%m/%Y'], label="Date de fin")

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View File

@ -1,24 +1,6 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.conf.urls import url from django.conf.urls import url

View File

@ -1,60 +1,37 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
# App de recherche pour re2o
# Augustin lemesle, Gabriel Détraz, Goulven Kermarec
# Gplv2
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 django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.db.models import Q from django.db.models import Q
from users.models import User from django.shortcuts import render
from search.forms import SearchForm, SearchFormPlus from django.template.context_processors import csrf
from med.settings import SEARCH_DISPLAY_PAGE from med.settings import SEARCH_DISPLAY_PAGE
from media.models import Media, Jeu, Emprunt from media.models import Media, Jeu, Emprunt
from search.forms import SearchForm, SearchFormPlus
from users.models import User
def form(ctx, template, request): def form(ctx, template, request):
c = ctx c = ctx
c.update(csrf(request)) c.update(csrf(request))
return render(request, template, c) return render(request, template, c)
def search_result(search, type, request): def search_result(search, type, request):
date_deb = None date_deb = None
date_fin = None date_fin = None
states=[] states = []
aff=[] aff = []
if(type): if (type):
aff = search.cleaned_data['affichage'] aff = search.cleaned_data['affichage']
states = search.cleaned_data['filtre'] states = search.cleaned_data['filtre']
date_deb = search.cleaned_data['date_deb'] date_deb = search.cleaned_data['date_deb']
date_fin = search.cleaned_data['date_fin'] date_fin = search.cleaned_data['date_fin']
date_query = Q() date_query = Q()
if aff==[]: if aff == []:
aff = ['0','1','2','3'] aff = ['0', '1', '2', '3']
if date_deb != None: if date_deb != None:
date_query = date_query & Q(date_emprunt__gte=date_deb) date_query = date_query & Q(date_emprunt__gte=date_deb)
if date_fin != None: if date_fin != None:
@ -62,32 +39,36 @@ def search_result(search, type, request):
search = search.cleaned_data['search_field'] search = search.cleaned_data['search_field']
query1 = Q() query1 = Q()
for s in states: for s in states:
query1 = query1 | Q(state = s) query1 = query1 | Q(state=s)
connexion = [] connexion = []
recherche = {'users_list': None, 'emprunts_list' : None, 'medias_list' : None, 'jeux_list': None} recherche = {'users_list': None, 'emprunts_list': None, 'medias_list': None, 'jeux_list': None}
if request.user.has_perms(('perm',)): if request.user.has_perms(('perm',)):
query = Q(user__pseudo__icontains = search) | Q(user__name__icontains = search) | Q(user__surname__icontains = search) query = Q(user__pseudo__icontains=search) | Q(user__name__icontains=search) | Q(user__surname__icontains=search)
else: else:
query = (Q(user__pseudo__icontains = search) | Q(user__name__icontains = search) | Q(user__surname__icontains = search)) & Q(user = request.user) query = (Q(user__pseudo__icontains=search) | Q(user__name__icontains=search) | Q(
user__surname__icontains=search)) & Q(user=request.user)
for i in aff: for i in aff:
if i == '0': if i == '0':
query_user_list = Q(pseudo__icontains = search) | Q(name__icontains = search) | Q(surname__icontains = search) & query1 query_user_list = Q(pseudo__icontains=search) | Q(name__icontains=search) | Q(
surname__icontains=search) & query1
if request.user.has_perms(('perm',)): if request.user.has_perms(('perm',)):
recherche['users_list'] = User.objects.filter(query_user_list).order_by('state', 'surname') recherche['users_list'] = User.objects.filter(query_user_list).order_by('state', 'surname')
else : else:
recherche['users_list'] = User.objects.filter(query_user_list & Q(id=request.user.id)).order_by('state', 'surname') recherche['users_list'] = User.objects.filter(query_user_list & Q(id=request.user.id)).order_by('state',
'surname')
if i == '1': if i == '1':
recherche['emprunts_list'] = Emprunt.objects.filter(query & date_query).order_by('date_emprunt').reverse() recherche['emprunts_list'] = Emprunt.objects.filter(query & date_query).order_by('date_emprunt').reverse()
if i == '2': if i == '2':
recherche['medias_list'] = Media.objects.filter(Q(auteur__nom__icontains = search) | Q(titre__icontains = search)) recherche['medias_list'] = Media.objects.filter(
Q(auteur__nom__icontains=search) | Q(titre__icontains=search))
if i == '3': if i == '3':
recherche['jeux_list'] = Jeu.objects.filter(Q(nom__icontains = search) | Q(proprietaire__pseudo__icontains = search) | Q(proprietaire__name__icontains = search) | Q(proprietaire__surname__icontains = search)) recherche['jeux_list'] = Jeu.objects.filter(
Q(nom__icontains=search) | Q(proprietaire__pseudo__icontains=search) | Q(
proprietaire__name__icontains=search) | Q(proprietaire__surname__icontains=search))
for r in recherche: for r in recherche:
if recherche[r] != None: if recherche[r] != None:
@ -97,17 +78,18 @@ def search_result(search, type, request):
return recherche return recherche
@login_required @login_required
def search(request): def search(request):
search = SearchForm(request.POST or None) search = SearchForm(request.POST or None)
if search.is_valid(): if search.is_valid():
return form(search_result(search, False, request), 'search/index.html',request) return form(search_result(search, False, request), 'search/index.html', request)
return form({'searchform' : search}, 'search/search.html', request) return form({'searchform': search}, 'search/search.html', request)
@login_required @login_required
def searchp(request): def searchp(request):
search = SearchFormPlus(request.POST or None) search = SearchFormPlus(request.POST or None)
if search.is_valid(): if search.is_valid():
return form(search_result(search, True, request), 'search/index.html',request) return form(search_result(search, True, request), 'search/index.html', request)
return form({'searchform' : search}, 'search/search.html', request) return form({'searchform': search}, 'search/search.html', request)

View File

@ -1,32 +1,14 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import Group
from reversion.admin import VersionAdmin from reversion.admin import VersionAdmin
from .models import User, Right, Adhesion, ListRight, Clef, Request
from .forms import UserChangeForm, UserCreationForm from .forms import UserChangeForm, UserCreationForm
from .models import User, Right, Adhesion, ListRight, Clef, Request
class UserAdmin(admin.ModelAdmin): class UserAdmin(admin.ModelAdmin):
@ -37,23 +19,29 @@ class UserAdmin(admin.ModelAdmin):
'email', 'email',
'state' 'state'
) )
search_fields = ('name','surname','pseudo') search_fields = ('name', 'surname', 'pseudo')
class RequestAdmin(admin.ModelAdmin): class RequestAdmin(admin.ModelAdmin):
list_display = ('user', 'type', 'created_at', 'expires_at') list_display = ('user', 'type', 'created_at', 'expires_at')
class RightAdmin(VersionAdmin): class RightAdmin(VersionAdmin):
list_display = ('user', 'right') list_display = ('user', 'right')
class ClefAdmin(VersionAdmin): class ClefAdmin(VersionAdmin):
list_display = ('proprio', 'nom') list_display = ('proprio', 'nom')
class AdhesionAdmin(VersionAdmin): class AdhesionAdmin(VersionAdmin):
list_display = ('annee_debut', 'annee_fin') list_display = ('annee_debut', 'annee_fin')
class ListRightAdmin(VersionAdmin): class ListRightAdmin(VersionAdmin):
list_display = ('listright',) list_display = ('listright',)
class UserAdmin(VersionAdmin, BaseUserAdmin): class UserAdmin(VersionAdmin, BaseUserAdmin):
# The forms to add and change user instances # The forms to add and change user instances
form = UserChangeForm form = UserChangeForm
@ -67,7 +55,7 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
fieldsets = ( fieldsets = (
(None, {'fields': ('pseudo', 'password')}), (None, {'fields': ('pseudo', 'password')}),
('Personal info', {'fields': ('name', 'surname', 'email')}), ('Personal info', {'fields': ('name', 'surname', 'email')}),
('Permissions', {'fields': ('is_admin', )}), ('Permissions', {'fields': ('is_admin',)}),
) )
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user. # overrides get_fieldsets to use this attribute when creating a user.
@ -75,12 +63,13 @@ class UserAdmin(VersionAdmin, BaseUserAdmin):
(None, { (None, {
'classes': ('wide',), 'classes': ('wide',),
'fields': ('pseudo', 'name', 'surname', 'email', 'is_admin', 'password1', 'password2')} 'fields': ('pseudo', 'name', 'surname', 'email', 'is_admin', 'password1', 'password2')}
), ),
) )
search_fields = ('pseudo',) search_fields = ('pseudo',)
ordering = ('pseudo',) ordering = ('pseudo',)
filter_horizontal = () filter_horizontal = ()
admin.site.register(User, UserAdmin) admin.site.register(User, UserAdmin)
admin.site.register(Request, RequestAdmin) admin.site.register(Request, RequestAdmin)
admin.site.register(ListRight, ListRightAdmin) admin.site.register(ListRight, ListRightAdmin)

View File

@ -1,46 +1,29 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
# App de gestion des users pour med
# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin
# Gplv2
from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from med.settings import AUTHORIZED_IP_RANGE, AUTHORIZED_IP6_RANGE
import ipaddress import ipaddress
from django.shortcuts import redirect
from med.settings import AUTHORIZED_IP_RANGE, AUTHORIZED_IP6_RANGE
def user_is_in_campus(function): def user_is_in_campus(function):
def wrap(request, *args, **kwargs): def wrap(request, *args, **kwargs):
if not request.user.is_authenticated: if not request.user.is_authenticated:
remote_ip = get_ip(request) remote_ip = get_ip(request)
if not ipaddress.ip_address(remote_ip) in ipaddress.ip_network(AUTHORIZED_IP_RANGE) and not ipaddress.ip_address(remote_ip) in ipaddress.ip_network(AUTHORIZED_IP6_RANGE): if not ipaddress.ip_address(remote_ip) in ipaddress.ip_network(
AUTHORIZED_IP_RANGE) and not ipaddress.ip_address(remote_ip) in ipaddress.ip_network(
AUTHORIZED_IP6_RANGE):
return redirect("/") return redirect("/")
return function(request, *args, **kwargs) return function(request, *args, **kwargs)
wrap.__doc__ = function.__doc__ wrap.__doc__ = function.__doc__
wrap.__name__ = function.__name__ wrap.__name__ = function.__name__
return wrap return wrap
def get_ip(request): def get_ip(request):
"""Returns the IP of the request, accounting for the possibility of being """Returns the IP of the request, accounting for the possibility of being
behind a proxy. behind a proxy.

View File

@ -1,46 +1,29 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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 -*-
from django import forms from django import forms
from django.forms import ModelForm, Form
from django.contrib.auth.forms import ReadOnlyPasswordHashField from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.validators import MinLengthValidator from django.core.validators import MinLengthValidator
from django.utils import timezone from django.forms import ModelForm, Form
from .models import Adhesion, Clef, ListRight, Right, User
from .models import Adhesion, Clef, ListRight, Right, Request, User
class PassForm(forms.Form): class PassForm(forms.Form):
passwd1 = forms.CharField(label=u'Nouveau mot de passe', max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput) passwd1 = forms.CharField(label=u'Nouveau mot de passe', max_length=255, validators=[MinLengthValidator(8)],
passwd2 = forms.CharField(label=u'Saisir à nouveau le mot de passe', max_length=255, validators=[MinLengthValidator(8)], widget=forms.PasswordInput) widget=forms.PasswordInput)
passwd2 = forms.CharField(label=u'Saisir à nouveau le mot de passe', max_length=255,
validators=[MinLengthValidator(8)], widget=forms.PasswordInput)
class UserCreationForm(forms.ModelForm): class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required """A form for creating new users. Includes all the required
fields, plus a repeated password.""" fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput, validators=[MinLengthValidator(8)], max_length=255) password1 = forms.CharField(label='Password', widget=forms.PasswordInput, validators=[MinLengthValidator(8)],
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput, validators=[MinLengthValidator(8)], max_length=255) max_length=255)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput,
validators=[MinLengthValidator(8)], max_length=255)
is_admin = forms.BooleanField(label='is admin') is_admin = forms.BooleanField(label='is admin')
class Meta: class Meta:
@ -95,16 +78,18 @@ class UserChangeForm(forms.ModelForm):
user.save() user.save()
return user return user
class ResetPasswordForm(forms.Form): class ResetPasswordForm(forms.Form):
pseudo = forms.CharField(label=u'Pseudo', max_length=255) pseudo = forms.CharField(label=u'Pseudo', max_length=255)
email = forms.EmailField(max_length=255) email = forms.EmailField(max_length=255)
class BaseInfoForm(ModelForm): class BaseInfoForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BaseInfoForm, self).__init__(*args, **kwargs) super(BaseInfoForm, self).__init__(*args, **kwargs)
self.fields['name'].label = 'Prénom' self.fields['name'].label = 'Prénom'
self.fields['surname'].label = 'Nom' self.fields['surname'].label = 'Nom'
#self.fields['comment'].label = 'Commentaire' # self.fields['comment'].label = 'Commentaire'
class Meta: class Meta:
model = User model = User
@ -117,9 +102,10 @@ class BaseInfoForm(ModelForm):
'adresse', 'adresse',
] ]
class InfoForm(BaseInfoForm): class InfoForm(BaseInfoForm):
class Meta(BaseInfoForm.Meta): class Meta(BaseInfoForm.Meta):
fields = [ fields = [
'name', 'name',
'pseudo', 'pseudo',
'surname', 'surname',
@ -135,22 +121,26 @@ class PasswordForm(ModelForm):
model = User model = User
fields = ['password'] fields = ['password']
class StateForm(ModelForm): class StateForm(ModelForm):
class Meta: class Meta:
model = User model = User
fields = ['state'] fields = ['state']
class ClefForm(ModelForm): class ClefForm(ModelForm):
class Meta: class Meta:
model = Clef model = Clef
fields = '__all__' fields = '__all__'
class BaseClefForm(ClefForm): class BaseClefForm(ClefForm):
class Meta(ClefForm.Meta): class Meta(ClefForm.Meta):
fields = [ fields = [
'commentaire', 'commentaire',
] ]
class AdhesionForm(ModelForm): class AdhesionForm(ModelForm):
adherent = forms.ModelMultipleChoiceField(User.objects.all(), widget=forms.CheckboxSelectMultiple, required=False) adherent = forms.ModelMultipleChoiceField(User.objects.all(), widget=forms.CheckboxSelectMultiple, required=False)
@ -158,6 +148,7 @@ class AdhesionForm(ModelForm):
model = Adhesion model = Adhesion
fields = '__all__' fields = '__all__'
class RightForm(ModelForm): class RightForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(RightForm, self).__init__(*args, **kwargs) super(RightForm, self).__init__(*args, **kwargs)
@ -170,12 +161,13 @@ class RightForm(ModelForm):
class DelRightForm(Form): class DelRightForm(Form):
rights = forms.ModelMultipleChoiceField(queryset=Right.objects.all(), widget=forms.CheckboxSelectMultiple) rights = forms.ModelMultipleChoiceField(queryset=Right.objects.all(), widget=forms.CheckboxSelectMultiple)
def __init__(self, right, *args, **kwargs): def __init__(self, right, *args, **kwargs):
super(DelRightForm, self).__init__(*args, **kwargs) super(DelRightForm, self).__init__(*args, **kwargs)
self.fields['rights'].queryset = Right.objects.filter(right=right) self.fields['rights'].queryset = Right.objects.filter(right=right)
class ListRightForm(ModelForm): class ListRightForm(ModelForm):
class Meta: class Meta:
model = ListRight model = ListRight
@ -185,11 +177,12 @@ class ListRightForm(ModelForm):
super(ListRightForm, self).__init__(*args, **kwargs) super(ListRightForm, self).__init__(*args, **kwargs)
self.fields['listright'].label = 'Nom du droit/groupe' self.fields['listright'].label = 'Nom du droit/groupe'
class NewListRightForm(ListRightForm): class NewListRightForm(ListRightForm):
class Meta(ListRightForm.Meta): class Meta(ListRightForm.Meta):
fields = '__all__' fields = '__all__'
class DelListRightForm(Form): class DelListRightForm(Form):
listrights = forms.ModelMultipleChoiceField(queryset=ListRight.objects.all(), label="Droits actuels", widget=forms.CheckboxSelectMultiple) listrights = forms.ModelMultipleChoiceField(queryset=ListRight.objects.all(), label="Droits actuels",
widget=forms.CheckboxSelectMultiple)

View File

@ -0,0 +1,22 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-08-02 14:42+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: models.py:195
msgid "right"
msgstr ""
#: models.py:196
msgid "rights"
msgstr ""

View File

@ -1,39 +1,16 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
import datetime
import uuid
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models from django.db import models
from django.db.models import Q from django.utils import timezone
from django.db.models.signals import post_save, post_delete from django.utils.translation import gettext_lazy as _
from django.dispatch import receiver
from django.utils.functional import cached_property
from med.settings import MAX_EMPRUNT, REQ_EXPIRE_HRS from med.settings import MAX_EMPRUNT, REQ_EXPIRE_HRS
import re, uuid
import datetime
from django.utils import timezone
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
import subprocess
class UserManager(BaseUserManager): class UserManager(BaseUserManager):
@ -75,23 +52,23 @@ class User(AbstractBaseUser):
STATE_DISABLED = 1 STATE_DISABLED = 1
STATE_ARCHIVE = 2 STATE_ARCHIVE = 2
STATES = ( STATES = (
(0, 'STATE_ACTIVE'), (0, 'STATE_ACTIVE'),
(1, 'STATE_DISABLED'), (1, 'STATE_DISABLED'),
(2, 'STATE_ARCHIVE'), (2, 'STATE_ARCHIVE'),
) )
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
surname = models.CharField(max_length=255) surname = models.CharField(max_length=255)
email = models.EmailField() email = models.EmailField()
telephone = models.CharField(max_length=15, null=True, blank=True) telephone = models.CharField(max_length=15, null=True, blank=True)
adresse = models.CharField(max_length=255, null=True, blank=True) adresse = models.CharField(max_length=255, null=True, blank=True)
maxemprunt = models.IntegerField(default=MAX_EMPRUNT, help_text="Maximum d'emprunts autorisés") maxemprunt = models.IntegerField(default=MAX_EMPRUNT, help_text="Maximum d'emprunts autorisés")
state = models.IntegerField(choices=STATES, default=STATE_ACTIVE) state = models.IntegerField(choices=STATES, default=STATE_ACTIVE)
pseudo = models.CharField(max_length=32, unique=True, help_text="Doit contenir uniquement des lettres, chiffres, ou tirets. ") pseudo = models.CharField(max_length=32, unique=True,
help_text="Doit contenir uniquement des lettres, chiffres, ou tirets. ")
comment = models.CharField(help_text="Commentaire, promo", max_length=255, blank=True) comment = models.CharField(help_text="Commentaire, promo", max_length=255, blank=True)
registered = models.DateTimeField(auto_now_add=True) registered = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'pseudo' USERNAME_FIELD = 'pseudo'
REQUIRED_FIELDS = ['name', 'surname', 'email'] REQUIRED_FIELDS = ['name', 'surname', 'email']
@ -150,16 +127,16 @@ class User(AbstractBaseUser):
def get_admin_right(self): def get_admin_right(self):
admin, created = ListRight.objects.get_or_create(listright="admin") admin, created = ListRight.objects.get_or_create(listright="admin")
return admin return admin
def make_admin(self): def make_admin(self):
""" Make User admin """ """ Make User admin """
user_admin_right = Right(user=self, right=self.get_admin_right()) user_admin_right = Right(user=self, right=self.get_admin_right())
user_admin_right.save() user_admin_right.save()
def un_admin(self): def un_admin(self):
try: try:
user_right = Right.objects.get(user=self,right=self.get_admin_right()) user_right = Right.objects.get(user=self, right=self.get_admin_right())
except Right.DoesNotExist: except Right.DoesNotExist:
return return
user_right.delete() user_right.delete()
@ -184,40 +161,44 @@ class Request(models.Model):
def save(self): def save(self):
if not self.expires_at: if not self.expires_at:
self.expires_at = timezone.now() \ self.expires_at = timezone.now() \
+ datetime.timedelta(hours=REQ_EXPIRE_HRS) + datetime.timedelta(hours=REQ_EXPIRE_HRS)
if not self.token: if not self.token:
self.token = str(uuid.uuid4()).replace('-', '') # remove hyphens self.token = str(uuid.uuid4()).replace('-', '') # remove hyphens
super(Request, self).save() super(Request, self).save()
class Right(models.Model): class Right(models.Model):
PRETTY_NAME = "Droits affectés à des users" PRETTY_NAME = "Droits affectés à des users"
user = models.ForeignKey('User', on_delete=models.PROTECT) user = models.ForeignKey('User', on_delete=models.PROTECT)
right = models.ForeignKey('ListRight', on_delete=models.PROTECT) right = models.ForeignKey('ListRight', on_delete=models.PROTECT)
class Meta: class Meta:
verbose_name = _("right")
verbose_name_plural = _("rights")
unique_together = ("user", "right") unique_together = ("user", "right")
def __str__(self): def __str__(self):
return str(self.user) return str(self.user)
class ListRight(models.Model): class ListRight(models.Model):
PRETTY_NAME = "Liste des droits existants" PRETTY_NAME = "Liste des droits existants"
listright = models.CharField(max_length=255, unique=True) listright = models.CharField(max_length=255, unique=True)
details = models.CharField(help_text="Description", max_length=255, blank=True) details = models.CharField(help_text="Description", max_length=255, blank=True)
def __str__(self): def __str__(self):
return self.listright return self.listright
class Clef(models.Model): class Clef(models.Model):
nom = models.CharField(max_length=255, unique=True) nom = models.CharField(max_length=255, unique=True)
proprio = models.ForeignKey('User', on_delete=models.PROTECT, blank=True, null=True) proprio = models.ForeignKey('User', on_delete=models.PROTECT, blank=True, null=True)
commentaire = models.CharField(max_length=255, null=True, blank=True) commentaire = models.CharField(max_length=255, null=True, blank=True)
class Adhesion(models.Model): class Adhesion(models.Model):
annee_debut = models.IntegerField(unique=True) annee_debut = models.IntegerField(unique=True)
annee_fin = models.IntegerField(unique=True) annee_fin = models.IntegerField(unique=True)
adherent = models.ManyToManyField('User', blank=True) adherent = models.ManyToManyField('User', blank=True)

View File

@ -1,25 +0,0 @@
# 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.
from django.test import TestCase
# Create your tests here.

View File

@ -1,24 +1,6 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
from django.conf.urls import url from django.conf.urls import url
@ -56,5 +38,3 @@ urlpatterns = [
url(r'^$', views.index, name='index'), url(r'^$', views.index, name='index'),
url(r'^index_ajour/$', views.index_ajour, name='index-ajour'), url(r'^index_ajour/$', views.index_ajour, name='index-ajour'),
] ]

View File

@ -1,52 +1,29 @@
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il # -*- mode: python; coding: utf-8 -*-
# se veut agnostique au réseau considéré, de manière à être installable en # Copyright (C) 2017-2019 by BDE ENS Paris-Saclay
# quelques clics. # SPDX-License-Identifier: GPL-3.0-or-later
#
# 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.
# App de gestion des users pour med
# Goulven Kermarec, Gabriel Détraz, Lemesle Augustin
# Gplv2
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 import messages
from django.contrib.auth.decorators import login_required, permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.signals import user_logged_in
from django.db.models import Max, ProtectedError
from django.db import IntegrityError
from django.core.mail import send_mail from django.core.mail import send_mail
from django.utils import timezone from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import IntegrityError
from django.db import transaction from django.db import transaction
from django.db.models import ProtectedError
from reversion.models import Version from django.shortcuts import get_object_or_404, render, redirect
from django.template import loader
from django.template.context_processors import csrf
from django.utils import timezone
from reversion import revisions as reversion from reversion import revisions as reversion
from users.forms import DelListRightForm, NewListRightForm, ListRightForm, RightForm, DelRightForm from reversion.models import Version
from users.forms import InfoForm, BaseInfoForm, StateForm, ClefForm, BaseClefForm, AdhesionForm
from users.models import User, Request, ListRight, Right, Clef, Adhesion
from users.forms import PassForm, ResetPasswordForm
from users.decorators import user_is_in_campus
from media.models import Emprunt
from med.settings import REQ_EXPIRE_STR, EMAIL_FROM, ASSO_NAME, ASSO_EMAIL, SITE_NAME, PAGINATION_NUMBER from med.settings import REQ_EXPIRE_STR, EMAIL_FROM, ASSO_NAME, ASSO_EMAIL, SITE_NAME, PAGINATION_NUMBER
from media.models import Emprunt
from users.decorators import user_is_in_campus
from users.forms import DelListRightForm, NewListRightForm, ListRightForm, RightForm, DelRightForm
from users.forms import InfoForm, BaseInfoForm, StateForm, ClefForm, AdhesionForm
from users.forms import PassForm, ResetPasswordForm
from users.models import User, Request, ListRight, Right, Clef, Adhesion
def form(ctx, template, request): def form(ctx, template, request):
@ -54,6 +31,7 @@ def form(ctx, template, request):
c.update(csrf(request)) c.update(csrf(request))
return render(request, template, c) return render(request, template, c)
def password_change_action(u_form, user, request, req=False): def password_change_action(u_form, user, request, req=False):
""" Fonction qui effectue le changeemnt de mdp bdd""" """ Fonction qui effectue le changeemnt de mdp bdd"""
if u_form.cleaned_data['passwd1'] != u_form.cleaned_data['passwd2']: if u_form.cleaned_data['passwd1'] != u_form.cleaned_data['passwd2']:
@ -69,20 +47,21 @@ def password_change_action(u_form, user, request, req=False):
return redirect("/") return redirect("/")
return redirect("/users/profil/" + str(user.id)) return redirect("/users/profil/" + str(user.id))
def reset_passwd_mail(req, request): def reset_passwd_mail(req, request):
""" Prend en argument un request, envoie un mail de réinitialisation de mot de pass """ """ Prend en argument un request, envoie un mail de réinitialisation de mot de pass """
t = loader.get_template('users/email_passwd_request') t = loader.get_template('users/email_passwd_request')
c = { c = {
'name': str(req.user.name) + ' ' + str(req.user.surname), 'name': str(req.user.name) + ' ' + str(req.user.surname),
'asso': ASSO_NAME, 'asso': ASSO_NAME,
'asso_mail': ASSO_EMAIL, 'asso_mail': ASSO_EMAIL,
'site_name': SITE_NAME, 'site_name': SITE_NAME,
'url': request.build_absolute_uri( 'url': request.build_absolute_uri(
reverse('users:process', kwargs={'token': req.token})), reverse('users:process', kwargs={'token': req.token})),
'expire_in': REQ_EXPIRE_STR, 'expire_in': REQ_EXPIRE_STR,
} }
send_mail('Votre compte %s' % SITE_NAME, t.render(c), send_mail('Votre compte %s' % SITE_NAME, t.render(c),
EMAIL_FROM, [req.user.email], fail_silently=False) EMAIL_FROM, [req.user.email], fail_silently=False)
return return
@ -101,10 +80,12 @@ def new_user(request):
req.user = user req.user = user
req.save() req.save()
reset_passwd_mail(req, request) reset_passwd_mail(req, request)
messages.success(request, "L'utilisateur %s a été crée, un mail pour l'initialisation du mot de passe a été envoyé" % user.pseudo) messages.success(request,
"L'utilisateur %s a été crée, un mail pour l'initialisation du mot de passe a été envoyé" % user.pseudo)
return redirect("/users/profil/" + str(user.id)) return redirect("/users/profil/" + str(user.id))
return form({'userform': user}, 'users/user.html', request) return form({'userform': user}, 'users/user.html', request)
@login_required @login_required
def edit_info(request, userid): def edit_info(request, userid):
""" Edite un utilisateur à partir de son id, si l'id est différent de request.user, vérifie la possession du droit admin """ """ Edite un utilisateur à partir de son id, si l'id est différent de request.user, vérifie la possession du droit admin """
@ -129,6 +110,7 @@ def edit_info(request, userid):
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
return form({'userform': user}, 'users/user.html', request) return form({'userform': user}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def state(request, userid): def state(request, userid):
@ -148,6 +130,7 @@ def state(request, userid):
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
return form({'userform': state}, 'users/user.html', request) return form({'userform': state}, 'users/user.html', request)
@login_required @login_required
def password(request, userid): def password(request, userid):
""" Reinitialisation d'un mot de passe à partir de l'userid, """ Reinitialisation d'un mot de passe à partir de l'userid,
@ -166,6 +149,7 @@ def password(request, userid):
return password_change_action(u_form, user, request) return password_change_action(u_form, user, request)
return form({'userform': u_form}, 'users/user.html', request) return form({'userform': u_form}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def add_listright(request): def add_listright(request):
@ -181,6 +165,7 @@ def add_listright(request):
return redirect("/users/index_listright/") return redirect("/users/index_listright/")
return form({'userform': listright}, 'users/user.html', request) return form({'userform': listright}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def edit_listright(request, listrightid): def edit_listright(request, listrightid):
@ -188,7 +173,7 @@ def edit_listright(request, listrightid):
try: try:
listright_instance = ListRight.objects.get(pk=listrightid) listright_instance = ListRight.objects.get(pk=listrightid)
except ListRight.DoesNotExist: except ListRight.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/users/") return redirect("/users/")
listright = ListRightForm(request.POST or None, instance=listright_instance) listright = ListRightForm(request.POST or None, instance=listright_instance)
if listright.is_valid(): if listright.is_valid():
@ -200,6 +185,7 @@ def edit_listright(request, listrightid):
return redirect("/users/index_listright/") return redirect("/users/index_listright/")
return form({'userform': listright}, 'users/user.html', request) return form({'userform': listright}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def del_listright(request): def del_listright(request):
@ -221,6 +207,7 @@ def del_listright(request):
return redirect("/users/index_listright/") return redirect("/users/index_listright/")
return form({'userform': listright}, 'users/user.html', request) return form({'userform': listright}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def add_right(request, userid): def add_right(request, userid):
@ -245,30 +232,34 @@ def add_right(request, userid):
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
return form({'userform': right}, 'users/user.html', request) return form({'userform': right}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def del_right(request): def del_right(request):
""" Supprimer un droit à un user, need droit bureau """ """ Supprimer un droit à un user, need droit bureau """
user_right_list = dict() user_right_list = dict()
for right in ListRight.objects.all(): for right in ListRight.objects.all():
user_right_list[right]= DelRightForm(right, request.POST or None) user_right_list[right] = DelRightForm(right, request.POST or None)
for keys, right_item in user_right_list.items(): for keys, right_item in user_right_list.items():
if right_item.is_valid(): if right_item.is_valid():
right_del = right_item.cleaned_data['rights'] right_del = right_item.cleaned_data['rights']
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
reversion.set_user(request.user) reversion.set_user(request.user)
reversion.set_comment("Retrait des droit %s" % ','.join(str(deleted_right) for deleted_right in right_del)) reversion.set_comment(
"Retrait des droit %s" % ','.join(str(deleted_right) for deleted_right in right_del))
right_del.delete() right_del.delete()
messages.success(request, "Droit retiré avec succès") messages.success(request, "Droit retiré avec succès")
return redirect("/users/") return redirect("/users/")
return form({'userform': user_right_list}, 'users/del_right.html', request) return form({'userform': user_right_list}, 'users/del_right.html', request)
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def index_listright(request): def index_listright(request):
""" Affiche l'ensemble des droits , need droit perm """ """ Affiche l'ensemble des droits , need droit perm """
listright_list = ListRight.objects.order_by('listright') listright_list = ListRight.objects.order_by('listright')
return render(request, 'users/index_listright.html', {'listright_list':listright_list}) return render(request, 'users/index_listright.html', {'listright_list': listright_list})
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
@ -283,12 +274,13 @@ def add_clef(request):
return redirect("/users/index_clef/") return redirect("/users/index_clef/")
return form({'userform': clef}, 'users/user.html', request) return form({'userform': clef}, 'users/user.html', request)
@user_is_in_campus @user_is_in_campus
def edit_clef(request, clefid): def edit_clef(request, clefid):
try: try:
clef_instance = Clef.objects.get(pk=clefid) clef_instance = Clef.objects.get(pk=clefid)
except Clef.DoesNotExist: except Clef.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/users/index_clef/") return redirect("/users/index_clef/")
clef = ClefForm(request.POST or None, instance=clef_instance) clef = ClefForm(request.POST or None, instance=clef_instance)
if clef.is_valid(): if clef.is_valid():
@ -301,13 +293,14 @@ def edit_clef(request, clefid):
return redirect("/users/index_clef/") return redirect("/users/index_clef/")
return form({'userform': clef}, 'users/user.html', request) return form({'userform': clef}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def del_clef(request, clefid): def del_clef(request, clefid):
try: try:
clef_instance = Clef.objects.get(pk=clefid) clef_instance = Clef.objects.get(pk=clefid)
except Clef.DoesNotExist: except Clef.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/users/index_clef/") return redirect("/users/index_clef/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
@ -317,10 +310,12 @@ def del_clef(request, clefid):
return redirect("/users/index_clef") return redirect("/users/index_clef")
return form({'objet': clef_instance, 'objet_name': 'clef'}, 'users/delete.html', request) return form({'objet': clef_instance, 'objet_name': 'clef'}, 'users/delete.html', request)
@user_is_in_campus @user_is_in_campus
def index_clef(request): def index_clef(request):
clef_list = Clef.objects.all().order_by('nom') clef_list = Clef.objects.all().order_by('nom')
return render(request, 'users/index_clef.html', {'clef_list':clef_list}) return render(request, 'users/index_clef.html', {'clef_list': clef_list})
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
@ -335,13 +330,14 @@ def add_adhesion(request):
return redirect("/users/index_adhesion/") return redirect("/users/index_adhesion/")
return form({'userform': adhesion}, 'users/user.html', request) return form({'userform': adhesion}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def edit_adhesion(request, adhesionid): def edit_adhesion(request, adhesionid):
try: try:
adhesion_instance = Adhesion.objects.get(pk=adhesionid) adhesion_instance = Adhesion.objects.get(pk=adhesionid)
except Adhesion.DoesNotExist: except Adhesion.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/users/index_adhesion/") return redirect("/users/index_adhesion/")
adhesion = AdhesionForm(request.POST or None, instance=adhesion_instance) adhesion = AdhesionForm(request.POST or None, instance=adhesion_instance)
if adhesion.is_valid(): if adhesion.is_valid():
@ -353,13 +349,14 @@ def edit_adhesion(request, adhesionid):
return redirect("/users/index_adhesion/") return redirect("/users/index_adhesion/")
return form({'userform': adhesion}, 'users/user.html', request) return form({'userform': adhesion}, 'users/user.html', request)
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def del_adhesion(request, adhesionid): def del_adhesion(request, adhesionid):
try: try:
adhesion_instance = Adhesion.objects.get(pk=adhesionid) adhesion_instance = Adhesion.objects.get(pk=adhesionid)
except Adhesion.DoesNotExist: except Adhesion.DoesNotExist:
messages.error(request, u"Entrée inexistante" ) messages.error(request, u"Entrée inexistante")
return redirect("/users/index_adhesion/") return redirect("/users/index_adhesion/")
if request.method == "POST": if request.method == "POST":
with transaction.atomic(), reversion.create_revision(): with transaction.atomic(), reversion.create_revision():
@ -369,10 +366,12 @@ def del_adhesion(request, adhesionid):
return redirect("/users/index_adhesion") return redirect("/users/index_adhesion")
return form({'objet': adhesion_instance, 'objet_name': 'adhesion'}, 'users/delete.html', request) return form({'objet': adhesion_instance, 'objet_name': 'adhesion'}, 'users/delete.html', request)
@login_required @login_required
def index_adhesion(request): def index_adhesion(request):
adhesion_list = Adhesion.objects.all() adhesion_list = Adhesion.objects.all()
return render(request, 'users/index_adhesion.html', {'adhesion_list':adhesion_list}) return render(request, 'users/index_adhesion.html', {'adhesion_list': adhesion_list})
@login_required @login_required
@permission_required('perm') @permission_required('perm')
@ -391,6 +390,7 @@ def index(request):
users_list = paginator.page(paginator.num_pages) users_list = paginator.page(paginator.num_pages)
return render(request, 'users/index.html', {'users_list': users_list}) return render(request, 'users/index.html', {'users_list': users_list})
@login_required @login_required
@permission_required('perm') @permission_required('perm')
def index_ajour(request): def index_ajour(request):
@ -408,46 +408,48 @@ def index_ajour(request):
users_list = paginator.page(paginator.num_pages) users_list = paginator.page(paginator.num_pages)
return render(request, 'users/index.html', {'users_list': users_list}) return render(request, 'users/index.html', {'users_list': users_list})
@user_is_in_campus @user_is_in_campus
def history(request, object, id): def history(request, object, id):
""" Affichage de l'historique : (acl, argument) """ Affichage de l'historique : (acl, argument)
user : self, userid""" user : self, userid"""
if object == 'clef': if object == 'clef':
try: try:
object_instance = Clef.objects.get(pk=id) object_instance = Clef.objects.get(pk=id)
except Clef.DoesNotExist: except Clef.DoesNotExist:
messages.error(request, "Utilisateur inexistant") messages.error(request, "Utilisateur inexistant")
return redirect("/users/") return redirect("/users/")
elif not request.user.is_authenticated: elif not request.user.is_authenticated:
messages.error(request, "Permission denied") messages.error(request, "Permission denied")
return redirect("/users/") return redirect("/users/")
if object == 'user': if object == 'user':
try: try:
object_instance = User.objects.get(pk=id) object_instance = User.objects.get(pk=id)
except User.DoesNotExist: except User.DoesNotExist:
messages.error(request, "Utilisateur inexistant") messages.error(request, "Utilisateur inexistant")
return redirect("/users/") return redirect("/users/")
if not request.user.has_perms(('perm',)) and object_instance != request.user: if not request.user.has_perms(('perm',)) and object_instance != request.user:
messages.error(request, "Vous ne pouvez pas afficher l'historique d'un autre user que vous sans droit admin") messages.error(request,
return redirect("/users/profil/" + str(request.user.id)) "Vous ne pouvez pas afficher l'historique d'un autre user que vous sans droit admin")
return redirect("/users/profil/" + str(request.user.id))
elif object == 'clef': elif object == 'clef':
try: try:
object_instance = Clef.objects.get(pk=id) object_instance = Clef.objects.get(pk=id)
except Clef.DoesNotExist: except Clef.DoesNotExist:
messages.error(request, "Utilisateur inexistant") messages.error(request, "Utilisateur inexistant")
return redirect("/users/") return redirect("/users/")
elif object == 'adhesion': elif object == 'adhesion':
try: try:
object_instance = Adhesion.objects.get(pk=id) object_instance = Adhesion.objects.get(pk=id)
except Adhesion.DoesNotExist: except Adhesion.DoesNotExist:
messages.error(request, "Utilisateur inexistant") messages.error(request, "Utilisateur inexistant")
return redirect("/users/") return redirect("/users/")
elif object == 'listright': elif object == 'listright':
try: try:
object_instance = ListRight.objects.get(pk=id) object_instance = ListRight.objects.get(pk=id)
except ListRight.DoesNotExist: except ListRight.DoesNotExist:
messages.error(request, "Droit inexistant") messages.error(request, "Droit inexistant")
return redirect("/users/") return redirect("/users/")
else: else:
messages.error(request, "Objet inconnu") messages.error(request, "Objet inconnu")
return redirect("/users/") return redirect("/users/")
@ -464,10 +466,12 @@ def history(request, object, id):
reversions = paginator.page(paginator.num_pages) reversions = paginator.page(paginator.num_pages)
return render(request, 'med/history.html', {'reversions': reversions, 'object': object_instance}) return render(request, 'med/history.html', {'reversions': reversions, 'object': object_instance})
@login_required @login_required
def mon_profil(request): def mon_profil(request):
return redirect("/users/profil/" + str(request.user.id)) return redirect("/users/profil/" + str(request.user.id))
@login_required @login_required
def profil(request, userid): def profil(request, userid):
try: try:
@ -486,10 +490,11 @@ def profil(request, userid):
{ {
'user': users, 'user': users,
'emprunts_list': emprunts_list, 'emprunts_list': emprunts_list,
'list_droits': list_droits, 'list_droits': list_droits,
} }
) )
@login_required @login_required
@permission_required('bureau') @permission_required('bureau')
def adherer(request, userid): def adherer(request, userid):
@ -506,13 +511,13 @@ def adherer(request, userid):
reversion.set_comment("Adhesion de %s" % users) reversion.set_comment("Adhesion de %s" % users)
messages.success(request, "Adhesion effectuee") messages.success(request, "Adhesion effectuee")
return redirect("/users/profil/" + userid) return redirect("/users/profil/" + userid)
def reset_password(request): def reset_password(request):
userform = ResetPasswordForm(request.POST or None) userform = ResetPasswordForm(request.POST or None)
if userform.is_valid(): if userform.is_valid():
try: try:
user = User.objects.get(pseudo=userform.cleaned_data['pseudo'],email=userform.cleaned_data['email']) user = User.objects.get(pseudo=userform.cleaned_data['pseudo'], email=userform.cleaned_data['email'])
except User.DoesNotExist: except User.DoesNotExist:
messages.error(request, "Cet utilisateur n'existe pas") messages.error(request, "Cet utilisateur n'existe pas")
return form({'userform': userform}, 'users/user.html', request) return form({'userform': userform}, 'users/user.html', request)
@ -525,6 +530,7 @@ def reset_password(request):
redirect("/") redirect("/")
return form({'userform': userform}, 'users/user.html', request) return form({'userform': userform}, 'users/user.html', request)
def process(request, token): def process(request, token):
valid_reqs = Request.objects.filter(expires_at__gt=timezone.now()) valid_reqs = Request.objects.filter(expires_at__gt=timezone.now())
req = get_object_or_404(valid_reqs, token=token) req = get_object_or_404(valid_reqs, token=token)
@ -537,6 +543,7 @@ def process(request, token):
messages.error(request, "Entrée incorrecte, contactez un admin") messages.error(request, "Entrée incorrecte, contactez un admin")
redirect("/") redirect("/")
def process_passwd(request, req): def process_passwd(request, req):
u_form = PassForm(request.POST or None) u_form = PassForm(request.POST or None)
user = req.user user = req.user