8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-26 22:52:26 +00:00

Pep8 compliance on re2o

This commit is contained in:
Maël Kervella 2018-04-13 23:42:22 +00:00
parent 287ce23d1c
commit 48d904b6de
19 changed files with 313 additions and 224 deletions

View file

@ -26,6 +26,7 @@
Here are defined some functions to check acl on the application.
"""
def can_view(user):
"""Check if an user can view the application.

View file

@ -44,12 +44,16 @@ class EditOptionalUserForm(ModelForm):
prefix=prefix,
**kwargs
)
self.fields['is_tel_mandatory'].label = 'Exiger un numéro de\
téléphone'
self.fields['user_solde'].label = 'Activation du solde pour\
les utilisateurs'
self.fields['is_tel_mandatory'].label = (
'Exiger un numéro de téléphone'
)
self.fields['user_solde'].label = (
'Activation du solde pour les utilisateurs'
)
self.fields['max_solde'].label = 'Solde maximum'
self.fields['min_online_payment'].label = 'Montant de rechargement minimum en ligne'
self.fields['min_online_payment'].label = (
'Montant de rechargement minimum en ligne'
)
self.fields['self_adhesion'].label = 'Auto inscription'
@ -162,7 +166,6 @@ class EditAssoOptionForm(ModelForm):
return cleaned_data
class EditMailMessageOptionForm(ModelForm):
"""Formulaire d'edition des messages de bienvenue personnalisés"""
class Meta:

View file

@ -36,6 +36,7 @@ from django.core.cache import cache
from .aes_field import AESEncryptedField
from re2o.mixins import AclMixin
class PreferencesModel(models.Model):
@classmethod
def set_in_cache(cls):
@ -46,7 +47,7 @@ class PreferencesModel(models.Model):
@classmethod
def get_cached_value(cls, key):
instance = cache.get(cls().__class__.__name__.lower())
if instance == None:
if instance is None:
instance = cls.set_in_cache()
return getattr(instance, key)
@ -146,7 +147,7 @@ class OptionalMachine(AclMixin, PreferencesModel):
@cached_property
def ipv6(self):
return not self.get_cached_value('ipv6_mode') == 'DISABLED'
return not self.get_cached_value('ipv6_mode') == 'DISABLED'
class Meta:
permissions = (
@ -230,7 +231,7 @@ class GeneralOption(AclMixin, PreferencesModel):
blank=True,
)
GTU = models.FileField(
upload_to = '',
upload_to='',
default="",
null=True,
blank=True,

View file

@ -73,7 +73,7 @@ urlpatterns = [
r'^history/(?P<object_name>\w+)/(?P<object_id>[0-9]+)$',
re2o.views.history,
name='history',
kwargs={'application':'preferences'},
kwargs={'application': 'preferences'},
),
url(r'^$', views.display_options, name='display-options'),
]

View file

@ -128,7 +128,7 @@ def add_service(request):
messages.success(request, "Ce service a été ajouté")
return redirect(reverse('preferences:display-options'))
return form(
{'preferenceform': service, 'action_name' : 'Ajouter'},
{'preferenceform': service, 'action_name': 'Ajouter'},
'preferences/preferences.html',
request
)
@ -151,7 +151,7 @@ def edit_service(request, service_instance, serviceid):
messages.success(request, "Service modifié")
return redirect(reverse('preferences:display-options'))
return form(
{'preferenceform': service, 'action_name' : 'Editer'},
{'preferenceform': service, 'action_name': 'Editer'},
'preferences/preferences.html',
request
)
@ -175,7 +175,7 @@ def del_services(request, instances):
suivant %s ne peut être supprimé" % services_del)
return redirect(reverse('preferences:display-options'))
return form(
{'preferenceform': services, 'action_name' : 'Supprimer'},
{'preferenceform': services, 'action_name': 'Supprimer'},
'preferences/preferences.html',
request
)

View file

@ -20,4 +20,3 @@
# 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,3 +1,28 @@
#!/usr/bin/env python3
CONTRIBUTORS = ['Gabriel "Chirac" Détraz', 'Maël "MoaMoaK" Kervella', 'Hugo "Klafyvel" Levy--Falk', 'Augustin "Dahlaro" Lemesle', 'Goulven "Lhark" Kermarec', 'Guillaume "Guimoz" Goessel', 'Yoann "Nanoy" Pietri', 'Matthieu "Lebanni" Michelet', 'Arthur "Grizzly" Grisel-Davy', 'Simon "Rezatoune" Brélivet', 'Sellem Lev-Arcady', 'David "5-1" Sinquin', 'Pierre "Redstorm" Cadart', 'Éloi "Goslig" Alain', 'Laouen "Volgarr" Fernet', 'Joanne Steiner', '"Krokmou"', 'Thibault "Tipunchetrhum" de Boutray', 'Baptiste "B" Fournier', 'Daniel "Dstan" Stan', 'Hugo "Shaka" Hervieux', '"Mikachu"', 'Thomas "Nymous" Gaudin', '"Esum"']
CONTRIBUTORS = [
'Gabriel "Chirac" Détraz',
'Maël "MoaMoaK" Kervella',
'Hugo "Klafyvel" Levy--Falk',
'Augustin "Dahlaro" Lemesle',
'Goulven "Lhark" Kermarec',
'Guillaume "Guimoz" Goessel',
'Yoann "Nanoy" Pietri',
'Matthieu "Lebanni" Michelet',
'Arthur "Grizzly" Grisel-Davy',
'Simon "Rezatoune" Brélivet',
'Sellem Lev-Arcady',
'David "5-1" Sinquin',
'Pierre "Redstorm" Cadart',
'Éloi "Goslig" Alain',
'Laouen "Volgarr" Fernet',
'Joanne Steiner',
'"Krokmou"',
'Thibault "Tipunchetrhum" de Boutray',
'Baptiste "B" Fournier',
'Daniel "Dstan" Stan',
'Hugo "Shaka" Hervieux',
'"Mikachu"',
'Thomas "Nymous" Gaudin',
'"Esum"'
]

View file

@ -43,13 +43,15 @@ class FieldPermissionModelMixin:
if result is not None:
return result
else:
result = user.has_perm(perm) # Don't supply 'obj', or else infinite recursion.
# Don't supply 'obj', or else infinite recursion.
result = user.has_perm(perm)
if result:
return True
# If no requirement can be met, then permission is denied.
return False
class FieldPermissionModel(FieldPermissionModelMixin, models.Model):
class Meta:
abstract = True
@ -76,4 +78,3 @@ class FieldPermissionFormMixin:
class FieldPermissionForm(FieldPermissionFormMixin, forms.ModelForm):
pass

View file

@ -20,18 +20,23 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Write in a python file the list of all contributors sorted by number of commits.
This list is extracted from the FedeRez gitlab repository.
Write in a python file the list of all contributors sorted by number of
commits. This list is extracted from the current gitlab repository.
"""
from django.core.management.base import BaseCommand, CommandError
import os
class Command(BaseCommand):
help = 'Update contributors list'
help = 'Update contributors list'
def handle(self, *args, **options):
contributeurs = [item.split('\t')[1] for item in os.popen("git shortlog -s -n").read().split("\n") if '\t' in item]
contributeurs = [
item.split('\t')[1]
for item in os.popen("git shortlog -s -n").read().split("\n")
if '\t' in item
]
self.stdout.write(self.style.SUCCESS("Exportation Sucessfull"))
with open("re2o/contributors.py", "w") as contrib_file:
contrib_file.write("#!/usr/bin/env python3\n")

View file

@ -37,9 +37,15 @@ class RevMixin(object):
class FormRevMixin(object):
def save(self, *args, **kwargs):
if reversion.get_comment() != "" and self.changed_data != []:
reversion.set_comment(reversion.get_comment() + ",%s" % ', '.join(field for field in self.changed_data))
reversion.set_comment(
reversion.get_comment() + ",%s"
% ', '.join(field for field in self.changed_data)
)
elif self.changed_data:
reversion.set_comment("Champs modifié(s) : %s" % ', '.join(field for field in self.changed_data))
reversion.set_comment(
"Champs modifié(s) : %s"
% ', '.join(field for field in self.changed_data)
)
return super(FormRevMixin, self).save(*args, **kwargs)
@ -47,12 +53,16 @@ class AclMixin(object):
"""This mixin is used in nearly every class/models defined in re2o apps.
It is used by acl, in models (decorators can_...) and in templates tags
:get_instance: Applied on a class, take an id argument, return an instance
:can_create: Applied on a class, take the requested user, return if the user
can do the creation
:can_edit: Applied on an instance, return if the user can edit the instance
:can_delete: Applied on an instance, return if the user can delete the instance
:can_view: Applied on an instance, return if the user can view the instance
:can_view_all: Applied on a class, return if the user can view all instances"""
:can_create: Applied on a class, take the requested user, return if the
user can do the creation
:can_edit: Applied on an instance, return if the user can edit the
instance
:can_delete: Applied on an instance, return if the user can delete the
instance
:can_view: Applied on an instance, return if the user can view the
instance
:can_view_all: Applied on a class, return if the user can view all
instances"""
@classmethod
def get_classname(cls):
@ -76,8 +86,12 @@ class AclMixin(object):
un object
:param user_request: instance utilisateur qui fait la requête
:return: soit True, soit False avec la raison de l'échec"""
return user_request.has_perm(cls.get_modulename() + '.add_' + cls.get_classname()), u"Vous n'avez pas le droit\
de créer un " + cls.get_classname()
return (
user_request.has_perm(
cls.get_modulename() + '.add_' + cls.get_classname()
),
u"Vous n'avez pas le droit de créer un " + cls.get_classname()
)
def can_edit(self, user_request, *args, **kwargs):
"""Verifie que l'user a les bons droits pour editer
@ -85,7 +99,12 @@ class AclMixin(object):
:param self: Instance à editer
:param user_request: Utilisateur qui fait la requête
:return: soit True, soit False avec la raison de l'échec"""
return user_request.has_perm(self.get_modulename() + '.change_' + self.get_classname()), u"Vous n'avez pas le droit d'éditer des " + self.get_classname()
return (
user_request.has_perm(
self.get_modulename() + '.change_' + self.get_classname()
),
u"Vous n'avez pas le droit d'éditer des " + self.get_classname()
)
def can_delete(self, user_request, *args, **kwargs):
"""Verifie que l'user a les bons droits pour delete
@ -93,7 +112,12 @@ class AclMixin(object):
:param self: Instance à delete
:param user_request: Utilisateur qui fait la requête
:return: soit True, soit False avec la raison de l'échec"""
return user_request.has_perm(self.get_modulename() + '.delete_' + self.get_classname()), u"Vous n'avez pas le droit d'éditer des " + self.get_classname()
return (
user_request.has_perm(
self.get_modulename() + '.delete_' + self.get_classname()
),
u"Vous n'avez pas le droit d'éditer des " + self.get_classname()
)
@classmethod
def can_view_all(cls, user_request, *args, **kwargs):
@ -101,7 +125,12 @@ class AclMixin(object):
droit particulier view objet correspondant
:param user_request: instance user qui fait l'edition
:return: True ou False avec la raison de l'échec le cas échéant"""
return user_request.has_perm(cls.get_modulename() + '.view_' + cls.get_classname()), u"Vous n'avez pas le droit de voir des " + cls.get_classname()
return (
user_request.has_perm(
cls.get_modulename() + '.view_' + cls.get_classname()
),
u"Vous n'avez pas le droit de voir des " + cls.get_classname()
)
def can_view(self, user_request, *args, **kwargs):
"""Vérifie qu'on peut bien voir cette instance particulière avec
@ -109,4 +138,9 @@ class AclMixin(object):
:param self: instance à voir
:param user_request: instance user qui fait l'edition
:return: True ou False avec la raison de l'échec le cas échéant"""
return user_request.has_perm(self.get_modulename() + '.view_' + self.get_classname()), u"Vous n'avez pas le droit de voir des " + self.get_classname()
return (
user_request.has_perm(
self.get_modulename() + '.view_' + self.get_classname()
),
u"Vous n'avez pas le droit de voir des " + self.get_classname()
)

View file

@ -19,15 +19,11 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import os, sys, pwd
import os
import sys
import pwd
proj_path="/var/www/re2o"
os.environ.setdefault("DJANGO_SETTINGS_MODULE","re2o.settings")
sys.path.append(proj_path)
os.chdir(proj_path)
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
from django.core.management.base import CommandError
from users.models import User
@ -37,14 +33,22 @@ from reversion import revisions as reversion
from django.db import transaction
from getpass import getpass
proj_path = "/var/www/re2o"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "re2o.settings")
sys.path.append(proj_path)
os.chdir(proj_path)
application = get_wsgi_application()
def get_user(pseudo):
"""Cherche un utilisateur re2o à partir de son pseudo"""
user = User.objects.filter(pseudo=pseudo)
if len(user)==0:
if len(user) == 0:
raise CommandError("Utilisateur invalide")
if len(user)>1:
raise CommandError("Plusieurs utilisateurs correspondant à ce pseudo. Ceci NE DEVRAIT PAS arriver")
if len(user) > 1:
raise CommandError("Plusieurs utilisateurs correspondant à ce "
"pseudo. Ceci NE DEVRAIT PAS arriver")
return user[0]
@ -53,7 +57,7 @@ def get_system_user():
return pwd.getpwuid(int(os.getenv("SUDO_UID") or os.getuid())).pw_name
def form_cli(Form,user,action,*args,**kwargs):
def form_cli(Form, user, action, *args, **kwargs):
"""
Remplit un formulaire à partir de la ligne de commande
Form : le formulaire (sous forme de classe) à remplir
@ -61,26 +65,30 @@ def form_cli(Form,user,action,*args,**kwargs):
action : l'action réalisée par le formulaire (pour les logs)
Les arguments suivants sont transmis tels quels au formulaire.
"""
data={}
dumb_form = Form(user=user,*args,**kwargs)
data = {}
dumb_form = Form(user=user, *args, **kwargs)
for key in dumb_form.fields:
if not dumb_form.fields[key].widget.input_type=='hidden':
if dumb_form.fields[key].widget.input_type=='password':
data[key]=getpass("%s : " % dumb_form.fields[key].label)
if not dumb_form.fields[key].widget.input_type == 'hidden':
if dumb_form.fields[key].widget.input_type == 'password':
data[key] = getpass("%s : " % dumb_form.fields[key].label)
else:
data[key]=input("%s : " % dumb_form.fields[key].label)
data[key] = input("%s : " % dumb_form.fields[key].label)
form = Form(data,user=user,*args,**kwargs)
form = Form(data, user=user, *args, **kwargs)
if not form.is_valid():
sys.stderr.write("Erreurs : \n")
for err in form.errors:
#Oui, oui, on gère du HTML là où d'autres ont eu la lumineuse idée de le mettre
sys.stderr.write("\t%s : %s\n" % (err,strip_tags(form.errors[err])))
# Oui, oui, on gère du HTML là où d'autres ont eu la
# lumineuse idée de le mettre
sys.stderr.write(
"\t%s : %s\n" % (err, strip_tags(form.errors[err]))
)
raise CommandError("Formulaire invalide")
with transaction.atomic(), reversion.create_revision():
form.save()
reversion.set_user(user)
reversion.set_comment(action)
form.save()
reversion.set_user(user)
reversion.set_comment(action)
sys.stdout.write("%s : effectué. La modification peut prendre quelques minutes pour s'appliquer.\n" % action)
sys.stdout.write("%s : effectué. La modification peut prendre "
"quelques minutes pour s'appliquer.\n" % action)

View file

@ -126,7 +126,7 @@ LANGUAGE_CODE = 'en'
# Proritary location search for translations
# then searches in {app}/locale/ for app in INSTALLED_APPS
LOCALE_PATHS = [
BASE_DIR + '/templates/locale/' # to define translations outside of apps
BASE_DIR + '/templates/locale/' # For translations outside of apps
]
TIME_ZONE = 'Europe/Paris'

View file

@ -73,23 +73,22 @@ EMAIL_PORT = MY_EMAIL_PORT
# Reglages pour la bdd ldap
LDAP = {
'base_user_dn' : 'cn=Utilisateurs,dc=example,dc=org',
'base_userservice_dn' : 'ou=service-users,dc=example,dc=org',
'base_usergroup_dn' : 'ou=posix,ou=groups,dc=example,dc=org',
'base_userservicegroup_dn' : 'ou=services,ou=groups,dc=example,dc=org',
'user_gid' : 500,
'base_user_dn': 'cn=Utilisateurs,dc=example,dc=org',
'base_userservice_dn': 'ou=service-users,dc=example,dc=org',
'base_usergroup_dn': 'ou=posix,ou=groups,dc=example,dc=org',
'base_userservicegroup_dn': 'ou=services,ou=groups,dc=example,dc=org',
'user_gid': 500,
}
UID_RANGES = {
'users' : [21001,30000],
'service-users' : [20000,21000],
'users': [21001, 30000],
'service-users': [20000, 21000],
}
# Chaque groupe a un gid assigné, voici la place libre pour assignation
GID_RANGES = {
'posix' : [501, 600],
'posix': [501, 600],
}
OPTIONNAL_APPS = ()

View file

@ -18,4 +18,3 @@
# 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

@ -85,32 +85,32 @@ register = template.Library()
MODEL_NAME = {
# cotisations
'Facture' : cotisations.models.Facture,
'Vente' : cotisations.models.Vente,
'Article' : cotisations.models.Article,
'Banque' : cotisations.models.Banque,
'Paiement' : cotisations.models.Paiement,
'Cotisation' : cotisations.models.Cotisation,
'Facture': cotisations.models.Facture,
'Vente': cotisations.models.Vente,
'Article': cotisations.models.Article,
'Banque': cotisations.models.Banque,
'Paiement': cotisations.models.Paiement,
'Cotisation': cotisations.models.Cotisation,
# machines
'Machine' : machines.models.Machine,
'MachineType' : machines.models.MachineType,
'IpType' : machines.models.IpType,
'Vlan' : machines.models.Vlan,
'Nas' : machines.models.Nas,
'SOA' : machines.models.SOA,
'Extension' : machines.models.Extension,
'Mx' : machines.models.Mx,
'Ns' : machines.models.Ns,
'Txt' : machines.models.Txt,
'Srv' : machines.models.Srv,
'Interface' : machines.models.Interface,
'Domain' : machines.models.Domain,
'IpList' : machines.models.IpList,
'Ipv6List' : machines.models.Ipv6List,
'machines.Service' : machines.models.Service,
'Service_link' : machines.models.Service_link,
'OuverturePortList' : machines.models.OuverturePortList,
'OuverturePort' : machines.models.OuverturePort,
'Machine': machines.models.Machine,
'MachineType': machines.models.MachineType,
'IpType': machines.models.IpType,
'Vlan': machines.models.Vlan,
'Nas': machines.models.Nas,
'SOA': machines.models.SOA,
'Extension': machines.models.Extension,
'Mx': machines.models.Mx,
'Ns': machines.models.Ns,
'Txt': machines.models.Txt,
'Srv': machines.models.Srv,
'Interface': machines.models.Interface,
'Domain': machines.models.Domain,
'IpList': machines.models.IpList,
'Ipv6List': machines.models.Ipv6List,
'machines.Service': machines.models.Service,
'Service_link': machines.models.Service_link,
'OuverturePortList': machines.models.OuverturePortList,
'OuverturePort': machines.models.OuverturePort,
# preferences
'OptionalUser': preferences.models.OptionalUser,
'OptionalMachine': preferences.models.OptionalMachine,
@ -120,25 +120,25 @@ MODEL_NAME = {
'AssoOption': preferences.models.AssoOption,
'MailMessageOption': preferences.models.MailMessageOption,
# topologie
'Stack' : topologie.models.Stack,
'Switch' : topologie.models.Switch,
'AccessPoint' : topologie.models.AccessPoint,
'ModelSwitch' : topologie.models.ModelSwitch,
'ConstructorSwitch' : topologie.models.ConstructorSwitch,
'Port' : topologie.models.Port,
'Room' : topologie.models.Room,
'Building' : topologie.models.Building,
'SwitchBay' : topologie.models.SwitchBay,
'Stack': topologie.models.Stack,
'Switch': topologie.models.Switch,
'AccessPoint': topologie.models.AccessPoint,
'ModelSwitch': topologie.models.ModelSwitch,
'ConstructorSwitch': topologie.models.ConstructorSwitch,
'Port': topologie.models.Port,
'Room': topologie.models.Room,
'Building': topologie.models.Building,
'SwitchBay': topologie.models.SwitchBay,
# users
'User' : users.models.User,
'Adherent' : users.models.Adherent,
'Club' : users.models.Club,
'ServiceUser' : users.models.ServiceUser,
'School' : users.models.School,
'ListRight' : users.models.ListRight,
'ListShell' : users.models.ListShell,
'Ban' : users.models.Ban,
'Whitelist' : users.models.Whitelist,
'User': users.models.User,
'Adherent': users.models.Adherent,
'Club': users.models.Club,
'ServiceUser': users.models.ServiceUser,
'School': users.models.School,
'ListRight': users.models.ListRight,
'ListShell': users.models.ListShell,
'Ban': users.models.Ban,
'Whitelist': users.models.Whitelist,
}
@ -184,17 +184,41 @@ def get_callback(tag_name, obj=None):
if tag_name == 'cannot_view_all':
return acl_fct(obj.can_view_all, True)
if tag_name == 'can_view_app':
return acl_fct(lambda x : (not any(not sys.modules[o].can_view(x) for o in obj), None), False)
return acl_fct(
lambda x: (
not any(not sys.modules[o].can_view(x) for o in obj),
None
),
False
)
if tag_name == 'cannot_view_app':
return acl_fct(lambda x : (not any(not sys.modules[o].can_view(x) for o in obj), None), True)
return acl_fct(
lambda x: (
not any(not sys.modules[o].can_view(x) for o in obj),
None
),
True
)
if tag_name == 'can_edit_history':
return acl_fct(lambda user:(user.has_perm('admin.change_logentry'),None),False)
return acl_fct(
lambda user: (user.has_perm('admin.change_logentry'), None),
False
)
if tag_name == 'cannot_edit_history':
return acl_fct(lambda user:(user.has_perm('admin.change_logentry'),None),True)
return acl_fct(
lambda user: (user.has_perm('admin.change_logentry'), None),
True
)
if tag_name == 'can_view_any_app':
return acl_fct(lambda x : (any(sys.modules[o].can_view(x) for o in obj), None), False)
return acl_fct(
lambda x: (any(sys.modules[o].can_view(x) for o in obj), None),
False
)
if tag_name == 'cannot_view_any_app':
return acl_fct(lambda x : (any(sys.modules[o].can_view(x) for o in obj), None), True)
return acl_fct(
lambda x: (any(sys.modules[o].can_view(x) for o in obj), None),
True
)
raise template.TemplateSyntaxError(
"%r tag is not a valid can_xxx tag" % tag_name
@ -246,11 +270,11 @@ def acl_app_filter(parser, token):
tag_name, *app_name = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError(
"%r tag require 1 argument : an application"
"%r tag require 1 argument: an application"
% token.contents.split()[0]
)
for name in app_name:
if not name in sys.modules.keys():
if name not in sys.modules.keys():
raise template.TemplateSyntaxError(
"%r is not a registered application for acl."
% name
@ -270,6 +294,7 @@ def acl_app_filter(parser, token):
return AclNode(callback, oknodes, konodes)
@register.tag('can_change')
@register.tag('cannot_change')
def acl_change_filter(parser, token):
@ -283,7 +308,7 @@ def acl_change_filter(parser, token):
args = tag_content[3:]
except ValueError:
raise template.TemplateSyntaxError(
"%r tag require at least 2 argument : the model and the field"
"%r tag require at least 2 argument: the model and the field"
% token.contents.split()[0]
)
@ -306,6 +331,7 @@ def acl_change_filter(parser, token):
return AclNode(callback, oknodes, konodes, *args)
@register.tag('can_create')
@register.tag('cannot_create')
@register.tag('can_edit_all')
@ -324,7 +350,7 @@ def acl_model_filter(parser, token):
args = tag_content[2:]
except ValueError:
raise template.TemplateSyntaxError(
"%r tag require at least 1 argument : the model"
"%r tag require at least 1 argument: the model"
% token.contents.split()[0]
)
@ -364,7 +390,7 @@ def acl_instance_filter(parser, token):
args = tag_content[2:]
except ValueError:
raise template.TemplateSyntaxError(
"%r tag require at least 1 argument : the instance"
"%r tag require at least 1 argument: the instance"
% token.contents.split()[0]
)

View file

@ -36,13 +36,14 @@ from bootstrap3.forms import render_field
register = template.Library()
@register.simple_tag
def massive_bootstrap_form(form, mbf_fields, *args, **kwargs):
"""
Render a form where some specific fields are rendered using Twitter
Typeahead and/or splitree's Bootstrap Tokenfield to improve the performance, the
speed and UX when dealing with very large datasets (select with 50k+ elts
for instance).
Typeahead and/or splitree's Bootstrap Tokenfield to improve the
performance, the speed and UX when dealing with very large datasets
(select with 50k+ elts for instance).
When the fields specified should normally be rendered as a select with
single selectable option, Twitter Typeahead is used for a better display
and the matching query engine. When dealing with multiple selectable
@ -189,8 +190,6 @@ def massive_bootstrap_form(form, mbf_fields, *args, **kwargs):
return mbf_form.render()
class MBFForm():
""" An object to hold all the information and useful methods needed to
create and render a massive django form into an actual HTML and JS
@ -198,7 +197,6 @@ class MBFForm():
Every field that is not listed is rendered as a normal bootstrap_field.
"""
def __init__(self, form, mbf_fields, *args, **kwargs):
# The django form object
self.form = form
@ -224,14 +222,13 @@ class MBFForm():
# HTML code to insert inside a template
self.html = ""
def render(self):
""" HTML code for the fully rendered form with all the necessary form
"""
for name, field in self.form.fields.items():
if not name in self.exclude:
if name not in self.exclude:
if name in self.fields and not name in self.hidden_fields:
if name in self.fields and name not in self.hidden_fields:
mbf_field = MBFField(
name,
field,
@ -256,9 +253,6 @@ class MBFForm():
return mark_safe(self.html)
class MBFField():
""" An object to hold all the information and useful methods needed to
create and render a massive django form field into an actual HTML and JS
@ -270,7 +264,6 @@ class MBFField():
the displayed input. It's used to store the actual data that will be sent
to the server """
def __init__(self, name_, field_, bound_, choices_, engine_, match_func_,
update_on_, gen_select_, *args_, **kwargs_):
@ -278,8 +271,8 @@ class MBFField():
if not isinstance(field_.widget, Select):
raise ValueError(
('Field named {f_name} is not a Select and'
'can\'t be rendered with massive_bootstrap_form.'
).format(
'can\'t be rendered with massive_bootstrap_form.')
.format(
f_name=name_
)
)
@ -324,7 +317,6 @@ class MBFField():
self.args = args_
self.kwargs = kwargs_
def default_choices(self):
""" JS code of the variable choices_<fieldname> """
@ -351,7 +343,6 @@ class MBFField():
)
)
def default_engine(self):
""" Default JS code of the variable engine_<field_name> """
return (
@ -365,7 +356,6 @@ class MBFField():
name=self.name
)
def default_datasets(self):
""" Default JS script of the datasets to use with typeahead """
return (
@ -384,7 +374,6 @@ class MBFField():
match_func=self.match_func
)
def default_match_func(self):
""" Default JS code of the matching function to use with typeahed """
return (
@ -402,14 +391,12 @@ class MBFField():
name=self.name
)
def render(self):
""" HTML code for the fully rendered field """
self.gen_displayed_div()
self.gen_hidden_div()
return mark_safe(self.html)
def gen_displayed_div(self):
""" Generate HTML code for the div that contains displayed tags """
if self.gen_select:
@ -434,7 +421,6 @@ class MBFField():
if not self.gen_select:
self.html += self.replace_input
def gen_hidden_div(self):
""" Generate HTML code for the div that contains hidden tags """
self.gen_full_js()
@ -449,7 +435,6 @@ class MBFField():
attrs={'id': self.div2_id}
)
def hidden_input(self):
""" HTML for the hidden input element """
return render_tag(
@ -462,14 +447,12 @@ class MBFField():
}
)
def gen_full_js(self):
""" Generate the full script tag containing the JS code """
self.create_js()
self.fill_js()
self.get_script()
def create_js(self):
""" Generate a template for the whole script to use depending on
gen_select and multiple """
@ -549,7 +532,6 @@ class MBFField():
'}} );'
)
def fill_js(self):
""" Fill the template with the correct values """
self.js_script = self.js_script.format(
@ -571,11 +553,12 @@ class MBFField():
typ_init_input=self.typeahead_init_input()
)
def get_script(self):
""" Insert the JS code inside a script tag """
self.js_script = render_tag('script', content=mark_safe(self.js_script))
self.js_script = render_tag(
'script',
content=mark_safe(self.js_script)
)
def del_select(self):
""" JS code to delete the select if it has been generated and replace
@ -589,7 +572,6 @@ class MBFField():
replace_input=self.replace_input
)
def gen_hidden(self):
""" JS code to add a hidden tag to store the value. """
return (
@ -606,7 +588,6 @@ class MBFField():
html_name=self.bound.html_name
)
def typeahead_init_input(self):
""" JS code to init the fields values """
init_key = self.bound.value() or '""'
@ -624,7 +605,6 @@ class MBFField():
hidden_id=self.hidden_id
)
def typeahead_reset_input(self):
""" JS code to reset the fields values """
return (
@ -635,7 +615,6 @@ class MBFField():
hidden_id=self.hidden_id
)
def typeahead_select(self):
""" JS code to create the function triggered when an item is selected
through typeahead """
@ -649,7 +628,6 @@ class MBFField():
hidden_id=self.hidden_id
)
def typeahead_change(self):
""" JS code of the function triggered when an item is changed (i.e.
looses focus and value has changed since the moment it gained focus )
@ -666,7 +644,6 @@ class MBFField():
hidden_id=self.hidden_id
)
def typeahead_updates(self):
""" JS code for binding external fields changes with a reset """
reset_input = self.typeahead_reset_input()
@ -683,7 +660,6 @@ class MBFField():
) for u_id in self.update_on]
return ''.join(updates)
def tokenfield_init_input(self):
""" JS code to init the fields values """
init_key = self.bound.value() or '""'
@ -700,7 +676,6 @@ class MBFField():
)
)
def tokenfield_reset_input(self):
""" JS code to reset the fields values """
return (
@ -709,7 +684,6 @@ class MBFField():
input_id=self.input_id
)
def tokenfield_create(self):
""" JS code triggered when a new token is created in tokenfield. """
return (
@ -739,7 +713,6 @@ class MBFField():
div2_id=self.div2_id
)
def tokenfield_edit(self):
""" JS code triggered when a token is edited in tokenfield. """
return (
@ -765,7 +738,6 @@ class MBFField():
hidden_id=self.hidden_id
)
def tokenfield_remove(self):
""" JS code trigggered when a token is removed from tokenfield. """
return (
@ -791,7 +763,6 @@ class MBFField():
hidden_id=self.hidden_id
)
def tokenfield_updates(self):
""" JS code for binding external fields changes with a reset """
reset_input = self.tokenfield_reset_input()

View file

@ -24,6 +24,7 @@ from preferences.models import OptionalUser, GeneralOption
register = template.Library()
@register.simple_tag
def self_adhesion():
options, _created = OptionalUser.objects.get_or_create()

View file

@ -118,14 +118,18 @@ def all_has_access(search_time=None):
def filter_active_interfaces(interface_set):
"""Filtre les machines autorisées à sortir sur internet dans une requête"""
return interface_set.filter(
machine__in=Machine.objects.filter(
user__in=all_has_access()
).filter(active=True)
).select_related('domain').select_related('machine')\
.select_related('type').select_related('ipv4')\
.select_related('domain__extension').select_related('ipv4__ip_type')\
.distinct()
return (interface_set
.filter(
machine__in=Machine.objects.filter(
user__in=all_has_access()
).filter(active=True)
).select_related('domain')
.select_related('machine')
.select_related('type')
.select_related('ipv4')
.select_related('domain__extension')
.select_related('ipv4__ip_type')
.distinct())
def filter_complete_interfaces(interface_set):
@ -160,6 +164,7 @@ def all_active_assigned_interfaces_count():
""" Version light seulement pour compter"""
return all_active_interfaces_count().filter(ipv4__isnull=False)
class SortTable:
""" Class gathering uselful stuff to sort the colums of a table, according
to the column and order requested. It's used with a dict of possible
@ -171,7 +176,8 @@ class SortTable:
# the url value and the values are a list of model field name to use to
# order the request. They are applied in the order they are given.
# A 'default' might be provided to specify what to do if the requested col
# doesn't match any keys.
# doesn't match any keys.
USERS_INDEX = {
'user_name': ['name'],
'user_surname': ['surname'],
@ -255,7 +261,7 @@ class SortTable:
}
TOPOLOGIE_INDEX_MODEL_SWITCH = {
'model-switch_name': ['reference'],
'model-switch_contructor' : ['constructor__name'],
'model-switch_contructor': ['constructor__name'],
'default': ['reference'],
}
TOPOLOGIE_INDEX_SWITCH_BAY = {
@ -290,6 +296,7 @@ class SortTable:
else:
return request
def re2o_paginator(request, query_set, pagination_number):
"""Paginator script for list display in re2o.
:request:
@ -307,6 +314,7 @@ def re2o_paginator(request, query_set, pagination_number):
results = paginator.page(paginator.num_pages)
return results
def remove_user_room(room):
""" Déménage de force l'ancien locataire de la chambre """
try:

View file

@ -44,12 +44,17 @@ from itertools import chain
from preferences.models import Service
from preferences.models import OptionalUser, GeneralOption, AssoOption
import users, preferences, cotisations, topologie, machines
import users
import preferences
import cotisations
import topologie
import machines
from .utils import re2o_paginator
from .settings import BASE_DIR, INSTALLED_APPS, MIDDLEWARE_CLASSES
from .contributors import CONTRIBUTORS
def form(ctx, template, request):
"""Form générique, raccourci importé par les fonctions views du site"""
context = ctx
@ -64,56 +69,58 @@ def index(request):
services[indice % 3].append(serv)
return form({'services_urls': services}, 're2o/index.html', request)
#: Binding the corresponding char sequence of history url to re2o models.
HISTORY_BIND = {
'users' : {
'user' : users.models.User,
'ban' : users.models.Ban,
'whitelist' : users.models.Whitelist,
'school' : users.models.School,
'listright' : users.models.ListRight,
'serviceuser' : users.models.ServiceUser,
'listshell' : users.models.ListShell,
'users': {
'user': users.models.User,
'ban': users.models.Ban,
'whitelist': users.models.Whitelist,
'school': users.models.School,
'listright': users.models.ListRight,
'serviceuser': users.models.ServiceUser,
'listshell': users.models.ListShell,
},
'preferences' : {
'service' : preferences.models.Service,
'preferences': {
'service': preferences.models.Service,
},
'cotisations' : {
'facture' : cotisations.models.Facture,
'article' : cotisations.models.Article,
'paiement' : cotisations.models.Paiement,
'banque' : cotisations.models.Banque,
'cotisations': {
'facture': cotisations.models.Facture,
'article': cotisations.models.Article,
'paiement': cotisations.models.Paiement,
'banque': cotisations.models.Banque,
},
'topologie' : {
'switch' : topologie.models.Switch,
'port' : topologie.models.Port,
'room' : topologie.models.Room,
'stack' : topologie.models.Stack,
'modelswitch' : topologie.models.ModelSwitch,
'constructorswitch' : topologie.models.ConstructorSwitch,
'accesspoint' : topologie.models.AccessPoint,
'switchbay' : topologie.models.SwitchBay,
'building' : topologie.models.Building,
'topologie': {
'switch': topologie.models.Switch,
'port': topologie.models.Port,
'room': topologie.models.Room,
'stack': topologie.models.Stack,
'modelswitch': topologie.models.ModelSwitch,
'constructorswitch': topologie.models.ConstructorSwitch,
'accesspoint': topologie.models.AccessPoint,
'switchbay': topologie.models.SwitchBay,
'building': topologie.models.Building,
},
'machines' : {
'machine' : machines.models.Machine,
'interface' : machines.models.Interface,
'domain' : machines.models.Domain,
'machinetype' : machines.models.MachineType,
'iptype' : machines.models.IpType,
'extension' : machines.models.Extension,
'soa' : machines.models.SOA,
'mx' : machines.models.Mx,
'txt' : machines.models.Txt,
'srv' : machines.models.Srv,
'ns' : machines.models.Ns,
'service' : machines.models.Service,
'vlan' : machines.models.Vlan,
'nas' : machines.models.Nas,
'ipv6list' : machines.models.Ipv6List,
'machines': {
'machine': machines.models.Machine,
'interface': machines.models.Interface,
'domain': machines.models.Domain,
'machinetype': machines.models.MachineType,
'iptype': machines.models.IpType,
'extension': machines.models.Extension,
'soa': machines.models.SOA,
'mx': machines.models.Mx,
'txt': machines.models.Txt,
'srv': machines.models.Srv,
'ns': machines.models.Ns,
'service': machines.models.Service,
'vlan': machines.models.Vlan,
'nas': machines.models.Nas,
'ipv6list': machines.models.Ipv6List,
},
}
@login_required
def history(request, application, object_name, object_id):
"""Render history for a model.
@ -144,21 +151,23 @@ def history(request, application, object_name, object_id):
instance = model.get_instance(**kwargs)
except model.DoesNotExist:
messages.error(request, u"Entrée inexistante")
return redirect(reverse('users:profil',
kwargs={'userid':str(request.user.id)}
return redirect(reverse(
'users:profil',
kwargs={'userid': str(request.user.id)}
))
can, msg = instance.can_view(request.user)
if not can:
messages.error(request, msg or "Vous ne pouvez pas accéder à ce menu")
return redirect(reverse(
'users:profil',
kwargs={'userid':str(request.user.id)}
kwargs={'userid': str(request.user.id)}
))
pagination_number = GeneralOption.get_cached_value('pagination_number')
reversions = Version.objects.get_for_object(instance)
if hasattr(instance, 'linked_objects'):
for related_object in chain(instance.linked_objects()):
reversions = reversions | Version.objects.get_for_object(related_object)
reversions = (reversions |
Version.objects.get_for_object(related_object))
reversions = re2o_paginator(request, reversions, pagination_number)
return render(
request,
@ -191,8 +200,8 @@ def about_page(request):
request,
"re2o/about.html",
{
'description': option.description ,
'AssoName' : option.name ,
'description': option.description,
'AssoName': option.name,
'git_info_contributors': git_info_contributors,
'git_info_remote': git_info_remote,
'git_info_branch': git_info_branch,
@ -201,4 +210,3 @@ def about_page(request):
'dependencies': dependencies
}
)