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

View file

@ -76,7 +76,12 @@ class OptionalUser(AclMixin, PreferencesModel):
ALL_ROOM = "ALL_ROOM"
ROOM_POLICY = (
(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")),
)
@ -98,7 +103,7 @@ class OptionalUser(AclMixin, PreferencesModel):
max_length=32,
choices=ROOM_POLICY,
default="DISABLED",
help_text=_("Policy on self users room edition")
help_text=_("Policy on self users room edition"),
)
local_email_accounts_enabled = models.BooleanField(
default=False, help_text=_("Enable local email accounts for users.")
@ -114,9 +119,7 @@ class OptionalUser(AclMixin, PreferencesModel):
)
delete_notyetactive = models.IntegerField(
default=15,
help_text=_(
"Not yet active users will be deleted after this number of days."
),
help_text=_("Not yet active users will be deleted after this number of days."),
)
disable_emailnotyetconfirmed = models.IntegerField(
default=2,
@ -217,7 +220,7 @@ class OptionalTopologie(AclMixin, PreferencesModel):
DEFINED = "DEFINED"
CHOICE_RADIUS = (
(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"))
@ -357,7 +360,9 @@ class OptionalTopologie(AclMixin, PreferencesModel):
)
class Meta:
permissions = (("view_optionaltopologie", _("Can view the topology preferences")),)
permissions = (
("view_optionaltopologie", _("Can view the topology preferences")),
)
verbose_name = _("topology preferences")
@ -568,7 +573,9 @@ class Mandate(RevMixin, AclMixin, models.Model):
)
if not mandate:
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
@ -675,7 +682,7 @@ class RadiusOption(AclMixin, PreferencesModel):
DEFINED = "DEFINED"
CHOICE_RADIUS = (
(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"
SET_VLAN = "SET_VLAN"

View file

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

View file

@ -87,6 +87,35 @@ from . import models
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
@can_view_all(
OptionalUser,
@ -120,9 +149,9 @@ def display_options(request):
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
optionnal_templates_list = [
app.views.preferences(request)
app.preferences.views.aff_preferences(request)
for app in optionnal_apps
if hasattr(app.views, "preferences")
if hasattr(app.preferences.views, "aff_preferences")
]
return form(
@ -153,32 +182,7 @@ def display_options(request):
@login_required
def edit_options(request, section):
""" 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()
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)
return edit_options_template_function(request, section, forms, models)
@login_required
@ -344,10 +348,7 @@ def add_switchmanagementcred(request):
messages.success(request, _("The switch management credentials were added."))
return redirect(reverse("preferences:display-options"))
return form(
{
"preferenceform": switchmanagementcred,
"action_name": _("Add"),
},
{"preferenceform": switchmanagementcred, "action_name": _("Add"),},
"preferences/preferences.html",
request,
)
@ -391,7 +392,10 @@ def del_switchmanagementcred(request, switchmanagementcred_instance, **_kwargs):
)
return redirect(reverse("preferences:display-options"))
return form(
{"objet": switchmanagementcred_instance, "objet_name": _("switch management credentials")},
{
"objet": switchmanagementcred_instance,
"objet_name": _("switch management credentials"),
},
"preferences/delete.html",
request,
)
@ -407,10 +411,7 @@ def add_mailcontact(request):
messages.success(request, _("The contact email address was created."))
return redirect(reverse("preferences:display-options"))
return form(
{
"preferenceform": mailcontact,
"action_name": _("Add"),
},
{"preferenceform": mailcontact, "action_name": _("Add"),},
"preferences/preferences.html",
request,
)

View file

@ -1,5 +1,39 @@
from django.contrib import admin
from .models import Ticket
# -*- 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
"""
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.template.loader import render_to_string
from django.forms import ModelForm, Form
from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
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"""
email = forms.EmailField(required=False)
class Meta:
model = Ticket
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:
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 ""
"Project-Id-Version: 2.5\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"
"Last-Translator: Laouen Fernet <laouen.fernet@supelec.fr>\n"
"Language-Team: \n"
@ -30,68 +30,88 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\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."
msgstr "Titre du ticket."
#: tickets/models.py:32
msgid "Description of the ticket."
msgstr "Description du ticket."
#: tickets/models.py:38
#: tickets/models.py:66
msgid "An email address to get back to you."
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"
msgstr "Peut voir un objet ticket"
#: tickets/models.py:45
#: tickets/models.py:75 tickets/models.py:171
msgid "ticket"
msgstr "ticket"
#: tickets/models.py:46
#: tickets/models.py:76 tickets/models.py:172
msgid "tickets"
msgstr "tickets"
#: tickets/models.py:50
#: tickets/models.py:80
#, python-format
msgid "Ticket from %(name)s. Date: %(date)s."
msgstr "Ticket de %(name)s. Date : %(date)s."
#: tickets/models.py:52
#: tickets/models.py:82
#, python-format
msgid "Anonymous ticket. 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."
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."
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 ""
"Email address to publish the new tickets (leave empty for no publication)."
msgstr ""
"Adresse mail où publier les nouveaux tickets (laissez vide pour ne pas "
"publier)."
#: tickets/preferences/models.py:17
msgid "French"
msgstr "Français"
#: tickets/preferences/models.py:46
msgid "tickets options"
msgstr "Options des tickets"
#: tickets/preferences/models.py:17
msgid "English"
msgstr "Anglais"
#: tickets/preferences/models.py:47
msgid "Can view tickets options"
msgstr "Peut voir les options des tickets"
#: tickets/preferences/models.py:21
msgid "tickets preferences"
msgstr "préférences de tickets"
#: tickets/templates/tickets/aff_ticket.html:30
#: tickets/templates/tickets/aff_ticket.html:32
#: tickets/templates/tickets/contact.html:4
#: tickets/templates/tickets/index.html:29
#: tickets/templates/tickets/preferences.html:6
@ -99,59 +119,84 @@ msgstr "préférences de tickets"
msgid "Tickets"
msgstr "Tickets"
#: tickets/templates/tickets/aff_ticket.html:34
#: tickets/templates/tickets/aff_ticket.html:36
#, python-format
msgid "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
msgid "Solved"
msgstr "Résolu"
#: tickets/templates/tickets/aff_ticket.html:38
#: tickets/templates/tickets/aff_ticket.html:40
msgid "Not solved"
msgstr "Non résolu"
#: tickets/templates/tickets/aff_ticket.html:44
#: tickets/templates/tickets/aff_ticket.html:46
msgid "Opened by"
msgstr "Ouvert par"
#: tickets/templates/tickets/aff_ticket.html:50
msgid "Anonymous user"
msgstr "Utilisateur anonyme"
#: tickets/templates/tickets/aff_ticket.html:54
#: tickets/templates/tickets/aff_ticket.html:56
msgid "Response address: "
msgstr "Adresse de réponse : "
#: tickets/templates/tickets/aff_ticket.html:54
#: tickets/templates/tickets/aff_ticket.html:56
msgid "Response to your ticket"
msgstr "Réponse à votre ticket"
#: tickets/templates/tickets/aff_ticket.html:59
msgid "Title:"
msgstr "Titre :"
#: tickets/templates/tickets/aff_ticket.html:61
msgid "Add a comment "
msgstr "Ajouter un commentaire"
#: tickets/templates/tickets/aff_ticket.html:60
msgid "Description:"
msgstr "Description :"
#: tickets/templates/tickets/aff_ticket.html:64
#: tickets/templates/tickets/preferences.html:14 tickets/views.py:153
msgid "Edit"
msgstr "Modifier"
#: tickets/templates/tickets/aff_ticket.html:68
#: tickets/templates/tickets/aff_ticket.html:66
msgid "Mark as solved"
msgstr "Marquer comme résolu"
#: tickets/templates/tickets/aff_ticket.html:71
msgid "Mark as not solved"
#: tickets/templates/tickets/aff_ticket.html:68
msgid "Mark as unsolved"
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"
msgstr "Tous les tickets"
#: tickets/templates/tickets/aff_tickets.html:35
#: tickets/templates/tickets/form_preferences.html:30
#: tickets/templates/tickets/form_ticket.html:31
#: tickets/templates/tickets/edit.html:31
msgid "Ticket"
msgid_plural "Tickets"
msgstr[0] "Ticket"
@ -201,28 +246,26 @@ msgstr ""
msgid "Open a ticket"
msgstr "Ouvrir un ticket"
#: tickets/templates/tickets/form_preferences.html:33
msgid "Editing of tickets preferences"
msgstr "Modification des préférences de tickets"
#: tickets/templates/tickets/delete.html:29
msgid "Deletion of tickets"
msgstr "Suppression de tickets"
#: tickets/templates/tickets/form_preferences.html:46
#: tickets/templates/tickets/preferences.html:14
msgid "Edit"
msgstr "Modifier"
#: tickets/templates/tickets/delete.html:35
#, python-format
msgid ""
"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"
msgstr "Ouverture de ticket"
#: tickets/templates/tickets/form_ticket.html:39 tickets/views.py:90
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
#: tickets/templates/tickets/help_text.html:3
msgid ""
"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:"
@ -231,11 +274,11 @@ msgstr ""
"possible pour nous aider à chercher une solution. Voici quelques "
"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.)."
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 ""
"The conditions in which you encounter the problem (Wi-Fi/wired connection, "
"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 "
"etc.)."
#: tickets/templates/tickets/form_ticket.html:53
#: tickets/templates/tickets/help_text.html:12
msgid ""
"The locations where you encounter the problem (in your room, in a common "
"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 "
"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
msgid "List of tickets"
msgstr "Liste des tickets"
@ -272,29 +311,78 @@ msgstr "Adresse mail de publication"
msgid "No email address, the tickets will not be published."
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
msgid "No tickets"
msgstr "Pas de tickets"
#: tickets/views.py:71 tickets/views.py:82
#: tickets/views.py:62
msgid ""
"Your ticket has been succesfully opened. We will take care of it as soon as "
"possible."
msgstr ""
"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"
msgstr "Jamais"
#: tickets/views.py:154
msgid "The tickets preferences were edited."
msgstr "Les préférences de tickets ont été modifiées."
#~ msgid "Description of the ticket."
#~ msgstr "Description du ticket."
#: tickets/views.py:157
msgid "Invalid form."
msgstr "Formulaire invalide."
#~ msgid "Mail language"
#~ msgstr "Langue du mail"
#~ 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.utils.translation import ugettext_lazy as _
from django.template import loader
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.functional import cached_property
from reversion.models import Version
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
import users.models
from .preferences.models import Preferences
from .preferences.models import TicketOption
class Ticket(AclMixin, models.Model):
@ -29,7 +59,6 @@ class Ticket(AclMixin, models.Model):
)
description = models.TextField(
max_length=3000,
help_text=_("Description of the ticket."),
blank=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
)
solved = models.BooleanField(default=False)
language = models.CharField(
max_length=16, help_text=_("Language of the ticket."), default="en"
)
request = None
class Meta:
permissions = (("view_tickets", _("Can view a ticket object")),)
permissions = (("view_ticket", _("Can view a ticket object")),)
verbose_name = _("ticket")
verbose_name_plural = _("tickets")
@ -51,39 +83,52 @@ class Ticket(AclMixin, models.Model):
else:
return _("Anonymous ticket. Date: %s.") % (self.date)
def publish_mail(self, request=None):
site_url = GeneralOption.objects.first().main_site_url
to_addr = Preferences.objects.first().publish_address
@cached_property
def opened_by(self):
"""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}
lang = Preferences.objects.first().mail_language
if lang == 0:
if self.language == "fr":
obj = "Nouveau ticket ouvert"
template = loader.get_template("tickets/publication_mail_fr")
else:
obj = "New ticket opened"
template = loader.get_template("tickets/publication_mail_en")
send_mail(
request,
mail_to_send = EmailMessage(
obj,
template.render(context),
GeneralOption.get_cached_value("email_from"),
[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):
""" Check that the user has the right to view the ticket
or that it is the author"""
if (
not user_request.has_perm("tickets.view_tickets")
not user_request.has_perm("tickets.view_ticket")
and self.user != user_request
):
return (
False,
_("You don't have the right to view other tickets than yours."),
("tickets.view_tickets",),
("tickets.view_ticket",),
)
else:
return True, None, None
@ -91,13 +136,13 @@ class Ticket(AclMixin, models.Model):
@staticmethod
def can_view_all(user_request, *_args, **_kwargs):
""" 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 (
can,
_("You don't have the right to view the list of tickets.")
if not can
else None,
("tickets.view_tickets",),
("tickets.view_ticket",),
)
def can_create(user_request, *_args, **_kwargs):
@ -105,10 +150,112 @@ class Ticket(AclMixin, models.Model):
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)
def ticket_post_save(**kwargs):
""" Send the mail to publish the new ticket """
if kwargs["created"]:
if Preferences.objects.first().publish_address:
if TicketOption.get_cached_value("publish_address"):
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.forms import ModelForm, Form
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"""
class Meta:
model = Preferences
model = TicketOption
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.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"""
publish_address = models.EmailField(
@ -12,10 +41,7 @@ class Preferences(models.Model):
max_length=1000,
null=True,
)
LANG_FR = 0
LANG_EN = 1
LANGUES = ((0, _("French")), (1, _("English")))
mail_language = models.IntegerField(choices=LANGUES, default=LANG_FR)
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 i18n %}
{% load humanize %}
{% load logs_extra %}
{% load acl %}
{% 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 %}
{% trans "Response address: " %}<A HREF="mailto:{{ticket.email}}?subject={% trans "Response to your ticket"%}">{{ticket.email}}</A>
{% 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 class="panel-body">
<p><b>{% trans "Title:" %}</b> {{ticket.title}}</p>
<p><b>{% trans "Description:" %}</b> {{ ticket.description }}</p>
<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>
<b>{% trans "Description:" %}</b> {{ ticket.description | linebreaks }}
</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">
<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>
{% 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 %}
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
@ -25,25 +25,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% endcomment %}
{% load bootstrap3 %}
{% load massive_bootstrap_form %}
{% load i18n %}
{% block title %}{% trans "Ticket" %}{% endblock %}
{% block content %}
<h2> {% trans "Editing of tickets preferences" %}</h2>
<h2>{% trans "Ticket opening" %}</h2>
{% for message in messages %}
<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 %}
{% bootstrap_form_errors ticketform %}
<form class="form" method="post">
{% csrf_token %}
{% bootstrap_field preferencesform.publish_address %}
{% bootstrap_field preferencesform.mail_language %}
{% trans "Edit" as tr_edit %}
{% bootstrap_button tr_edit button_type="submit" icon='ok' button_class='btn-success' %}
{% bootstrap_form ticketform %}
{% bootstrap_button action_name button_type="submit" icon='ok' button_class='btn-success' %}
</form>
{% 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">
<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>
{% trans "Edit" %}
</a>
@ -25,12 +25,8 @@
<td><p>{% trans "No email address, the tickets will not be published." %}</p></td>
{% endif %}
</tr>
<tr>
<th><p>{% trans "Email language" %}</p></th>
<td><p>{{ language }}</p></th>
</tr>
<table class="table">
</table>
</div>
</div>
</div>
</div>

View file

@ -1,12 +1,12 @@
{% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket.
Profile: {{site_url}}{% url 'users:profil' ticket.user.id%}
Answer to the address: {{ticket.user.get_mail}}.
{% else %}
An anonymous user (not authenticated) opened a ticket
Answer to the address:{{ticket.email}}.
{% 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.
Profil : {{site_url}}{% url 'users:profil' ticket.user.id%}
Répondre à l'adresse : {{ticket.user.get_mail}}.
{% else %}
Un utilisateur anonyme (non connecté) a ouvert un ticket.
Répondre à l'adresse : {{ticket.email}}.
{% 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 . import views
from .preferences.views import edit_options
urlpatterns = [
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(
r"^ticket/edit-preferences-tickets$",
views.edit_preferences,
name="edit-preferences-tickets",
r"^edit_options/(?P<section>TicketOption)$",
edit_options,
name="edit-options",
),
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
# quelques clics.
#
# Copyright © 2017 Gabriel Détraz
# Copyright © 2017 Lara Kermarec
# Copyright © 2017 Augustin Lemesle
# 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
@ -37,80 +36,137 @@ from re2o.views import form
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 .models import Ticket
from .models import Ticket, CommentTicket
from .preferences.models import Preferences
from .forms import NewTicketForm, ChangeStatusTicketForm
from .preferences.forms import EditPreferencesForm
from .forms import NewTicketForm, EditTicketForm, CommentTicketForm
def new_ticket(request):
""" Ticket creation view"""
ticketform = NewTicketForm(request.POST or None)
if request.method == "POST":
ticketform = NewTicketForm(request.POST)
if ticketform.is_valid():
email = ticketform.cleaned_data.get("email")
ticket = ticketform.save(commit=False)
ticket.request = request
if request.user.is_authenticated:
ticket.user = request.user
ticket.save()
messages.success(
request,
_(
"Your ticket has been succesfully opened. We will take care of it as soon as possible."
),
)
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)
ticketform = NewTicketForm(request.POST or None, request=request)
if ticketform.is_valid():
ticketform.save()
messages.success(
request,
_(
"Your ticket has been succesfully opened. We will take care of it as soon as possible."
),
)
if not request.user.is_authenticated:
return redirect(reverse("index"))
else:
return redirect(
reverse("users:profil", kwargs={"userid": str(request.user.id)})
)
return form(
{"ticketform": ticketform, 'action_name': ("Create a ticket")}, "tickets/edit.html", request
)
@login_required
@can_view(Ticket)
def aff_ticket(request, ticket, ticketid):
"""View to display only one ticket"""
changestatusform = ChangeStatusTicketForm(request.POST)
if request.method == "POST":
ticket.solved = not ticket.solved
ticket.save()
comments = CommentTicket.objects.filter(parent_ticket=ticket)
return render(
request,
"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)
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
def profil(request, user):
""" 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):
"""View to display a contact address on the contact page
used here to display a link to open a ticket"""