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

Merge branch 'modularity_preferences_and_tickets_fix' into 'dev'

Modularity preferences and tickets fix

See merge request re2o/re2o!512
This commit is contained in:
klafyvel 2020-04-23 09:51:38 +02:00
commit 3fa0dc577a
28 changed files with 1221 additions and 554 deletions

View file

@ -256,57 +256,57 @@ msgstr "Modèles de document actuels"
msgid "Current attributes" msgid "Current attributes"
msgstr "Attributs actuels" msgstr "Attributs actuels"
#: preferences/models.py:78 #: preferences/models.py:56
msgid "Users can't select their room" msgid "Users can't select their room"
msgstr "Les utilisateurs ne peuvent pas modifier leur chambre" msgstr "Les utilisateurs ne peuvent pas modifier leur chambre"
#: preferences/models.py:79 #: preferences/models.py:57
msgid "" msgid ""
"Users can only select a room occupied by a user with a disabled connection." "Users can only select a room occupied by a user with a disabled connection."
msgstr "" msgstr ""
"Les utilisateurs peuvent sélectionner la chambre d'un adhérent dont la " "Les utilisateurs peuvent sélectionner la chambre d'un adhérent dont la "
"connexion est désactivée." "connexion est désactivée."
#: preferences/models.py:80 #: preferences/models.py:58
msgid "Users can select all rooms" msgid "Users can select all rooms"
msgstr "Les utilisateurs peuvent choisir toutes les chambres" msgstr "Les utilisateurs peuvent choisir toutes les chambres"
#: preferences/models.py:86 #: preferences/models.py:64
msgid "Users can create a club." msgid "Users can create a club."
msgstr "Les utilisateurs peuvent créer un club." msgstr "Les utilisateurs peuvent créer un club."
#: preferences/models.py:89 #: preferences/models.py:67
msgid "Users can create a member." msgid "Users can create a member."
msgstr "Les utilisateurs peuvent créer un adhérent." msgstr "Les utilisateurs peuvent créer un adhérent."
#: preferences/models.py:95 #: preferences/models.py:73
msgid "Users can edit their shell." msgid "Users can edit their shell."
msgstr "Les utilisateurs peuvent modifier leur interface en ligne de commande." msgstr "Les utilisateurs peuvent modifier leur interface en ligne de commande."
#: preferences/models.py:101 #: preferences/models.py:79
msgid "Policy on self users room edition" msgid "Policy on self users room edition"
msgstr "Autorisation d'édtion du champ chambre par les utilisateurs" msgstr "Autorisation d'édtion du champ chambre par les utilisateurs"
#: preferences/models.py:104 #: preferences/models.py:82
msgid "Enable local email accounts for users." msgid "Enable local email accounts for users."
msgstr "Activer les comptes mail locaux pour les utilisateurs." msgstr "Activer les comptes mail locaux pour les utilisateurs."
#: preferences/models.py:109 #: preferences/models.py:87
msgid "Domain to use for local email accounts." msgid "Domain to use for local email accounts."
msgstr "Domaine à utiliser pour les comptes mail locaux." msgstr "Domaine à utiliser pour les comptes mail locaux."
#: preferences/models.py:113 #: preferences/models.py:91
msgid "Maximum number of local email addresses for a standard user." msgid "Maximum number of local email addresses for a standard user."
msgstr "" msgstr ""
"Nombre maximum d'adresses mail locales autorisé pour un utilisateur standard." "Nombre maximum d'adresses mail locales autorisé pour un utilisateur standard."
#: preferences/models.py:118 #: preferences/models.py:96
msgid "Not yet active users will be deleted after this number of days." msgid "Not yet active users will be deleted after this number of days."
msgstr "" msgstr ""
"Les utilisateurs n'ayant jamais adhéré seront supprimés après ce nombre de " "Les utilisateurs n'ayant jamais adhéré seront supprimés après ce nombre de "
"jours." "jours."
#: preferences/models.py:124 #: preferences/models.py:102
msgid "" msgid ""
"Users with an email address not yet confirmed will be disabled after this " "Users with an email address not yet confirmed will be disabled after this "
"number of days." "number of days."
@ -314,11 +314,11 @@ msgstr ""
"Les utilisateurs n'ayant pas confirmé leur addresse mail seront désactivés " "Les utilisateurs n'ayant pas confirmé leur addresse mail seront désactivés "
"après ce nombre de jours" "après ce nombre de jours"
#: preferences/models.py:128 #: preferences/models.py:106
msgid "A new user can create their account on Re2o." msgid "A new user can create their account on Re2o."
msgstr "Un nouvel utilisateur peut créer son compte sur Re2o." msgstr "Un nouvel utilisateur peut créer son compte sur Re2o."
#: preferences/models.py:133 #: preferences/models.py:111
msgid "" msgid ""
"If True, all new created and connected users are active. If False, only when " "If True, all new created and connected users are active. If False, only when "
"a valid registration has been paid." "a valid registration has been paid."
@ -326,7 +326,7 @@ msgstr ""
"Si True, tous les nouveaux utilisations créés et connectés sont actifs. Si " "Si True, tous les nouveaux utilisations créés et connectés sont actifs. Si "
"False, seulement quand une inscription validée a été payée." "False, seulement quand une inscription validée a été payée."
#: preferences/models.py:140 #: preferences/models.py:118
msgid "" msgid ""
"If True, users have the choice to receive an email containing a link to " "If True, users have the choice to receive an email containing a link to "
"reset their password during creation, or to directly set their password in " "reset their password during creation, or to directly set their password in "
@ -337,172 +337,172 @@ msgstr ""
"de choisir leur mot de passe immédiatement. Si False, un mail est toujours " "de choisir leur mot de passe immédiatement. Si False, un mail est toujours "
"envoyé." "envoyé."
#: preferences/models.py:147 #: preferences/models.py:125
msgid "If True, archived users are allowed to connect." msgid "If True, archived users are allowed to connect."
msgstr "Si True, les utilisateurs archivés sont autorisés à se connecter." msgstr "Si True, les utilisateurs archivés sont autorisés à se connecter."
#: preferences/models.py:151 #: preferences/models.py:129
msgid "Can view the user preferences" msgid "Can view the user preferences"
msgstr "Peut voir les préférences d'utilisateur" msgstr "Peut voir les préférences d'utilisateur"
#: preferences/models.py:152 #: preferences/models.py:130
msgid "user preferences" msgid "user preferences"
msgstr "Préférences d'utilisateur" msgstr "Préférences d'utilisateur"
#: preferences/models.py:159 #: preferences/models.py:137
msgid "Email domain must begin with @." msgid "Email domain must begin with @."
msgstr "Un domaine mail doit commencer par @." msgstr "Un domaine mail doit commencer par @."
#: preferences/models.py:177 #: preferences/models.py:155
msgid "Automatic configuration by RA" msgid "Automatic configuration by RA"
msgstr "Configuration automatique par RA" msgstr "Configuration automatique par RA"
#: preferences/models.py:178 #: preferences/models.py:156
msgid "IP addresses assignment by DHCPv6" msgid "IP addresses assignment by DHCPv6"
msgstr "Attribution d'adresses IP par DHCPv6" msgstr "Attribution d'adresses IP par DHCPv6"
#: preferences/models.py:179 #: preferences/models.py:157
msgid "Disabled" msgid "Disabled"
msgstr "Désactivé" msgstr "Désactivé"
#: preferences/models.py:188 #: preferences/models.py:166
msgid "default Time To Live (TTL) for CNAME, A and AAAA records" msgid "default Time To Live (TTL) for CNAME, A and AAAA records"
msgstr "" msgstr ""
"Temps de vie (TTL) par défault pour des enregistrements CNAME, A et AAAA" "Temps de vie (TTL) par défault pour des enregistrements CNAME, A et AAAA"
#: preferences/models.py:198 #: preferences/models.py:176
msgid "Can view the machine preferences" msgid "Can view the machine preferences"
msgstr "Peut voir les préférences de machine" msgstr "Peut voir les préférences de machine"
#: preferences/models.py:199 #: preferences/models.py:177
msgid "machine preferences" msgid "machine preferences"
msgstr "Préférences de machine" msgstr "Préférences de machine"
#: preferences/models.py:219 preferences/models.py:677 #: preferences/models.py:197 preferences/models.py:655
msgid "On the IP range's VLAN of the machine" msgid "On the IP range's VLAN of the machine"
msgstr "Sur le VLAN de la plage d'IP de la machine" msgstr "Sur le VLAN de la plage d'IP de la machine"
#: preferences/models.py:220 preferences/models.py:678 #: preferences/models.py:198 preferences/models.py:656
msgid "Preset in \"VLAN for machines accepted by RADIUS\"" msgid "Preset in \"VLAN for machines accepted by RADIUS\""
msgstr "Prédéfinie dans « VLAN pour les machines acceptées par RADIUS »" msgstr "Prédéfinie dans « VLAN pour les machines acceptées par RADIUS »"
#: preferences/models.py:226 #: preferences/models.py:204
msgid "Web management, activated in case of automatic provision." msgid "Web management, activated in case of automatic provision."
msgstr "Gestion web, activée en cas de provision automatique." msgstr "Gestion web, activée en cas de provision automatique."
#: preferences/models.py:231 #: preferences/models.py:209
msgid "" msgid ""
"SSL web management, make sure that a certificate is installed on the switch." "SSL web management, make sure that a certificate is installed on the switch."
msgstr "" msgstr ""
"Gestion web SSL, vérifiez qu'un certificat est installé sur le commutateur " "Gestion web SSL, vérifiez qu'un certificat est installé sur le commutateur "
"réseau." "réseau."
#: preferences/models.py:237 #: preferences/models.py:215
msgid "REST management, activated in case of automatic provision." msgid "REST management, activated in case of automatic provision."
msgstr "Gestion REST, activée en cas de provision automatique." msgstr "Gestion REST, activée en cas de provision automatique."
#: preferences/models.py:244 #: preferences/models.py:222
msgid "IP range for the management of switches." msgid "IP range for the management of switches."
msgstr "Plage d'IP pour la gestion des commutateurs réseau." msgstr "Plage d'IP pour la gestion des commutateurs réseau."
#: preferences/models.py:250 #: preferences/models.py:228
msgid "Provision of configuration mode for switches." msgid "Provision of configuration mode for switches."
msgstr "Mode de provision de configuration pour les commutateurs réseau." msgstr "Mode de provision de configuration pour les commutateurs réseau."
#: preferences/models.py:253 #: preferences/models.py:231
msgid "SFTP login for switches." msgid "SFTP login for switches."
msgstr "Identifiant SFTP pour les commutateurs réseau." msgstr "Identifiant SFTP pour les commutateurs réseau."
#: preferences/models.py:256 #: preferences/models.py:234
msgid "SFTP password." msgid "SFTP password."
msgstr "Mot de passe SFTP." msgstr "Mot de passe SFTP."
#: preferences/models.py:360 #: preferences/models.py:338
msgid "Can view the topology preferences" msgid "Can view the topology preferences"
msgstr "Peut voir les préférences de topologie" msgstr "Peut voir les préférences de topologie"
#: preferences/models.py:361 #: preferences/models.py:339
msgid "topology preferences" msgid "topology preferences"
msgstr "préférences de topologie" msgstr "préférences de topologie"
#: preferences/models.py:374 #: preferences/models.py:352
msgid "RADIUS key." msgid "RADIUS key."
msgstr "Clé RADIUS." msgstr "Clé RADIUS."
#: preferences/models.py:376 #: preferences/models.py:354
msgid "Comment for this key." msgid "Comment for this key."
msgstr "Commentaire pour cette clé." msgstr "Commentaire pour cette clé."
#: preferences/models.py:379 #: preferences/models.py:357
msgid "Default key for switches." msgid "Default key for switches."
msgstr "Clé par défaut pour les commutateurs réseau." msgstr "Clé par défaut pour les commutateurs réseau."
#: preferences/models.py:383 #: preferences/models.py:361
msgid "Can view a RADIUS key object" msgid "Can view a RADIUS key object"
msgstr "Peut voir un objet clé RADIUS" msgstr "Peut voir un objet clé RADIUS"
#: preferences/models.py:384 preferences/views.py:331 #: preferences/models.py:362 preferences/views.py:307
msgid "RADIUS key" msgid "RADIUS key"
msgstr "Clé RADIUS" msgstr "Clé RADIUS"
#: preferences/models.py:385 #: preferences/models.py:363
#: preferences/templates/preferences/display_preferences.html:221 #: preferences/templates/preferences/display_preferences.html:221
msgid "RADIUS keys" msgid "RADIUS keys"
msgstr "clés RADIUS" msgstr "clés RADIUS"
#: preferences/models.py:392 #: preferences/models.py:370
msgid "Default RADIUS key for switches already exists." msgid "Default RADIUS key for switches already exists."
msgstr "Clé par défaut pour les commutateurs réseau." msgstr "Clé par défaut pour les commutateurs réseau."
#: preferences/models.py:395 #: preferences/models.py:373
msgid "RADIUS key " msgid "RADIUS key "
msgstr "clé RADIUS " msgstr "clé RADIUS "
#: preferences/models.py:401 #: preferences/models.py:379
msgid "Switch login." msgid "Switch login."
msgstr "Identifiant du commutateur réseau." msgstr "Identifiant du commutateur réseau."
#: preferences/models.py:402 #: preferences/models.py:380
msgid "Password." msgid "Password."
msgstr "Mot de passe." msgstr "Mot de passe."
#: preferences/models.py:404 #: preferences/models.py:382
msgid "Default credentials for switches." msgid "Default credentials for switches."
msgstr "Identifiants par défaut pour les commutateurs réseau." msgstr "Identifiants par défaut pour les commutateurs réseau."
#: preferences/models.py:411 #: preferences/models.py:389
msgid "Can view a switch management credentials object" msgid "Can view a switch management credentials object"
msgstr "Peut voir un objet identifiants de gestion de commutateur réseau" msgstr "Peut voir un objet identifiants de gestion de commutateur réseau"
#: preferences/models.py:414 preferences/views.py:394 #: preferences/models.py:392 preferences/views.py:370
msgid "switch management credentials" msgid "switch management credentials"
msgstr "identifiants de gestion de commutateur réseau" msgstr "identifiants de gestion de commutateur réseau"
#: preferences/models.py:417 #: preferences/models.py:395
msgid "Switch login " msgid "Switch login "
msgstr "Identifiant du commutateur réseau " msgstr "Identifiant du commutateur réseau "
#: preferences/models.py:429 #: preferences/models.py:407
msgid "Delay between the email and the membership's end." msgid "Delay between the email and the membership's end."
msgstr "Délai entre le mail et la fin d'adhésion." msgstr "Délai entre le mail et la fin d'adhésion."
#: preferences/models.py:435 #: preferences/models.py:413
msgid "Message displayed specifically for this reminder." msgid "Message displayed specifically for this reminder."
msgstr "Message affiché spécifiquement pour ce rappel." msgstr "Message affiché spécifiquement pour ce rappel."
#: preferences/models.py:439 #: preferences/models.py:417
msgid "Can view a reminder object" msgid "Can view a reminder object"
msgstr "Peut voir un objet rappel" msgstr "Peut voir un objet rappel"
#: preferences/models.py:440 preferences/views.py:276 #: preferences/models.py:418 preferences/views.py:252
msgid "reminder" msgid "reminder"
msgstr "rappel" msgstr "rappel"
#: preferences/models.py:441 #: preferences/models.py:419
msgid "reminders" msgid "reminders"
msgstr "rappels" msgstr "rappels"
#: preferences/models.py:462 #: preferences/models.py:440
msgid "" msgid ""
"General message displayed on the French version of the website (e.g. in case " "General message displayed on the French version of the website (e.g. in case "
"of maintenance)." "of maintenance)."
@ -510,7 +510,7 @@ msgstr ""
"Message général affiché sur la version française du site (ex : en cas de " "Message général affiché sur la version française du site (ex : en cas de "
"maintenance)." "maintenance)."
#: preferences/models.py:470 #: preferences/models.py:448
msgid "" msgid ""
"General message displayed on the English version of the website (e.g. in " "General message displayed on the English version of the website (e.g. in "
"case of maintenance)." "case of maintenance)."
@ -518,75 +518,75 @@ msgstr ""
"Message général affiché sur la version anglaise du site (ex : en cas de " "Message général affiché sur la version anglaise du site (ex : en cas de "
"maintenance)." "maintenance)."
#: preferences/models.py:485 #: preferences/models.py:463
msgid "Can view the general preferences" msgid "Can view the general preferences"
msgstr "Peut voir les préférences générales" msgstr "Peut voir les préférences générales"
#: preferences/models.py:486 #: preferences/models.py:464
msgid "general preferences" msgid "general preferences"
msgstr "préférences générales" msgstr "préférences générales"
#: preferences/models.py:506 #: preferences/models.py:484
msgid "Can view the service preferences" msgid "Can view the service preferences"
msgstr "Peut voir les préférences de service" msgstr "Peut voir les préférences de service"
#: preferences/models.py:507 preferences/views.py:227 #: preferences/models.py:485 preferences/views.py:203
msgid "service" msgid "service"
msgstr "service" msgstr "service"
#: preferences/models.py:508 #: preferences/models.py:486
msgid "services" msgid "services"
msgstr "services" msgstr "services"
#: preferences/models.py:518 #: preferences/models.py:496
msgid "Contact email address." msgid "Contact email address."
msgstr "Adresse mail de contact." msgstr "Adresse mail de contact."
#: preferences/models.py:524 #: preferences/models.py:502
msgid "Description of the associated email address." msgid "Description of the associated email address."
msgstr "Description de l'adresse mail associée." msgstr "Description de l'adresse mail associée."
#: preferences/models.py:534 #: preferences/models.py:512
msgid "Can view a contact email address object" msgid "Can view a contact email address object"
msgstr "Peut voir un objet adresse mail de contact" msgstr "Peut voir un objet adresse mail de contact"
#: preferences/models.py:536 #: preferences/models.py:514
msgid "contact email address" msgid "contact email address"
msgstr "adresse mail de contact" msgstr "adresse mail de contact"
#: preferences/models.py:537 #: preferences/models.py:515
msgid "contact email addresses" msgid "contact email addresses"
msgstr "adresses mail de contact" msgstr "adresses mail de contact"
#: preferences/models.py:545 preferences/views.py:634 #: preferences/models.py:523 preferences/views.py:610
msgid "mandate" msgid "mandate"
msgstr "mandat" msgstr "mandat"
#: preferences/models.py:546 #: preferences/models.py:524
msgid "mandates" msgid "mandates"
msgstr "mandats" msgstr "mandats"
#: preferences/models.py:547 #: preferences/models.py:525
msgid "Can view a mandate object" msgid "Can view a mandate object"
msgstr "Peut voir un objet mandat" msgstr "Peut voir un objet mandat"
#: preferences/models.py:554 #: preferences/models.py:532
msgid "president of the association" msgid "president of the association"
msgstr "président de l'association" msgstr "président de l'association"
#: preferences/models.py:555 #: preferences/models.py:533
msgid "Displayed on subscription vouchers." msgid "Displayed on subscription vouchers."
msgstr "Affiché sur les reçus de cotisation." msgstr "Affiché sur les reçus de cotisation."
#: preferences/models.py:557 #: preferences/models.py:535
msgid "start date" msgid "start date"
msgstr "date de début" msgstr "date de début"
#: preferences/models.py:558 #: preferences/models.py:536
msgid "end date" msgid "end date"
msgstr "date de fin" msgstr "date de fin"
#: preferences/models.py:571 #: preferences/models.py:549
msgid "" msgid ""
"No mandates have been created. Please go to the preferences page to create " "No mandates have been created. Please go to the preferences page to create "
"one." "one."
@ -594,140 +594,140 @@ msgstr ""
"Aucun mandat n'a été créé. Veuillez vous rendre sur la page de préférences " "Aucun mandat n'a été créé. Veuillez vous rendre sur la page de préférences "
"pour en créer un." "pour en créer un."
#: preferences/models.py:586 #: preferences/models.py:564
msgid "Networking organisation school Something" msgid "Networking organisation school Something"
msgstr "Association de réseau de l'école Machin" msgstr "Association de réseau de l'école Machin"
#: preferences/models.py:589 #: preferences/models.py:567
msgid "Threadneedle Street" msgid "Threadneedle Street"
msgstr "1 rue de la Vrillière" msgstr "1 rue de la Vrillière"
#: preferences/models.py:590 #: preferences/models.py:568
msgid "London EC2R 8AH" msgid "London EC2R 8AH"
msgstr "75001 Paris" msgstr "75001 Paris"
#: preferences/models.py:593 #: preferences/models.py:571
msgid "Organisation" msgid "Organisation"
msgstr "Association" msgstr "Association"
#: preferences/models.py:600 #: preferences/models.py:578
msgid "Can view the organisation preferences" msgid "Can view the organisation preferences"
msgstr "Peut voir les préférences d'association" msgstr "Peut voir les préférences d'association"
#: preferences/models.py:601 #: preferences/models.py:579
msgid "organisation preferences" msgid "organisation preferences"
msgstr "préférences d'association" msgstr "préférences d'association"
#: preferences/models.py:619 #: preferences/models.py:597
msgid "Can view the homepage preferences" msgid "Can view the homepage preferences"
msgstr "Peut voir les préférences de page d'accueil" msgstr "Peut voir les préférences de page d'accueil"
#: preferences/models.py:620 #: preferences/models.py:598
msgid "homepage preferences" msgid "homepage preferences"
msgstr "Préférences de page d'accueil" msgstr "Préférences de page d'accueil"
#: preferences/models.py:634 #: preferences/models.py:612
msgid "Welcome email in French." msgid "Welcome email in French."
msgstr "Mail de bienvenue en français." msgstr "Mail de bienvenue en français."
#: preferences/models.py:637 #: preferences/models.py:615
msgid "Welcome email in English." msgid "Welcome email in English."
msgstr "Mail de bienvenue en anglais." msgstr "Mail de bienvenue en anglais."
#: preferences/models.py:642 #: preferences/models.py:620
msgid "Can view the email message preferences" msgid "Can view the email message preferences"
msgstr "Peut voir les préférences de message pour les mails" msgstr "Peut voir les préférences de message pour les mails"
#: preferences/models.py:644 #: preferences/models.py:622
msgid "email message preferences" msgid "email message preferences"
msgstr "préférences de messages pour les mails" msgstr "préférences de messages pour les mails"
#: preferences/models.py:649 #: preferences/models.py:627
msgid "RADIUS attribute" msgid "RADIUS attribute"
msgstr "attribut RADIUS" msgstr "attribut RADIUS"
#: preferences/models.py:650 #: preferences/models.py:628
msgid "RADIUS attributes" msgid "RADIUS attributes"
msgstr "attributs RADIUS" msgstr "attributs RADIUS"
#: preferences/models.py:654 preferences/views.py:587 #: preferences/models.py:632 preferences/views.py:563
msgid "attribute" msgid "attribute"
msgstr "attribut" msgstr "attribut"
#: preferences/models.py:655 #: preferences/models.py:633
msgid "See https://freeradius.org/rfc/attributes.html." msgid "See https://freeradius.org/rfc/attributes.html."
msgstr "Voir https://freeradius.org/rfc/attributes.html." msgstr "Voir https://freeradius.org/rfc/attributes.html."
#: preferences/models.py:657 #: preferences/models.py:635
msgid "value" msgid "value"
msgstr "valeur" msgstr "valeur"
#: preferences/models.py:659 #: preferences/models.py:637
msgid "comment" msgid "comment"
msgstr "commentaire" msgstr "commentaire"
#: preferences/models.py:660 #: preferences/models.py:638
msgid "Use this field to document this attribute." msgid "Use this field to document this attribute."
msgstr "Utilisez ce champ pour documenter cet attribut." msgstr "Utilisez ce champ pour documenter cet attribut."
#: preferences/models.py:671 #: preferences/models.py:649
msgid "RADIUS policy" msgid "RADIUS policy"
msgstr "politique de RADIUS" msgstr "politique de RADIUS"
#: preferences/models.py:672 #: preferences/models.py:650
#: preferences/templates/preferences/display_preferences.html:299 #: preferences/templates/preferences/display_preferences.html:299
msgid "RADIUS policies" msgid "RADIUS policies"
msgstr "politiques de RADIUS" msgstr "politiques de RADIUS"
#: preferences/models.py:683 #: preferences/models.py:661
msgid "Reject the machine" msgid "Reject the machine"
msgstr "Rejeter la machine" msgstr "Rejeter la machine"
#: preferences/models.py:684 #: preferences/models.py:662
msgid "Place the machine on the VLAN" msgid "Place the machine on the VLAN"
msgstr "Placer la machine sur le VLAN" msgstr "Placer la machine sur le VLAN"
#: preferences/models.py:693 #: preferences/models.py:671
msgid "policy for unknown machines" msgid "policy for unknown machines"
msgstr "politique pour les machines inconnues" msgstr "politique pour les machines inconnues"
#: preferences/models.py:701 #: preferences/models.py:679
msgid "unknown machines VLAN" msgid "unknown machines VLAN"
msgstr "VLAN pour les machines inconnues" msgstr "VLAN pour les machines inconnues"
#: preferences/models.py:702 #: preferences/models.py:680
msgid "VLAN for unknown machines if not rejected." msgid "VLAN for unknown machines if not rejected."
msgstr "VLAN pour les machines inconnues si non rejeté." msgstr "VLAN pour les machines inconnues si non rejeté."
#: preferences/models.py:708 #: preferences/models.py:686
msgid "unknown machines attributes" msgid "unknown machines attributes"
msgstr "attributs pour les machines inconnues" msgstr "attributs pour les machines inconnues"
#: preferences/models.py:709 #: preferences/models.py:687
msgid "Answer attributes for unknown machines." msgid "Answer attributes for unknown machines."
msgstr "Attributs de réponse pour les machines inconnues." msgstr "Attributs de réponse pour les machines inconnues."
#: preferences/models.py:715 #: preferences/models.py:693
msgid "policy for unknown ports" msgid "policy for unknown ports"
msgstr "politique pour les ports inconnus" msgstr "politique pour les ports inconnus"
#: preferences/models.py:723 #: preferences/models.py:701
msgid "unknown ports VLAN" msgid "unknown ports VLAN"
msgstr "VLAN pour les ports inconnus" msgstr "VLAN pour les ports inconnus"
#: preferences/models.py:724 #: preferences/models.py:702
msgid "VLAN for unknown ports if not rejected." msgid "VLAN for unknown ports if not rejected."
msgstr "VLAN pour les ports inconnus si non rejeté." msgstr "VLAN pour les ports inconnus si non rejeté."
#: preferences/models.py:730 #: preferences/models.py:708
msgid "unknown ports attributes" msgid "unknown ports attributes"
msgstr "attributs pour les ports inconnus" msgstr "attributs pour les ports inconnus"
#: preferences/models.py:731 #: preferences/models.py:709
msgid "Answer attributes for unknown ports." msgid "Answer attributes for unknown ports."
msgstr "Attributs de réponse pour les ports inconnus." msgstr "Attributs de réponse pour les ports inconnus."
#: preferences/models.py:738 #: preferences/models.py:716
msgid "" msgid ""
"Policy for machines connecting from unregistered rooms (relevant on ports " "Policy for machines connecting from unregistered rooms (relevant on ports "
"with STRICT RADIUS mode)" "with STRICT RADIUS mode)"
@ -735,87 +735,87 @@ msgstr ""
"Politique pour les machines se connectant depuis des chambre non " "Politique pour les machines se connectant depuis des chambre non "
"enregistrées (pertinent pour les ports avec le mode de RADIUS STRICT)" "enregistrées (pertinent pour les ports avec le mode de RADIUS STRICT)"
#: preferences/models.py:748 #: preferences/models.py:726
msgid "unknown rooms VLAN" msgid "unknown rooms VLAN"
msgstr "VLAN pour les chambres inconnues" msgstr "VLAN pour les chambres inconnues"
#: preferences/models.py:749 #: preferences/models.py:727
msgid "VLAN for unknown rooms if not rejected." msgid "VLAN for unknown rooms if not rejected."
msgstr "VLAN pour les chambres inconnues si non rejeté." msgstr "VLAN pour les chambres inconnues si non rejeté."
#: preferences/models.py:755 #: preferences/models.py:733
msgid "unknown rooms attributes" msgid "unknown rooms attributes"
msgstr "attributs pour les chambres inconnues" msgstr "attributs pour les chambres inconnues"
#: preferences/models.py:756 #: preferences/models.py:734
msgid "Answer attributes for unknown rooms." msgid "Answer attributes for unknown rooms."
msgstr "Attributs de réponse pour les chambres inconnues." msgstr "Attributs de réponse pour les chambres inconnues."
#: preferences/models.py:762 #: preferences/models.py:740
msgid "policy for non members" msgid "policy for non members"
msgstr "politique pour les non adhérents" msgstr "politique pour les non adhérents"
#: preferences/models.py:770 #: preferences/models.py:748
msgid "non members VLAN" msgid "non members VLAN"
msgstr "VLAN pour les non adhérents" msgstr "VLAN pour les non adhérents"
#: preferences/models.py:771 #: preferences/models.py:749
msgid "VLAN for non members if not rejected." msgid "VLAN for non members if not rejected."
msgstr "VLAN pour les non adhérents si non rejeté." msgstr "VLAN pour les non adhérents si non rejeté."
#: preferences/models.py:777 #: preferences/models.py:755
msgid "non members attributes" msgid "non members attributes"
msgstr "attributs pour les non adhérents" msgstr "attributs pour les non adhérents"
#: preferences/models.py:778 #: preferences/models.py:756
msgid "Answer attributes for non members." msgid "Answer attributes for non members."
msgstr "Attributs de réponse pour les non adhérents." msgstr "Attributs de réponse pour les non adhérents."
#: preferences/models.py:784 #: preferences/models.py:762
msgid "policy for banned users" msgid "policy for banned users"
msgstr "politique pour les utilisateurs bannis" msgstr "politique pour les utilisateurs bannis"
#: preferences/models.py:792 #: preferences/models.py:770
msgid "banned users VLAN" msgid "banned users VLAN"
msgstr "VLAN pour les utilisateurs bannis" msgstr "VLAN pour les utilisateurs bannis"
#: preferences/models.py:793 #: preferences/models.py:771
msgid "VLAN for banned users if not rejected." msgid "VLAN for banned users if not rejected."
msgstr "VLAN pour les utilisateurs bannis si non rejeté." msgstr "VLAN pour les utilisateurs bannis si non rejeté."
#: preferences/models.py:799 #: preferences/models.py:777
msgid "banned users attributes" msgid "banned users attributes"
msgstr "attributs pour les utilisateurs bannis" msgstr "attributs pour les utilisateurs bannis"
#: preferences/models.py:800 #: preferences/models.py:778
msgid "Answer attributes for banned users." msgid "Answer attributes for banned users."
msgstr "Attributs de réponse pour les utilisateurs bannis." msgstr "Attributs de réponse pour les utilisateurs bannis."
#: preferences/models.py:813 #: preferences/models.py:791
msgid "accepted users attributes" msgid "accepted users attributes"
msgstr "attributs pour les utilisateurs acceptés" msgstr "attributs pour les utilisateurs acceptés"
#: preferences/models.py:814 #: preferences/models.py:792
msgid "Answer attributes for accepted users." msgid "Answer attributes for accepted users."
msgstr "Attributs de réponse pour les utilisateurs acceptés." msgstr "Attributs de réponse pour les utilisateurs acceptés."
#: preferences/models.py:841 #: preferences/models.py:819
msgid "subscription preferences" msgid "subscription preferences"
msgstr "préférences de cotisation" msgstr "préférences de cotisation"
#: preferences/models.py:845 #: preferences/models.py:823
msgid "template for invoices" msgid "template for invoices"
msgstr "modèle pour les factures" msgstr "modèle pour les factures"
#: preferences/models.py:852 #: preferences/models.py:830
msgid "template for subscription vouchers" msgid "template for subscription vouchers"
msgstr "modèle pour les reçus de cotisation" msgstr "modèle pour les reçus de cotisation"
#: preferences/models.py:858 #: preferences/models.py:836
msgid "send voucher by email when the invoice is controlled" msgid "send voucher by email when the invoice is controlled"
msgstr "envoyer le reçu par mail quand la facture est contrôlée" msgstr "envoyer le reçu par mail quand la facture est contrôlée"
#: preferences/models.py:860 #: preferences/models.py:838
msgid "" msgid ""
"Be careful, if no mandate is defined on the preferences page, errors will be " "Be careful, if no mandate is defined on the preferences page, errors will be "
"triggered when generating vouchers." "triggered when generating vouchers."
@ -823,19 +823,19 @@ msgstr ""
"Faites attention, si aucun mandat n'est défini sur la page de préférences, " "Faites attention, si aucun mandat n'est défini sur la page de préférences, "
"des erreurs seront déclenchées en générant des reçus." "des erreurs seront déclenchées en générant des reçus."
#: preferences/models.py:872 #: preferences/models.py:850
msgid "template" msgid "template"
msgstr "modèle" msgstr "modèle"
#: preferences/models.py:873 #: preferences/models.py:851
msgid "name" msgid "name"
msgstr "nom" msgstr "nom"
#: preferences/models.py:876 #: preferences/models.py:854
msgid "document template" msgid "document template"
msgstr "modèle de document" msgstr "modèle de document"
#: preferences/models.py:877 #: preferences/models.py:855
msgid "document templates" msgid "document templates"
msgstr "modèles de document" msgstr "modèles de document"
@ -1035,9 +1035,9 @@ msgstr "Préférences générales"
#: preferences/templates/preferences/display_preferences.html:417 #: preferences/templates/preferences/display_preferences.html:417
#: preferences/templates/preferences/display_preferences.html:495 #: preferences/templates/preferences/display_preferences.html:495
#: preferences/templates/preferences/edit_preferences.html:46 #: preferences/templates/preferences/edit_preferences.html:46
#: preferences/views.py:212 preferences/views.py:261 preferences/views.py:307 #: preferences/views.py:188 preferences/views.py:237 preferences/views.py:283
#: preferences/views.py:367 preferences/views.py:431 preferences/views.py:496 #: preferences/views.py:343 preferences/views.py:407 preferences/views.py:472
#: preferences/views.py:572 preferences/views.py:619 #: preferences/views.py:548 preferences/views.py:595
msgid "Edit" msgid "Edit"
msgstr "Modifier" msgstr "Modifier"
@ -1359,75 +1359,75 @@ msgstr "URL du compte Facebook"
msgid "Editing of preferences" msgid "Editing of preferences"
msgstr "Modification des préférences" msgstr "Modification des préférences"
#: preferences/views.py:160 #: preferences/utils/views.py:45
msgid "Unknown object." msgid "Unknown object."
msgstr "Objet inconnu." msgstr "Objet inconnu."
#: preferences/views.py:179 #: preferences/utils/views.py:64
msgid "The preferences were edited." msgid "The preferences were edited."
msgstr "Les préférences ont été modifiées." msgstr "Les préférences ont été modifiées."
#: preferences/views.py:191 #: preferences/views.py:167
msgid "The service was added." msgid "The service was added."
msgstr "Le service a été ajouté." msgstr "Le service a été ajouté."
#: preferences/views.py:194 preferences/views.py:243 preferences/views.py:292 #: preferences/views.py:170 preferences/views.py:219 preferences/views.py:268
#: preferences/views.py:349 preferences/views.py:412 preferences/views.py:471 #: preferences/views.py:325 preferences/views.py:388 preferences/views.py:447
#: preferences/views.py:554 preferences/views.py:603 #: preferences/views.py:530 preferences/views.py:579
msgid "Add" msgid "Add"
msgstr "Ajouter" msgstr "Ajouter"
#: preferences/views.py:209 #: preferences/views.py:185
msgid "The service was edited." msgid "The service was edited."
msgstr "Le service a été modifié." msgstr "Le service a été modifié."
#: preferences/views.py:224 #: preferences/views.py:200
msgid "The service was deleted." msgid "The service was deleted."
msgstr "Le service a été supprimé." msgstr "Le service a été supprimé."
#: preferences/views.py:240 #: preferences/views.py:216
msgid "The reminder was added." msgid "The reminder was added."
msgstr "Le rappel a été ajouté." msgstr "Le rappel a été ajouté."
#: preferences/views.py:258 #: preferences/views.py:234
msgid "The reminder was edited." msgid "The reminder was edited."
msgstr "Le rappel a été modifié." msgstr "Le rappel a été modifié."
#: preferences/views.py:273 #: preferences/views.py:249
msgid "The reminder was deleted." msgid "The reminder was deleted."
msgstr "Le rappel a été supprimé." msgstr "Le rappel a été supprimé."
#: preferences/views.py:289 #: preferences/views.py:265
msgid "The RADIUS key was added." msgid "The RADIUS key was added."
msgstr "La clé RADIUS a été ajoutée." msgstr "La clé RADIUS a été ajoutée."
#: preferences/views.py:304 #: preferences/views.py:280
msgid "The RADIUS key was edited." msgid "The RADIUS key was edited."
msgstr "La clé RADIUS a été modifiée." msgstr "La clé RADIUS a été modifiée."
#: preferences/views.py:320 #: preferences/views.py:296
msgid "The RADIUS key was deleted." msgid "The RADIUS key was deleted."
msgstr "La clé RADIUS a été supprimée." msgstr "La clé RADIUS a été supprimée."
#: preferences/views.py:325 #: preferences/views.py:301
msgid "The RADIUS key is assigned to at least one switch, you can't delete it." msgid "The RADIUS key is assigned to at least one switch, you can't delete it."
msgstr "" msgstr ""
"La clé RADIUS est assignée a au moins un commutateur réseau, vous ne pouvez " "La clé RADIUS est assignée a au moins un commutateur réseau, vous ne pouvez "
"pas la supprimer." "pas la supprimer."
#: preferences/views.py:344 #: preferences/views.py:320
msgid "The switch management credentials were added." msgid "The switch management credentials were added."
msgstr "Les identifiants de gestion de commutateur réseay ont été ajoutés." msgstr "Les identifiants de gestion de commutateur réseay ont été ajoutés."
#: preferences/views.py:364 #: preferences/views.py:340
msgid "The switch management credentials were edited." msgid "The switch management credentials were edited."
msgstr "Les identifiants de gestion de commutateur réseau ont été modifiés." msgstr "Les identifiants de gestion de commutateur réseau ont été modifiés."
#: preferences/views.py:381 #: preferences/views.py:357
msgid "The switch management credentials were deleted." msgid "The switch management credentials were deleted."
msgstr "Les identifiants de gestion de commutateur réseau ont été supprimés." msgstr "Les identifiants de gestion de commutateur réseau ont été supprimés."
#: preferences/views.py:387 #: preferences/views.py:363
msgid "" msgid ""
"The switch management credentials are assigned to at least one switch, you " "The switch management credentials are assigned to at least one switch, you "
"can't delete them." "can't delete them."
@ -1435,44 +1435,44 @@ msgstr ""
"Les identifiants de gestion de commutateur réseau sont assignés à au moins " "Les identifiants de gestion de commutateur réseau sont assignés à au moins "
"un commutateur réseau , vous ne pouvez pas les supprimer." "un commutateur réseau , vous ne pouvez pas les supprimer."
#: preferences/views.py:407 #: preferences/views.py:383
msgid "The contact email address was created." msgid "The contact email address was created."
msgstr "L'adresse mail de contact a été supprimée." msgstr "L'adresse mail de contact a été supprimée."
#: preferences/views.py:428 #: preferences/views.py:404
msgid "The contact email address was edited." msgid "The contact email address was edited."
msgstr "L'adresse mail de contact a été modifiée." msgstr "L'adresse mail de contact a été modifiée."
#: preferences/views.py:446 #: preferences/views.py:422
msgid "The contact email adress was deleted." msgid "The contact email adress was deleted."
msgstr "L'adresse mail de contact a été supprimée." msgstr "L'adresse mail de contact a été supprimée."
#: preferences/views.py:449 preferences/views.py:536 #: preferences/views.py:425 preferences/views.py:512
msgid "Delete" msgid "Delete"
msgstr "Supprimer" msgstr "Supprimer"
#: preferences/views.py:466 #: preferences/views.py:442
msgid "The document template was created." msgid "The document template was created."
msgstr "Le modèle de document a été créé." msgstr "Le modèle de document a été créé."
#: preferences/views.py:472 #: preferences/views.py:448
msgid "New document template" msgid "New document template"
msgstr "Nouveau modèle de document" msgstr "Nouveau modèle de document"
#: preferences/views.py:491 #: preferences/views.py:467
msgid "The document template was edited." msgid "The document template was edited."
msgstr "Le modèle de document a été édité." msgstr "Le modèle de document a été édité."
#: preferences/views.py:497 #: preferences/views.py:473
msgid "Edit document template" msgid "Edit document template"
msgstr "Modifier le modèle de document" msgstr "Modifier le modèle de document"
#: preferences/views.py:520 #: preferences/views.py:496
#, python-format #, python-format
msgid "The document template %(document_template)s was deleted." msgid "The document template %(document_template)s was deleted."
msgstr "Le modèle de document %(document_template)s a été supprimé." msgstr "Le modèle de document %(document_template)s a été supprimé."
#: preferences/views.py:527 #: preferences/views.py:503
#, python-format #, python-format
msgid "" msgid ""
"The document template %(document_template)s can't be deleted because it is " "The document template %(document_template)s can't be deleted because it is "
@ -1481,31 +1481,31 @@ msgstr ""
"Le modèle de document %(document_template)s ne peut pas être supprimé car il " "Le modèle de document %(document_template)s ne peut pas être supprimé car il "
"est actuellement utilisé." "est actuellement utilisé."
#: preferences/views.py:537 #: preferences/views.py:513
msgid "Delete document template" msgid "Delete document template"
msgstr "Supprimer le modèle de document" msgstr "Supprimer le modèle de document"
#: preferences/views.py:551 #: preferences/views.py:527
msgid "The attribute was added." msgid "The attribute was added."
msgstr "L'attribut a été ajouté." msgstr "L'attribut a été ajouté."
#: preferences/views.py:569 #: preferences/views.py:545
msgid "The attribute was edited." msgid "The attribute was edited."
msgstr "L'attribut a été modifié." msgstr "L'attribut a été modifié."
#: preferences/views.py:584 #: preferences/views.py:560
msgid "The attribute was deleted." msgid "The attribute was deleted."
msgstr "L'attribut a été supprimé." msgstr "L'attribut a été supprimé."
#: preferences/views.py:600 #: preferences/views.py:576
msgid "The mandate was added." msgid "The mandate was added."
msgstr "Le mandat a été ajouté." msgstr "Le mandat a été ajouté."
#: preferences/views.py:616 #: preferences/views.py:592
msgid "The mandate was edited." msgid "The mandate was edited."
msgstr "Le mandat a été modifié." msgstr "Le mandat a été modifié."
#: preferences/views.py:631 #: preferences/views.py:607
msgid "The mandate was deleted." msgid "The mandate was deleted."
msgstr "Le mandat été supprimé." msgstr "Le mandat été supprimé."

View file

@ -76,7 +76,12 @@ class OptionalUser(AclMixin, PreferencesModel):
ALL_ROOM = "ALL_ROOM" ALL_ROOM = "ALL_ROOM"
ROOM_POLICY = ( ROOM_POLICY = (
(DISABLED, _("Users can't select their room")), (DISABLED, _("Users can't select their room")),
(ONLY_INACTIVE, _("Users can only select a room occupied by a user with a disabled connection.")), (
ONLY_INACTIVE,
_(
"Users can only select a room occupied by a user with a disabled connection."
),
),
(ALL_ROOM, _("Users can select all rooms")), (ALL_ROOM, _("Users can select all rooms")),
) )
@ -98,7 +103,7 @@ class OptionalUser(AclMixin, PreferencesModel):
max_length=32, max_length=32,
choices=ROOM_POLICY, choices=ROOM_POLICY,
default="DISABLED", default="DISABLED",
help_text=_("Policy on self users room edition") help_text=_("Policy on self users room edition"),
) )
local_email_accounts_enabled = models.BooleanField( local_email_accounts_enabled = models.BooleanField(
default=False, help_text=_("Enable local email accounts for users.") default=False, help_text=_("Enable local email accounts for users.")
@ -114,9 +119,7 @@ class OptionalUser(AclMixin, PreferencesModel):
) )
delete_notyetactive = models.IntegerField( delete_notyetactive = models.IntegerField(
default=15, default=15,
help_text=_( help_text=_("Not yet active users will be deleted after this number of days."),
"Not yet active users will be deleted after this number of days."
),
) )
disable_emailnotyetconfirmed = models.IntegerField( disable_emailnotyetconfirmed = models.IntegerField(
default=2, default=2,
@ -217,7 +220,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
DEFINED = "DEFINED" DEFINED = "DEFINED"
CHOICE_RADIUS = ( CHOICE_RADIUS = (
(MACHINE, _("On the IP range's VLAN of the machine")), (MACHINE, _("On the IP range's VLAN of the machine")),
(DEFINED, _("Preset in \"VLAN for machines accepted by RADIUS\"")), (DEFINED, _('Preset in "VLAN for machines accepted by RADIUS"')),
) )
CHOICE_PROVISION = (("sftp", "SFTP"), ("tftp", "TFTP")) CHOICE_PROVISION = (("sftp", "SFTP"), ("tftp", "TFTP"))
@ -357,7 +360,9 @@ class OptionalTopologie(AclMixin, PreferencesModel):
) )
class Meta: class Meta:
permissions = (("view_optionaltopologie", _("Can view the topology preferences")),) permissions = (
("view_optionaltopologie", _("Can view the topology preferences")),
)
verbose_name = _("topology preferences") verbose_name = _("topology preferences")
@ -568,7 +573,9 @@ class Mandate(RevMixin, AclMixin, models.Model):
) )
if not mandate: if not mandate:
raise cls.DoesNotExist( raise cls.DoesNotExist(
_("No mandates have been created. Please go to the preferences page to create one.") _(
"No mandates have been created. Please go to the preferences page to create one."
)
) )
return mandate return mandate
@ -675,7 +682,7 @@ class RadiusOption(AclMixin, PreferencesModel):
DEFINED = "DEFINED" DEFINED = "DEFINED"
CHOICE_RADIUS = ( CHOICE_RADIUS = (
(MACHINE, _("On the IP range's VLAN of the machine")), (MACHINE, _("On the IP range's VLAN of the machine")),
(DEFINED, _("Preset in \"VLAN for machines accepted by RADIUS\"")), (DEFINED, _('Preset in "VLAN for machines accepted by RADIUS"')),
) )
REJECT = "REJECT" REJECT = "REJECT"
SET_VLAN = "SET_VLAN" SET_VLAN = "SET_VLAN"

View file

@ -28,52 +28,53 @@ from __future__ import unicode_literals
from django.conf.urls import url from django.conf.urls import url
from . import views from . import views
from .views import edit_options
urlpatterns = [ urlpatterns = [
url( url(
r"^edit_options/(?P<section>OptionalUser)$", r"^edit_options/(?P<section>OptionalUser)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>OptionalMachine)$", r"^edit_options/(?P<section>OptionalMachine)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>OptionalTopologie)$", r"^edit_options/(?P<section>OptionalTopologie)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>GeneralOption)$", r"^edit_options/(?P<section>GeneralOption)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>AssoOption)$", r"^edit_options/(?P<section>AssoOption)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>HomeOption)$", r"^edit_options/(?P<section>HomeOption)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>MailMessageOption)$", r"^edit_options/(?P<section>MailMessageOption)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>RadiusOption)$", r"^edit_options/(?P<section>RadiusOption)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url( url(
r"^edit_options/(?P<section>CotisationsOption)$", r"^edit_options/(?P<section>CotisationsOption)$",
views.edit_options, edit_options,
name="edit-options", name="edit-options",
), ),
url(r"^add_service/$", views.add_service, name="add-service"), url(r"^add_service/$", views.add_service, name="add-service"),

View file

@ -87,6 +87,35 @@ from . import models
from . import forms from . import forms
def edit_options_template_function(request, section, forms, models):
""" Edition des préférences générales"""
model = getattr(models, section, None)
form_instance = getattr(forms, "Edit" + section + "Form", None)
if not (model or form_instance):
messages.error(request, _("Unknown object."))
return redirect(reverse("preferences:display-options"))
options_instance, _created = model.objects.get_or_create()
_is_allowed_to_edit, msg, permissions = options_instance.can_edit(request.user)
if not _is_allowed_to_edit:
messages.error(request, acl_error_message(msg, permissions))
return redirect(reverse("index"))
options = form_instance(
request.POST or None, request.FILES or None, instance=options_instance
)
if options.is_valid():
with transaction.atomic(), reversion.create_revision():
options.save()
reversion.set_user(request.user)
reversion.set_comment(
"Field(s) edited: %s"
% ", ".join(field for field in options.changed_data)
)
messages.success(request, _("The preferences were edited."))
return redirect(reverse("preferences:display-options"))
return form({"options": options}, "preferences/edit_preferences.html", request)
@login_required @login_required
@can_view_all( @can_view_all(
OptionalUser, OptionalUser,
@ -120,9 +149,9 @@ def display_options(request):
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O] optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
optionnal_templates_list = [ optionnal_templates_list = [
app.views.preferences(request) app.preferences.views.aff_preferences(request)
for app in optionnal_apps for app in optionnal_apps
if hasattr(app.views, "preferences") if hasattr(app.preferences.views, "aff_preferences")
] ]
return form( return form(
@ -153,32 +182,7 @@ def display_options(request):
@login_required @login_required
def edit_options(request, section): def edit_options(request, section):
""" Edition des préférences générales""" return edit_options_template_function(request, section, forms, models)
model = getattr(models, section, None)
form_instance = getattr(forms, "Edit" + section + "Form", None)
if not (model or form_instance):
messages.error(request, _("Unknown object."))
return redirect(reverse("preferences:display-options"))
options_instance, _created = model.objects.get_or_create()
can, msg, permissions = options_instance.can_edit(request.user)
if not can:
messages.error(request, acl_error_message(msg, permissions))
return redirect(reverse("index"))
options = form_instance(
request.POST or None, request.FILES or None, instance=options_instance
)
if options.is_valid():
with transaction.atomic(), reversion.create_revision():
options.save()
reversion.set_user(request.user)
reversion.set_comment(
"Field(s) edited: %s"
% ", ".join(field for field in options.changed_data)
)
messages.success(request, _("The preferences were edited."))
return redirect(reverse("preferences:display-options"))
return form({"options": options}, "preferences/edit_preferences.html", request)
@login_required @login_required
@ -344,10 +348,7 @@ def add_switchmanagementcred(request):
messages.success(request, _("The switch management credentials were added.")) messages.success(request, _("The switch management credentials were added."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{ {"preferenceform": switchmanagementcred, "action_name": _("Add"),},
"preferenceform": switchmanagementcred,
"action_name": _("Add"),
},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )
@ -391,7 +392,10 @@ def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
) )
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{"objet": switchmanagementcred_instance, "objet_name": _("switch management credentials")}, {
"objet": switchmanagementcred_instance,
"objet_name": _("switch management credentials"),
},
"preferences/delete.html", "preferences/delete.html",
request, request,
) )
@ -407,10 +411,7 @@ def add_mailcontact(request):
messages.success(request, _("The contact email address was created.")) messages.success(request, _("The contact email address was created."))
return redirect(reverse("preferences:display-options")) return redirect(reverse("preferences:display-options"))
return form( return form(
{ {"preferenceform": mailcontact, "action_name": _("Add"),},
"preferenceform": mailcontact,
"action_name": _("Add"),
},
"preferences/preferences.html", "preferences/preferences.html",
request, request,
) )

View file

@ -1,5 +1,39 @@
from django.contrib import admin # -*- mode: python; coding: utf-8 -*-
from .models import Ticket # 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 © 2019 Arthur Grisel-Davy
# Copyright © 2020 Gabriel Détraz
#
# 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.
"""
Ticket preferences model
"""
admin.site.register(Ticket)
# Register your models here. from django.contrib import admin
from .models import Ticket, CommentTicket
from reversion.admin import VersionAdmin
class TicketAdmin(VersionAdmin):
pass
class CommentTicketAdmin(VersionAdmin):
pass
admin.site.register(Ticket, TicketAdmin)
admin.site.register(CommentTicket, CommentTicketAdmin)

View file

@ -1,25 +1,80 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2019 Arthur Grisel-Davy
# Copyright © 2020 Gabriel Détraz
#
# 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.
"""
Ticket form
"""
from django import forms from django import forms
from django.template.loader import render_to_string
from django.forms import ModelForm, Form from django.forms import ModelForm, Form
from re2o.field_permissions import FieldPermissionFormMixin from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin from re2o.mixins import FormRevMixin
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .models import Ticket from .models import Ticket, CommentTicket
class NewTicketForm(ModelForm): class NewTicketForm(FormRevMixin, ModelForm):
""" Creation of a ticket""" """ Creation of a ticket"""
email = forms.EmailField(required=False)
class Meta: class Meta:
model = Ticket model = Ticket
fields = ["title", "description", "email"] fields = ["title", "description", "email"]
def __init__(self, *args, **kwargs):
request = kwargs.pop("request", None)
super(NewTicketForm, self).__init__(*args, **kwargs)
if request.user.is_authenticated:
self.fields.pop('email')
self.instance.user = request.user
self.fields['description'].help_text = render_to_string('tickets/help_text.html')
self.instance.language = getattr(request, "LANGUAGE_CODE", "en")
self.instance.request = request
class ChangeStatusTicketForm(ModelForm):
""" Change ticket status""" class EditTicketForm(FormRevMixin, ModelForm):
""" Creation of a ticket"""
class Meta: class Meta:
model = Ticket model = Ticket
fields = [] fields = "__all__"
def __init__(self, *args, **kwargs):
super(EditTicketForm, self).__init__(*args, **kwargs)
self.fields['email'].required = False
class CommentTicketForm(FormRevMixin, ModelForm):
"""Edit and create comment to a ticket"""
class Meta:
model = CommentTicket
fields = ["comment"]
def __init__(self, *args, **kwargs):
request = kwargs.pop("request", None)
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(CommentTicketForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields["comment"].label = _("comment")
self.instance.request = request

View file

@ -21,7 +21,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2.5\n" "Project-Id-Version: 2.5\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-22 19:00+0200\n" "POT-Creation-Date: 2020-04-23 03:10+0200\n"
"PO-Revision-Date: 2019-11-16 00:35+0100\n" "PO-Revision-Date: 2019-11-16 00:35+0100\n"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n" "Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n" "Language-Team: \n"
@ -30,68 +30,88 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
#: tickets/models.py:28 #: tickets/forms.py:76
msgid "comment"
msgstr "commentaire"
#: tickets/models.py:57
msgid "Title of the ticket." msgid "Title of the ticket."
msgstr "Titre du ticket." msgstr "Titre du ticket."
#: tickets/models.py:32 #: tickets/models.py:66
msgid "Description of the ticket."
msgstr "Description du ticket."
#: tickets/models.py:38
msgid "An email address to get back to you." msgid "An email address to get back to you."
msgstr "Une adresse mail pour vous recontacter." msgstr "Une adresse mail pour vous recontacter."
#: tickets/models.py:44 #: tickets/models.py:70
msgid "Language of the ticket."
msgstr "Langue des tickets"
#: tickets/models.py:74 tickets/models.py:170
msgid "Can view a ticket object" msgid "Can view a ticket object"
msgstr "Peut voir un objet ticket" msgstr "Peut voir un objet ticket"
#: tickets/models.py:45 #: tickets/models.py:75 tickets/models.py:171
msgid "ticket" msgid "ticket"
msgstr "ticket" msgstr "ticket"
#: tickets/models.py:46 #: tickets/models.py:76 tickets/models.py:172
msgid "tickets" msgid "tickets"
msgstr "tickets" msgstr "tickets"
#: tickets/models.py:50 #: tickets/models.py:80
#, python-format #, python-format
msgid "Ticket from %(name)s. Date: %(date)s." msgid "Ticket from %(name)s. Date: %(date)s."
msgstr "Ticket de %(name)s. Date : %(date)s." msgstr "Ticket de %(name)s. Date : %(date)s."
#: tickets/models.py:52 #: tickets/models.py:82
#, python-format #, python-format
msgid "Anonymous ticket. Date: %s." msgid "Anonymous ticket. Date: %s."
msgstr "Ticket anonyme. Date : %s." msgstr "Ticket anonyme. Date : %s."
#: tickets/models.py:85 #: tickets/models.py:90 tickets/templates/tickets/aff_ticket.html:52
msgid "Anonymous user"
msgstr "Utilisateur anonyme"
#: tickets/models.py:128
msgid "You don't have the right to view other tickets than yours." msgid "You don't have the right to view other tickets than yours."
msgstr "Vous n'avez pas le droit de voir d'autres tickets que les vôtres." msgstr "Vous n'avez pas le droit de voir d'autres tickets que les vôtres."
#: tickets/models.py:97 #: tickets/models.py:140 tickets/models.py:214
msgid "You don't have the right to view the list of tickets." msgid "You don't have the right to view the list of tickets."
msgstr "Vous n'avez pas le droit de voir la liste des tickets." msgstr "Vous n'avez pas le droit de voir la liste des tickets."
#: tickets/preferences/models.py:10 #: tickets/models.py:187
msgid "You don't have the right to view other tickets comments than yours."
msgstr "Vous n'avez pas le droit de voir d'autres tickets que les vôtres."
#: tickets/models.py:202
msgid "You don't have the right to edit other tickets comments than yours."
msgstr "Vous n'avez pas le droit d'éditer d'autres tickets que les vôtres."
#: tickets/models.py:232
msgid "Update of your ticket"
msgstr "Mise à jour de votre ticket"
#: tickets/preferences/forms.py:44
msgid "Publish address"
msgstr "Adresse mail de publication"
#: tickets/preferences/models.py:39
msgid "" msgid ""
"Email address to publish the new tickets (leave empty for no publication)." "Email address to publish the new tickets (leave empty for no publication)."
msgstr "" msgstr ""
"Adresse mail où publier les nouveaux tickets (laissez vide pour ne pas " "Adresse mail où publier les nouveaux tickets (laissez vide pour ne pas "
"publier)." "publier)."
#: tickets/preferences/models.py:17 #: tickets/preferences/models.py:46
msgid "French" msgid "tickets options"
msgstr "Français" msgstr "Options des tickets"
#: tickets/preferences/models.py:17 #: tickets/preferences/models.py:47
msgid "English" msgid "Can view tickets options"
msgstr "Anglais" msgstr "Peut voir les options des tickets"
#: tickets/preferences/models.py:21 #: tickets/templates/tickets/aff_ticket.html:32
msgid "tickets preferences"
msgstr "préférences de tickets"
#: tickets/templates/tickets/aff_ticket.html:30
#: tickets/templates/tickets/contact.html:4 #: tickets/templates/tickets/contact.html:4
#: tickets/templates/tickets/index.html:29 #: tickets/templates/tickets/index.html:29
#: tickets/templates/tickets/preferences.html:6 #: tickets/templates/tickets/preferences.html:6
@ -99,59 +119,84 @@ msgstr "préférences de tickets"
msgid "Tickets" msgid "Tickets"
msgstr "Tickets" msgstr "Tickets"
#: tickets/templates/tickets/aff_ticket.html:34 #: tickets/templates/tickets/aff_ticket.html:36
#, python-format #, python-format
msgid "Ticket #%(id)s" msgid "Ticket #%(id)s"
msgstr "Ticket #%(id)s" msgstr "Ticket #%(id)s"
#: tickets/templates/tickets/aff_ticket.html:36 #: tickets/templates/tickets/aff_ticket.html:38
#: tickets/templates/tickets/aff_tickets.html:58 #: tickets/templates/tickets/aff_tickets.html:58
msgid "Solved" msgid "Solved"
msgstr "Résolu" msgstr "Résolu"
#: tickets/templates/tickets/aff_ticket.html:38 #: tickets/templates/tickets/aff_ticket.html:40
msgid "Not solved" msgid "Not solved"
msgstr "Non résolu" msgstr "Non résolu"
#: tickets/templates/tickets/aff_ticket.html:44 #: tickets/templates/tickets/aff_ticket.html:46
msgid "Opened by" msgid "Opened by"
msgstr "Ouvert par" msgstr "Ouvert par"
#: tickets/templates/tickets/aff_ticket.html:50 #: tickets/templates/tickets/aff_ticket.html:56
msgid "Anonymous user"
msgstr "Utilisateur anonyme"
#: tickets/templates/tickets/aff_ticket.html:54
msgid "Response address: " msgid "Response address: "
msgstr "Adresse de réponse : " msgstr "Adresse de réponse : "
#: tickets/templates/tickets/aff_ticket.html:54 #: tickets/templates/tickets/aff_ticket.html:56
msgid "Response to your ticket" msgid "Response to your ticket"
msgstr "Réponse à votre ticket" msgstr "Réponse à votre ticket"
#: tickets/templates/tickets/aff_ticket.html:59 #: tickets/templates/tickets/aff_ticket.html:61
msgid "Title:" msgid "Add a comment "
msgstr "Titre :" msgstr "Ajouter un commentaire"
#: tickets/templates/tickets/aff_ticket.html:60 #: tickets/templates/tickets/aff_ticket.html:64
msgid "Description:" #: tickets/templates/tickets/preferences.html:14 tickets/views.py:153
msgstr "Description :" msgid "Edit"
msgstr "Modifier"
#: tickets/templates/tickets/aff_ticket.html:68 #: tickets/templates/tickets/aff_ticket.html:66
msgid "Mark as solved" msgid "Mark as solved"
msgstr "Marquer comme résolu" msgstr "Marquer comme résolu"
#: tickets/templates/tickets/aff_ticket.html:71 #: tickets/templates/tickets/aff_ticket.html:68
msgid "Mark as not solved" msgid "Mark as unsolved"
msgstr "Marquer comme non résolu" msgstr "Marquer comme non résolu"
#: tickets/templates/tickets/aff_ticket.html:81 #: tickets/templates/tickets/aff_ticket.html:76
msgid "Title:"
msgstr "Titre :"
#: tickets/templates/tickets/aff_ticket.html:77
#: tickets/templates/tickets/aff_ticket.html:84
msgid "Description:"
msgstr "Description :"
#: tickets/templates/tickets/aff_ticket.html:83
msgid "Comment "
msgstr "Commentaire"
#: tickets/templates/tickets/aff_ticket.html:83
msgid " added by "
msgstr " ajouté par "
#: tickets/templates/tickets/aff_ticket.html:83
msgid " on "
msgstr " le "
#: tickets/templates/tickets/aff_ticket.html:87
msgid "Edit this comment "
msgstr "Modifier le commentaire"
#: tickets/templates/tickets/aff_ticket.html:90
msgid "Delete this comment "
msgstr "Supprimer ce commentaire"
#: tickets/templates/tickets/aff_ticket.html:99
msgid "All tickets" msgid "All tickets"
msgstr "Tous les tickets" msgstr "Tous les tickets"
#: tickets/templates/tickets/aff_tickets.html:35 #: tickets/templates/tickets/aff_tickets.html:35
#: tickets/templates/tickets/form_preferences.html:30 #: tickets/templates/tickets/edit.html:31
#: tickets/templates/tickets/form_ticket.html:31
msgid "Ticket" msgid "Ticket"
msgid_plural "Tickets" msgid_plural "Tickets"
msgstr[0] "Ticket" msgstr[0] "Ticket"
@ -201,28 +246,26 @@ msgstr ""
msgid "Open a ticket" msgid "Open a ticket"
msgstr "Ouvrir un ticket" msgstr "Ouvrir un ticket"
#: tickets/templates/tickets/form_preferences.html:33 #: tickets/templates/tickets/delete.html:29
msgid "Editing of tickets preferences" msgid "Deletion of tickets"
msgstr "Modification des préférences de tickets" msgstr "Suppression de tickets"
#: tickets/templates/tickets/form_preferences.html:46 #: tickets/templates/tickets/delete.html:35
#: tickets/templates/tickets/preferences.html:14 #, python-format
msgid "Edit" msgid ""
msgstr "Modifier" "Warning: are you sure you want to delete this %(objet_name)s object "
"( %(objet)s )?"
msgstr ""
#: tickets/templates/tickets/form_ticket.html:34 #: tickets/templates/tickets/delete.html:36
msgid "Confirm"
msgstr "Confirmer"
#: tickets/templates/tickets/edit.html:34
msgid "Ticket opening" msgid "Ticket opening"
msgstr "Ouverture de ticket" msgstr "Ouverture de ticket"
#: tickets/templates/tickets/form_ticket.html:39 tickets/views.py:90 #: tickets/templates/tickets/help_text.html:3
msgid ""
"You are not authenticated. Please log in or provide an email address so we "
"can get back to you."
msgstr ""
"Vous n'êtes pas authentifié. Veuillez vous connecter ou fournir une adresse "
"mail pour que nous puissions vous recontacter."
#: tickets/templates/tickets/form_ticket.html:44
msgid "" msgid ""
"Description of your problem. Please give as much information as possible to " "Description of your problem. Please give as much information as possible to "
"help us searching for a solution. Here is some information we might need:" "help us searching for a solution. Here is some information we might need:"
@ -231,11 +274,11 @@ msgstr ""
"possible pour nous aider à chercher une solution. Voici quelques " "possible pour nous aider à chercher une solution. Voici quelques "
"informations dont nous pourrions avoir besoin :" "informations dont nous pourrions avoir besoin :"
#: tickets/templates/tickets/form_ticket.html:47 #: tickets/templates/tickets/help_text.html:6
msgid "The type of your problem (membership, connection, payment etc.)." msgid "The type of your problem (membership, connection, payment etc.)."
msgstr "Le type de votre problème (adhésion, connexion, paiement etc.)." msgstr "Le type de votre problème (adhésion, connexion, paiement etc.)."
#: tickets/templates/tickets/form_ticket.html:50 #: tickets/templates/tickets/help_text.html:9
msgid "" msgid ""
"The conditions in which you encounter the problem (Wi-Fi/wired connection, " "The conditions in which you encounter the problem (Wi-Fi/wired connection, "
"on every machines or only one, on a new machine etc.)." "on every machines or only one, on a new machine etc.)."
@ -244,7 +287,7 @@ msgstr ""
"filaire, sur toutes les machines ou une seule, sur une nouvelle machine " "filaire, sur toutes les machines ou une seule, sur une nouvelle machine "
"etc.)." "etc.)."
#: tickets/templates/tickets/form_ticket.html:53 #: tickets/templates/tickets/help_text.html:12
msgid "" msgid ""
"The locations where you encounter the problem (in your room, in a common " "The locations where you encounter the problem (in your room, in a common "
"space, in a specific building etc.)." "space, in a specific building etc.)."
@ -252,10 +295,6 @@ msgstr ""
"Les lieux où vous rencontrez le problème (dans votre chambre, dans un espace " "Les lieux où vous rencontrez le problème (dans votre chambre, dans un espace "
"commun, dans un bâtiment en particulier etc.)." "commun, dans un bâtiment en particulier etc.)."
#: tickets/templates/tickets/form_ticket.html:56
msgid "Open the ticket"
msgstr "Ouvrir le ticket"
#: tickets/templates/tickets/index.html:32 #: tickets/templates/tickets/index.html:32
msgid "List of tickets" msgid "List of tickets"
msgstr "Liste des tickets" msgstr "Liste des tickets"
@ -272,29 +311,78 @@ msgstr "Adresse mail de publication"
msgid "No email address, the tickets will not be published." msgid "No email address, the tickets will not be published."
msgstr "Pas d'adresse mail, les tickets ne seront pas publiés." msgstr "Pas d'adresse mail, les tickets ne seront pas publiés."
#: tickets/templates/tickets/preferences.html:29
msgid "Email language"
msgstr "Langue du mail"
#: tickets/templates/tickets/profil.html:19 #: tickets/templates/tickets/profil.html:19
msgid "No tickets" msgid "No tickets"
msgstr "Pas de tickets" msgstr "Pas de tickets"
#: tickets/views.py:71 tickets/views.py:82 #: tickets/views.py:62
msgid "" msgid ""
"Your ticket has been succesfully opened. We will take care of it as soon as " "Your ticket has been succesfully opened. We will take care of it as soon as "
"possible." "possible."
msgstr "" msgstr ""
"Votre ticket a bien été ouvert. Nous nous en occuperons dès que possible." "Votre ticket a bien été ouvert. Nous nous en occuperons dès que possible."
#: tickets/views.py:127 tickets/views.py:177 #: tickets/views.py:109
msgid "Ticket has been updated successfully"
msgstr "Le ticket a été mis à jour"
#: tickets/views.py:130
msgid "This comment was added."
msgstr "Le commentaire a été ajouté"
#: tickets/views.py:135
msgid "Add a comment"
msgstr "Ajouter un commentaire"
#: tickets/views.py:148
msgid "This comment was edited."
msgstr "Le commentaire a été édité"
#: tickets/views.py:164
msgid "The comment was deleted."
msgstr "Le commentaire a été supprimé"
#: tickets/views.py:169
msgid "Ticket Comment"
msgstr "Commentaire de ticket"
#: tickets/views.py:183 tickets/views.py:208
msgid "Never" msgid "Never"
msgstr "Jamais" msgstr "Jamais"
#: tickets/views.py:154 #~ msgid "Description of the ticket."
msgid "The tickets preferences were edited." #~ msgstr "Description du ticket."
msgstr "Les préférences de tickets ont été modifiées."
#: tickets/views.py:157 #~ msgid "Mail language"
msgid "Invalid form." #~ msgstr "Langue du mail"
msgstr "Formulaire invalide."
#~ msgid "French"
#~ msgstr "Français"
#~ msgid "English"
#~ msgstr "Anglais"
#~ msgid "Mark as not solved"
#~ msgstr "Marquer comme non résolu"
#~ msgid "Editing of tickets preferences"
#~ msgstr "Modification des préférences de tickets"
#~ msgid ""
#~ "You are not authenticated. Please log in or provide an email address so "
#~ "we can get back to you."
#~ msgstr ""
#~ "Vous n'êtes pas authentifié. Veuillez vous connecter ou fournir une "
#~ "adresse mail pour que nous puissions vous recontacter."
#~ msgid "Email language"
#~ msgstr "Langue du mail"
#~ msgid "The tickets preferences were edited."
#~ msgstr "Les préférences de tickets ont été modifiées."
#~ msgid "Invalid form."
#~ msgstr "Formulaire invalide."
#~ msgid "tickets preferences"
#~ msgstr "préférences de tickets"

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-22 16:39
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('tickets', '0002_auto_20191120_0159'),
]
operations = [
migrations.RenameModel(
old_name='Preferences',
new_name='TicketOption',
),
migrations.AlterModelOptions(
name='ticketoption',
options={'permissions': (('view_ticketoption', 'Can view tickets options'),), 'verbose_name': 'tickets options'},
),
]

View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-22 19:27
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tickets', '0003_auto_20200422_1839'),
]
operations = [
migrations.RemoveField(
model_name='ticketoption',
name='mail_language',
),
migrations.AlterField(
model_name='ticket',
name='description',
field=models.TextField(max_length=3000),
),
]

View file

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-22 21:09
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import re2o.mixins
class Migration(migrations.Migration):
dependencies = [
('tickets', '0004_auto_20200422_2127'),
]
operations = [
migrations.CreateModel(
name='CommentTicket',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date', models.DateTimeField(auto_now_add=True)),
('comment', models.TextField(max_length=4095)),
],
options={
'verbose_name': 'ticket',
'verbose_name_plural': 'tickets',
'permissions': (('view_commentticket', 'Can view a ticket object'),),
},
bases=(re2o.mixins.AclMixin, models.Model),
),
migrations.AlterModelOptions(
name='ticket',
options={'permissions': (('view_ticket', 'Can view a ticket object'),), 'verbose_name': 'ticket', 'verbose_name_plural': 'tickets'},
),
migrations.AddField(
model_name='commentticket',
name='parent_ticket',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tickets.Ticket'),
),
]

View file

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-23 00:02
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('tickets', '0005_auto_20200422_2309'),
]
operations = [
migrations.AddField(
model_name='commentticket',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
preserve_default=False,
),
migrations.AddField(
model_name='commentticket',
name='created_by',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ticket_comment', to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.28 on 2020-04-23 01:05
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tickets', '0006_auto_20200423_0202'),
]
operations = [
migrations.AddField(
model_name='ticket',
name='language',
field=models.CharField(default='en', help_text='Language of the ticket.', max_length=16),
),
]

View file

@ -1,17 +1,47 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2019 Arthur Grisel-Davy
# Copyright © 2020 Gabriel Détraz
#
# 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.
"""
Ticket model
"""
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.template import loader from django.template import loader
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.functional import cached_property
from reversion.models import Version
from re2o.mixins import AclMixin from re2o.mixins import AclMixin
from re2o.mail_utils import send_mail from re2o.mail_utils import send_mail_object
from django.core.mail import EmailMessage
from preferences.models import GeneralOption from preferences.models import GeneralOption
import users.models import users.models
from .preferences.models import Preferences from .preferences.models import TicketOption
class Ticket(AclMixin, models.Model): class Ticket(AclMixin, models.Model):
@ -29,7 +59,6 @@ class Ticket(AclMixin, models.Model):
) )
description = models.TextField( description = models.TextField(
max_length=3000, max_length=3000,
help_text=_("Description of the ticket."),
blank=False, blank=False,
null=False, null=False,
) )
@ -38,10 +67,13 @@ class Ticket(AclMixin, models.Model):
help_text=_("An email address to get back to you."), max_length=100, null=True help_text=_("An email address to get back to you."), max_length=100, null=True
) )
solved = models.BooleanField(default=False) solved = models.BooleanField(default=False)
language = models.CharField(
max_length=16, help_text=_("Language of the ticket."), default="en"
)
request = None request = None
class Meta: class Meta:
permissions = (("view_tickets", _("Can view a ticket object")),) permissions = (("view_ticket", _("Can view a ticket object")),)
verbose_name = _("ticket") verbose_name = _("ticket")
verbose_name_plural = _("tickets") verbose_name_plural = _("tickets")
@ -51,39 +83,52 @@ class Ticket(AclMixin, models.Model):
else: else:
return _("Anonymous ticket. Date: %s.") % (self.date) return _("Anonymous ticket. Date: %s.") % (self.date)
def publish_mail(self, request=None): @cached_property
site_url = GeneralOption.objects.first().main_site_url def opened_by(self):
to_addr = Preferences.objects.first().publish_address """Return full name of this ticket opener"""
if self.user:
return self.user.get_full_name()
else:
return _("Anonymous user")
@cached_property
def get_mail(self):
"""Return the mail of the owner of this ticket"""
return self.email or self.user.get_mail
def publish_mail(self):
site_url = GeneralOption.get_cached_value("main_site_url")
to_addr = TicketOption.get_cached_value("publish_address")
context = {"ticket": self, "site_url": site_url} context = {"ticket": self, "site_url": site_url}
lang = Preferences.objects.first().mail_language if self.language == "fr":
if lang == 0:
obj = "Nouveau ticket ouvert" obj = "Nouveau ticket ouvert"
template = loader.get_template("tickets/publication_mail_fr") template = loader.get_template("tickets/publication_mail_fr")
else: else:
obj = "New ticket opened" obj = "New ticket opened"
template = loader.get_template("tickets/publication_mail_en") template = loader.get_template("tickets/publication_mail_en")
send_mail( mail_to_send = EmailMessage(
request,
obj, obj,
template.render(context), template.render(context),
GeneralOption.get_cached_value("email_from"), GeneralOption.get_cached_value("email_from"),
[to_addr], [to_addr],
fail_silently=False, reply_to=[self.get_mail],
) )
send_mail_object(mail_to_send, self.request)
def can_view(self, user_request, *_args, **_kwargs): def can_view(self, user_request, *_args, **_kwargs):
""" Check that the user has the right to view the ticket """ Check that the user has the right to view the ticket
or that it is the author""" or that it is the author"""
if ( if (
not user_request.has_perm("tickets.view_tickets") not user_request.has_perm("tickets.view_ticket")
and self.user != user_request and self.user != user_request
): ):
return ( return (
False, False,
_("You don't have the right to view other tickets than yours."), _("You don't have the right to view other tickets than yours."),
("tickets.view_tickets",), ("tickets.view_ticket",),
) )
else: else:
return True, None, None return True, None, None
@ -91,13 +136,13 @@ class Ticket(AclMixin, models.Model):
@staticmethod @staticmethod
def can_view_all(user_request, *_args, **_kwargs): def can_view_all(user_request, *_args, **_kwargs):
""" Check that the user has access to the list of all tickets""" """ Check that the user has access to the list of all tickets"""
can = user_request.has_perm("tickets.view_tickets") can = user_request.has_perm("tickets.view_ticket")
return ( return (
can, can,
_("You don't have the right to view the list of tickets.") _("You don't have the right to view the list of tickets.")
if not can if not can
else None, else None,
("tickets.view_tickets",), ("tickets.view_ticket",),
) )
def can_create(user_request, *_args, **_kwargs): def can_create(user_request, *_args, **_kwargs):
@ -105,10 +150,112 @@ class Ticket(AclMixin, models.Model):
return True, None, None return True, None, None
class CommentTicket(AclMixin, models.Model):
"""A comment of a ticket"""
date = models.DateTimeField(auto_now_add=True)
comment = models.TextField(
max_length=4095,
blank=False,
null=False,
)
parent_ticket = models.ForeignKey(
"Ticket", on_delete=models.CASCADE
)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(
"users.User",
on_delete=models.CASCADE,
related_name="ticket_comment",
)
request = None
class Meta:
permissions = (("view_commentticket", _("Can view a ticket object")),)
verbose_name = _("ticket")
verbose_name_plural = _("tickets")
@cached_property
def comment_id(self):
return CommentTicket.objects.filter(parent_ticket=self.parent_ticket, pk__lt=self.pk).count() + 1
def can_view(self, user_request, *_args, **_kwargs):
""" Check that the user has the right to view the ticket comment
or that it is the author"""
if (
not user_request.has_perm("tickets.view_commentticket")
and self.parent_ticket.user != user_request
):
return (
False,
_("You don't have the right to view other tickets comments than yours."),
("tickets.view_commentticket",),
)
else:
return True, None, None
def can_edit(self, user_request, *_args, **_kwargs):
""" Check that the user has the right to edit the ticket comment
or that it is the author"""
if (
not user_request.has_perm("tickets.edit_commentticket")
and (self.parent_ticket.user != user_request or self.parent_ticket.user != self.created_by)
):
return (
False,
_("You don't have the right to edit other tickets comments than yours."),
("tickets.edit_commentticket",),
)
else:
return True, None, None
@staticmethod
def can_view_all(user_request, *_args, **_kwargs):
""" Check that the user has access to the list of all tickets comments"""
can = user_request.has_perm("tickets.view_commentticket")
return (
can,
_("You don't have the right to view the list of tickets.")
if not can
else None,
("tickets.view_commentticket",),
)
def __str__(self):
return "Comment " + str(self.comment_id) + " on " + str(self.parent_ticket)
def publish_mail(self):
"""Send mail to user and admin after new comment"""
site_url = GeneralOption.get_cached_value("main_site_url")
to_addr = TicketOption.get_cached_value("publish_address")
context = {"comment": self, "site_url": site_url}
if self.parent_ticket.language == "fr":
template = loader.get_template("tickets/update_mail_fr")
else:
template = loader.get_template("tickets/update_mail_en")
obj = _("Update of your ticket")
mail_to_send = EmailMessage(
obj,
template.render(context),
GeneralOption.get_cached_value("email_from"),
[to_addr, self.parent_ticket.get_mail],
)
send_mail_object(mail_to_send, self.request)
@receiver(post_save, sender=Ticket) @receiver(post_save, sender=Ticket)
def ticket_post_save(**kwargs): def ticket_post_save(**kwargs):
""" Send the mail to publish the new ticket """ """ Send the mail to publish the new ticket """
if kwargs["created"]: if kwargs["created"]:
if Preferences.objects.first().publish_address: if TicketOption.get_cached_value("publish_address"):
ticket = kwargs["instance"] ticket = kwargs["instance"]
ticket.publish_mail(ticket.request) ticket.publish_mail()
@receiver(post_save, sender=CommentTicket)
def comment_post_save(**kwargs):
""" Send the mail to publish the new comment """
if kwargs["created"]:
if TicketOption.get_cached_value("publish_address"):
comment = kwargs["instance"]
comment.publish_mail()

View file

@ -1,13 +1,44 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2019 Arthur Grisel-Davy
# Copyright © 2020 Gabriel Détraz
#
# 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.
"""
Ticket preferences form
"""
from django import forms from django import forms
from django.forms import ModelForm, Form from django.forms import ModelForm, Form
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from .models import Preferences from re2o.mixins import FormRevMixin
from .models import TicketOption
class EditPreferencesForm(ModelForm): class EditTicketOptionForm(FormRevMixin, ModelForm):
""" Edit the ticket's settings""" """ Edit the ticket's settings"""
class Meta: class Meta:
model = Preferences model = TicketOption
fields = "__all__" fields = "__all__"
def __init__(self, *args, **kwargs):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(EditTicketOptionForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields["publish_address"].label = _("Publish address")

View file

@ -1,8 +1,37 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2019 Arthur Grisel-Davy
# Copyright © 2020 Gabriel Détraz
#
# 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.
"""
Ticket preferences model
"""
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from re2o.mixins import AclMixin, RevMixin
from preferences.models import PreferencesModel
class Preferences(models.Model):
class TicketOption(AclMixin, PreferencesModel):
""" Definition of the ticket's settings""" """ Definition of the ticket's settings"""
publish_address = models.EmailField( publish_address = models.EmailField(
@ -12,10 +41,7 @@ class Preferences(models.Model):
max_length=1000, max_length=1000,
null=True, null=True,
) )
LANG_FR = 0
LANG_EN = 1
LANGUES = ((0, _("French")), (1, _("English")))
mail_language = models.IntegerField(choices=LANGUES, default=LANG_FR)
class Meta: class Meta:
verbose_name = _("tickets preferences") verbose_name = _("tickets options")
permissions = (("view_ticketoption", _("Can view tickets options")),)

View file

@ -0,0 +1,57 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2020 Gabriel Détraz
# Copyright © 2019 Arthur Grisel-Davy
#
# 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 re2o
# Lara Kermarec, Gabriel Détraz, Lemesle Augustin
# Gplv2
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.template.loader import render_to_string
from django.utils.translation import ugettext as _
from django.urls import reverse
from re2o.base import re2o_paginator
from re2o.acl import can_view, can_view_all, can_edit, can_create
from preferences.views import edit_options_template_function
from . import forms
from . import models
def aff_preferences(request):
""" View to display the settings of the tickets in the preferences page"""
pref, created = models.TicketOption.objects.get_or_create()
context = {
"preferences": pref,
}
return render_to_string(
"tickets/preferences.html", context=context, request=request, using=None
)
@login_required
def edit_options(request, section):
return edit_options_template_function(request, section, forms, models)

View file

@ -26,6 +26,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% load bootstrap3 %} {% load bootstrap3 %}
{% load i18n %} {% load i18n %}
{% load humanize %} {% load humanize %}
{% load logs_extra %}
{% load acl %}
{% block title %}{% trans "Tickets" %}{% endblock %} {% block title %}{% trans "Tickets" %}{% endblock %}
@ -53,32 +55,48 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% if not ticket.user %} {% if not ticket.user %}
{% trans "Response address: " %}<A HREF="mailto:{{ticket.email}}?subject={% trans "Response to your ticket"%}">{{ticket.email}}</A> {% trans "Response address: " %}<A HREF="mailto:{{ticket.email}}?subject={% trans "Response to your ticket"%}">{{ticket.email}}</A>
{% endif %} {% endif %}
<div class="text-right">
{% can_view ticket %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'tickets:add-comment' ticket.id %}"><i class="fa fa-plus"></i> {% trans "Add a comment " %}</a>
{% acl_end %}
{% can_edit ticket %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'tickets:edit-ticket' ticket.id %}"><i class="fa fa-edit"></i> {% trans "Edit" %}</a>
{% if not ticket.solved %}
<a class="btn btn-success btn-sm" role="button" href="{% url 'tickets:change-ticket-status' ticket.id %}"><i class="fa fa-check"></i> {% trans "Mark as solved" %}</a>
{% else %}
<a class="btn btn-warning btn-sm" role="button" href="{% url 'tickets:change-ticket-status' ticket.id %}"><i class="fa fa-close"></i> {% trans "Mark as unsolved" %}</a>
{% endif %}
{% acl_end %}
{% history_button ticket text=True %}
</div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<p><b>{% trans "Title:" %}</b> {{ticket.title}}</p> <p><b>{% trans "Title:" %}</b> {{ticket.title}}</p>
<p><b>{% trans "Description:" %}</b> {{ ticket.description }}</p> <b>{% trans "Description:" %}</b> {{ ticket.description | linebreaks }}
<div class="text-right">
<form class="form" method="post">
{% csrf_token %}
{% bootstrap_form changestatusform %}
{% if not ticket.solved %}
{% trans "Mark as solved" as tr_mark_solved %}
{% bootstrap_button tr_mark_solved button_type="submit" button_class='btn-info' %}
{% else %}
{% trans "Mark as not solved" as tr_mark_not_solved %}
{% bootstrap_button tr_mark_not_solved button_type="submit" button_class='btn-warning' %}
{% endif %}
</form>
</div>
</div>
</div> </div>
{% for comment in comments %}
<div class="panel-footer">
<p><span class="badge">{% trans "Comment " %}<b>#{{comment.comment_id}}</b></span> {% trans " added by " %}{{ comment.created_by.get_full_name }}{% trans " on " %} {{comment.created_at}}</p>
<b>{% trans "Description:" %}</b> {{ comment.comment | linebreaks }}
<div class="text-right">
{% can_edit comment %}
<a class="btn btn-info btn-sm" role="button" href="{% url 'tickets:edit-comment' comment.id %}"><i class="fa fa-edit"></i> {% trans "Edit this comment " %}</a>
{% acl_end %}
{% can_delete comment %}
<a class="btn btn-danger btn-sm" role="button" href="{% url 'tickets:del-comment' comment.id %}"><i class="fa fa-close"></i> {% trans "Delete this comment " %}</a>
{% acl_end %}
{% history_button comment text=True %}
</div>
</div>
{% endfor %}
</div>
<div class="text-right"> <div class="text-right">
<a type="button" href="{% url 'tickets:aff-tickets' %}" class="btn btn-primary"><p>{% trans "All tickets" %}</p></a> <a class="btn btn-primary" role="button" href="{% url 'tickets:aff-tickets' %}"><i class="fa fa-reorder"></i> {% trans "All tickets" %}</a>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,43 @@
{% extends 'users/sidebar.html' %}
{% comment %}
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 Lara 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.
{% endcomment %}
{% load bootstrap3 %}
{% load i18n %}
{% block title %}{% trans "Deletion of tickets" %}{% endblock %}
{% block content %}
<form class="form" method="post">
{% csrf_token %}
<h4>{% blocktrans %}Warning: are you sure you want to delete this {{ objet_name }} object ( {{ objet }} )?{% endblocktrans %}</h4>
{% trans "Confirm" as tr_confirm %}
{% bootstrap_button tr_confirm button_type="submit" icon="trash" button_class='btn-danger' %}
</form>
<br />
<br />
<br />
{% endblock %}

View file

@ -1,4 +1,4 @@
{% extends 'machines/sidebar.html' %} {% extends 'users/sidebar.html' %}
{% comment %} {% comment %}
Re2o est un logiciel d'administration développé initiallement au rezometz. Il 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 se veut agnostique au réseau considéré, de manière à être installable en
@ -25,25 +25,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %} {% endcomment %}
{% load bootstrap3 %} {% load bootstrap3 %}
{% load massive_bootstrap_form %}
{% load i18n %} {% load i18n %}
{% block title %}{% trans "Ticket" %}{% endblock %} {% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %} {% block content %}
<h2> {% trans "Editing of tickets preferences" %}</h2> <h2>{% trans "Ticket opening" %}</h2>
{% for message in messages %} {% bootstrap_form_errors ticketform %}
<div class="{{ message| bootstrap_message_classes }} alert-dismissable">
<button type="button" class="close" data_dismiss="alert" aria-hidden="true">&#125;</button>
{{ message | safe }}
</div>
{% endfor %}
<form class="form" method="post"> <form class="form" method="post">
{% csrf_token %} {% csrf_token %}
{% bootstrap_field preferencesform.publish_address %} {% bootstrap_form ticketform %}
{% bootstrap_field preferencesform.mail_language %} {% bootstrap_button action_name button_type="submit" icon='ok' button_class='btn-success' %}
{% trans "Edit" as tr_edit %}
{% bootstrap_button tr_edit button_type="submit" icon='ok' button_class='btn-success' %}
</form> </form>
{% endblock %} {% endblock %}

View file

@ -1,59 +0,0 @@
{% extends 'users/sidebar.html' %}
{% comment %}
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 Lara Kermarec
Copyright © 2017 Augustin Lemesle
Copyright © 2017 Maël Kervella
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.
{% endcomment %}
{% load bootstrap3 %}
{% load massive_bootstrap_form %}
{% load i18n %}
{% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %}
<h2>{% trans "Ticket opening" %}</h2>
<form class="form" method="post">
{% csrf_token %}
{% if not user.is_authenticated %}
<p>{% trans "You are not authenticated. Please log in or provide an email address so we can get back to you." %}</p>
{% bootstrap_field ticketform.email %}
{% endif %}
{% bootstrap_field ticketform.title %}
<br>
<p>{% trans "Description of your problem. Please give as much information as possible to help us searching for a solution. Here is some information we might need:" %}</p>
<ul class="list">
<li>
<p> {% trans "The type of your problem (membership, connection, payment etc.)." %}</p>
</li>
<li>
<p> {% trans "The conditions in which you encounter the problem (Wi-Fi/wired connection, on every machines or only one, on a new machine etc.)." %}</p>
</li>
<li>
<p> {% trans "The locations where you encounter the problem (in your room, in a common space, in a specific building etc.)." %}</p>
</ul>
{% bootstrap_field ticketform.description %}
{% trans "Open the ticket" as tr_open %}
{% bootstrap_button tr_open button_type="submit" icon='ok' button_class='btn-success' %}
</form>
{% endblock %}

View file

@ -0,0 +1,14 @@
{% load i18n %}
<br>
<p>{% trans "Description of your problem. Please give as much information as possible to help us searching for a solution. Here is some information we might need:" %}</p>
<ul class="list">
<li>
<p> {% trans "The type of your problem (membership, connection, payment etc.)." %}</p>
</li>
<li>
<p> {% trans "The conditions in which you encounter the problem (Wi-Fi/wired connection, on every machines or only one, on a new machine etc.)." %}</p>
</li>
<li>
<p> {% trans "The locations where you encounter the problem (in your room, in a common space, in a specific building etc.)." %}</p>
</ul>

View file

@ -9,7 +9,7 @@
<div id="collapse_tickets" class="panel-collapse panel-body collapse"> <div id="collapse_tickets" class="panel-collapse panel-body collapse">
<a class="btn btn-primary btn-sm" role="button" href="{% url 'tickets:edit-preferences-tickets' %}"> <a class="btn btn-primary btn-sm" role="button" href="{% url 'tickets:edit-options' 'TicketOption' %}">
<i class="fa fa-edit"></i> <i class="fa fa-edit"></i>
{% trans "Edit" %} {% trans "Edit" %}
</a> </a>
@ -25,12 +25,8 @@
<td><p>{% trans "No email address, the tickets will not be published." %}</p></td> <td><p>{% trans "No email address, the tickets will not be published." %}</p></td>
{% endif %} {% endif %}
</tr> </tr>
<tr>
<th><p>{% trans "Email language" %}</p></th>
<td><p>{{ language }}</p></th>
</tr>
<table class="table"> <table class="table">
</table> </table>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,12 +1,12 @@
{% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket. {% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket.
Profile: {{site_url}}{% url 'users:profil' ticket.user.id%} Profile: {{site_url}}{% url 'users:profil' ticket.user.id%}
Answer to the address: {{ticket.user.get_mail}}.
{% else %} {% else %}
An anonymous user (not authenticated) opened a ticket An anonymous user (not authenticated) opened a ticket
Answer to the address:{{ticket.email}}.
{% endif %} {% endif %}
Answer to the address: {{{ticket.get_mail}}.
Title: {{ticket.title}} Title: {{ ticket.title | safe }}
Description: {{ ticket.description | safe }}
Description: {{ticket.description}}

View file

@ -1,12 +1,12 @@
{% if ticket.user %} {{ ticket.user.get_full_name }} a ouvert un ticket. {% if ticket.user %} {{ ticket.user.get_full_name }} a ouvert un ticket.
Profil : {{site_url}}{% url 'users:profil' ticket.user.id%} Profil : {{site_url}}{% url 'users:profil' ticket.user.id%}
Répondre à l'adresse : {{ticket.user.get_mail}}.
{% else %} {% else %}
Un utilisateur anonyme (non connecté) a ouvert un ticket. Un utilisateur anonyme (non connecté) a ouvert un ticket.
Répondre à l'adresse : {{ticket.email}}.
{% endif %} {% endif %}
Répondre à l'adresse : {{ticket.get_mail}}.
Titre : {{ticket.title}}
Description : {{ticket.description}} Titre : {{ ticket.title | safe }}
Description : {{ ticket.description | safe }}

View file

@ -0,0 +1,12 @@
Hello,
The ticket {{ comment.parent_ticket.title | safe }} n°{{ comment.parent_ticket.id }}, opened by {{ comment.parent_ticket.opened_by }}, has been updated by {{ comment.created_by.get_full_name | safe }}.
{% if comment.parent_ticket.user %}
The complete re2o profil can be found here : {{site_url}}{% url 'users:profil' comment.parent_ticket.user.id%}
{% endif %}
Description : {{ comment.comment | safe }}
Best regards,
The member of the association

View file

@ -0,0 +1,12 @@
Bonjour,
Le ticket {{ comment.parent_ticket.title | safe }} n°{{ comment.parent_ticket.id }}, ouvert par {{ comment.parent_ticket.opened_by }}, a reçu une mise à jour par {{ comment.created_by.get_full_name | safe }}.
{% if comment.parent_ticket.user %}
Le profil re2o est accessible à l'adresse suivante : {{site_url}}{% url 'users:profil' comment.parent_ticket.user.id%}
{% endif %}
Description : {{ comment.comment | safe }}
Cordialement,
Les membres actifs de l'association

View file

@ -1,14 +1,45 @@
# -*- mode: python; coding: utf-8 -*-
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il
# se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics.
#
# Copyright © 2019 Arthur Grisel-Davy
# Copyright © 2020 Gabriel Détraz
#
# 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.
"""
Tickets url
"""
from django.conf.urls import url from django.conf.urls import url
from . import views from . import views
from .preferences.views import edit_options
urlpatterns = [ urlpatterns = [
url(r"^$", views.aff_tickets, name="aff-tickets"), url(r"^$", views.aff_tickets, name="aff-tickets"),
url(r"^ticket/(?P<ticketid>[0-9]+)$", views.aff_ticket, name="aff-ticket"), url(r"^(?P<ticketid>[0-9]+)$", views.aff_ticket, name="aff-ticket"),
url(r"^change_ticket_status/(?P<ticketid>[0-9]+)$", views.change_ticket_status, name="change-ticket-status"),
url(r"^edit_ticket/(?P<ticketid>[0-9]+)$", views.edit_ticket, name="edit-ticket"),
url( url(
r"^ticket/edit-preferences-tickets$", r"^edit_options/(?P<section>TicketOption)$",
views.edit_preferences, edit_options,
name="edit-preferences-tickets", name="edit-options",
), ),
url(r"^new_ticket/$", views.new_ticket, name="new-ticket"), url(r"^new_ticket/$", views.new_ticket, name="new-ticket"),
url(r"^add_comment/(?P<ticketid>[0-9]+)$", views.add_comment, name="add-comment"),
url(r"^edit_comment/(?P<commentticketid>[0-9]+)$", views.edit_comment, name="edit-comment"),
url(r"^del_comment/(?P<commentticketid>[0-9]+)$", views.del_comment, name="del-comment"),
] ]

View file

@ -3,9 +3,8 @@
# se veut agnostique au réseau considéré, de manière à être installable en # se veut agnostique au réseau considéré, de manière à être installable en
# quelques clics. # quelques clics.
# #
# Copyright © 2017 Gabriel Détraz # Copyright © 2019 Arthur Grisel-Davy
# Copyright © 2017 Lara Kermarec # Copyright © 2020 Gabriel Détraz
# Copyright © 2017 Augustin Lemesle
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -37,80 +36,137 @@ from re2o.views import form
from re2o.base import re2o_paginator from re2o.base import re2o_paginator
from re2o.acl import can_view, can_view_all, can_edit, can_create from re2o.acl import (
can_view,
can_view_all,
can_edit,
can_create,
can_delete
)
from preferences.models import GeneralOption from preferences.models import GeneralOption
from .models import Ticket from .models import Ticket, CommentTicket
from .preferences.models import Preferences from .forms import NewTicketForm, EditTicketForm, CommentTicketForm
from .forms import NewTicketForm, ChangeStatusTicketForm
from .preferences.forms import EditPreferencesForm
def new_ticket(request): def new_ticket(request):
""" Ticket creation view""" """ Ticket creation view"""
ticketform = NewTicketForm(request.POST or None) ticketform = NewTicketForm(request.POST or None, request=request)
if ticketform.is_valid():
if request.method == "POST": ticketform.save()
ticketform = NewTicketForm(request.POST) messages.success(
request,
if ticketform.is_valid(): _(
email = ticketform.cleaned_data.get("email") "Your ticket has been succesfully opened. We will take care of it as soon as possible."
ticket = ticketform.save(commit=False) ),
ticket.request = request )
if not request.user.is_authenticated:
if request.user.is_authenticated: return redirect(reverse("index"))
ticket.user = request.user else:
ticket.save() return redirect(
messages.success( reverse("users:profil", kwargs={"userid": str(request.user.id)})
request, )
_( return form(
"Your ticket has been succesfully opened. We will take care of it as soon as possible." {"ticketform": ticketform, 'action_name': ("Create a ticket")}, "tickets/edit.html", request
), )
)
return redirect(
reverse("users:profil", kwargs={"userid": str(request.user.id)})
)
if not request.user.is_authenticated and email != "":
ticket.save()
messages.success(
request,
_(
"Your ticket has been succesfully opened. We will take care of it as soon as possible."
),
)
return redirect(reverse("index"))
else:
messages.error(
request,
_(
"You are not authenticated. Please log in or provide an email address so we can get back to you."
),
)
return form(
{"ticketform": ticketform}, "tickets/form_ticket.html", request
)
else:
ticketform = NewTicketForm
return form({"ticketform": ticketform}, "tickets/form_ticket.html", request)
@login_required @login_required
@can_view(Ticket) @can_view(Ticket)
def aff_ticket(request, ticket, ticketid): def aff_ticket(request, ticket, ticketid):
"""View to display only one ticket""" """View to display only one ticket"""
changestatusform = ChangeStatusTicketForm(request.POST) comments = CommentTicket.objects.filter(parent_ticket=ticket)
if request.method == "POST":
ticket.solved = not ticket.solved
ticket.save()
return render( return render(
request, request,
"tickets/aff_ticket.html", "tickets/aff_ticket.html",
{"ticket": ticket, "changestatusform": changestatusform}, {"ticket": ticket, "comments": comments},
)
@login_required
@can_edit(Ticket)
def change_ticket_status(request, ticket, ticketid):
"""View to edit ticket state"""
ticket.solved = not ticket.solved
ticket.save()
return redirect(
reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)})
)
@login_required
@can_edit(Ticket)
def edit_ticket(request, ticket, ticketid):
""" Ticket creation view"""
ticketform = EditTicketForm(request.POST or None, instance=ticket)
if ticketform.is_valid():
ticketform.save()
messages.success(
request,
_(
"Ticket has been updated successfully"
),
)
return redirect(
reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)})
)
return form(
{"ticketform": ticketform, 'action_name': ("Edit this ticket")}, "tickets/edit.html", request
)
@login_required
@can_view(Ticket)
def add_comment(request, ticket, ticketid):
""" Add a comment to a ticket"""
commentticket = CommentTicketForm(request.POST or None, request=request)
if commentticket.is_valid():
commentticket = commentticket.save(commit=False)
commentticket.parent_ticket = ticket
commentticket.created_by = request.user
commentticket.save()
messages.success(request, _("This comment was added."))
return redirect(
reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)})
)
return form(
{"ticketform": commentticket, "action_name": _("Add a comment")}, "tickets/edit.html", request
)
@login_required
@can_edit(CommentTicket)
def edit_comment(request, commentticket_instance, **_kwargs):
""" Edit a comment of a ticket"""
commentticket = CommentTicketForm(request.POST or None, instance=commentticket_instance)
if commentticket.is_valid():
ticketid = commentticket_instance.parent_ticket.id
if commentticket.changed_data:
commentticket.save()
messages.success(request, _("This comment was edited."))
return redirect(
reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)})
)
return form(
{"ticketform": commentticket, "action_name": _("Edit")}, "tickets/edit.html", request,
)
@login_required
@can_delete(CommentTicket)
def del_comment(request, commentticket, **_kwargs):
"""Delete a comment of a ticket"""
if request.method == "POST":
ticketid = commentticket.parent_ticket.id
commentticket.delete()
messages.success(request, _("The comment was deleted."))
return redirect(
reverse("tickets:aff-ticket", kwargs={"ticketid": str(ticketid)})
)
return form(
{"objet": commentticket, "objet_name": _("Ticket Comment")}, "tickets/delete.html", request
) )
@ -140,31 +196,6 @@ def aff_tickets(request):
return render(request, "tickets/index.html", context=context) return render(request, "tickets/index.html", context=context)
def edit_preferences(request):
""" View to edit the settings of the tickets """
preferences_instance, created = Preferences.objects.get_or_create(id=1)
preferencesform = EditPreferencesForm(
request.POST or None, instance=preferences_instance
)
if preferencesform.is_valid():
if preferencesform.changed_data:
preferencesform.save()
messages.success(request, _("The tickets preferences were edited."))
return redirect(reverse("preferences:display-options"))
else:
messages.error(request, _("Invalid form."))
return form(
{"preferencesform": preferencesform},
"tickets/form_preferences.html",
request,
)
return form(
{"preferencesform": preferencesform}, "tickets/form_preferences.html", request
)
# views cannoniques des apps optionnels # views cannoniques des apps optionnels
def profil(request, user): def profil(request, user):
""" View to display the ticket's module on the profil""" """ View to display the ticket's module on the profil"""
@ -191,18 +222,6 @@ def profil(request, user):
) )
def preferences(request):
""" View to display the settings of the tickets in the preferences page"""
pref, created = Preferences.objects.get_or_create(id=1)
context = {
"preferences": pref,
"language": str(pref.LANGUES[pref.mail_language][1]),
}
return render_to_string(
"tickets/preferences.html", context=context, request=request, using=None
)
def contact(request): def contact(request):
"""View to display a contact address on the contact page """View to display a contact address on the contact page
used here to display a link to open a ticket""" used here to display a link to open a ticket"""