mirror of https://gitlab.federez.net/re2o/re2o
35 changed files with 904 additions and 4 deletions
@ -0,0 +1,4 @@ |
|||||
|
from django.contrib import admin |
||||
|
from .models import Ticket |
||||
|
admin.site.register(Ticket) |
||||
|
# Register your models here. |
||||
@ -0,0 +1,5 @@ |
|||||
|
from django.apps import AppConfig |
||||
|
|
||||
|
|
||||
|
class TicketsConfig(AppConfig): |
||||
|
name = 'tickets' |
||||
@ -0,0 +1,24 @@ |
|||||
|
from django import forms |
||||
|
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, |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class NewTicketForm(ModelForm): |
||||
|
""" Creation of a ticket""" |
||||
|
email = forms.EmailField(required=False) |
||||
|
class Meta: |
||||
|
model = Ticket |
||||
|
fields = ['title', 'description', 'email'] |
||||
|
|
||||
|
class ChangeStatusTicketForm(ModelForm): |
||||
|
""" Change ticket status""" |
||||
|
class Meta: |
||||
|
model = Ticket |
||||
|
fields = [] |
||||
|
|
||||
@ -0,0 +1,48 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.10.7 on 2019-08-19 08:19 |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.conf import settings |
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
import re2o.mixins |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
initial = True |
||||
|
|
||||
|
dependencies = [ |
||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name='Preferences', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('publish_address', models.EmailField(help_text='Email address to publish the new tickets (leave empty for no publications)', max_length=1000, null=True)), |
||||
|
('mail_language', models.IntegerField(choices=[(0, 'Français'), (1, 'English')], default=0)), |
||||
|
], |
||||
|
options={ |
||||
|
'verbose_name': "Ticket's settings", |
||||
|
}, |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name='Ticket', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('title', models.CharField(help_text='Title of the ticket', max_length=255)), |
||||
|
('description', models.TextField(help_text='Description of the ticket', max_length=3000)), |
||||
|
('date', models.DateTimeField(auto_now_add=True)), |
||||
|
('email', models.EmailField(help_text='An email address to get back to you', max_length=100, null=True)), |
||||
|
('solved', models.BooleanField(default=False)), |
||||
|
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tickets', to=settings.AUTH_USER_MODEL)), |
||||
|
], |
||||
|
options={ |
||||
|
'verbose_name': 'Ticket', |
||||
|
'verbose_name_plural': 'Tickets', |
||||
|
}, |
||||
|
bases=(re2o.mixins.AclMixin, models.Model), |
||||
|
), |
||||
|
] |
||||
@ -0,0 +1,97 @@ |
|||||
|
from django.db import models |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
from django.core.mail import send_mail |
||||
|
from django.template import Context, loader |
||||
|
from django.db.models.signals import post_save |
||||
|
from django.dispatch import receiver |
||||
|
|
||||
|
from re2o.mixins import AclMixin |
||||
|
|
||||
|
from preferences.models import GeneralOption |
||||
|
|
||||
|
import users.models |
||||
|
|
||||
|
from .preferences.models import Preferences |
||||
|
|
||||
|
class Ticket(AclMixin, models.Model): |
||||
|
"""Model of a ticket""" |
||||
|
|
||||
|
user = models.ForeignKey( |
||||
|
'users.User', |
||||
|
on_delete=models.CASCADE, |
||||
|
related_name="tickets", |
||||
|
blank=True, |
||||
|
null=True) |
||||
|
title = models.CharField( |
||||
|
max_length=255, |
||||
|
help_text=_("Title of the ticket"), |
||||
|
blank=False, |
||||
|
null=False,) |
||||
|
description = models.TextField( |
||||
|
max_length=3000, |
||||
|
help_text=_("Description of the ticket"), |
||||
|
blank=False, |
||||
|
null=False) |
||||
|
date = models.DateTimeField(auto_now_add=True) |
||||
|
email = models.EmailField( |
||||
|
help_text = _("An email address to get back to you"), |
||||
|
max_length=100, |
||||
|
null=True) |
||||
|
solved = models.BooleanField(default=False) |
||||
|
|
||||
|
class Meta: |
||||
|
verbose_name = _("Ticket") |
||||
|
verbose_name_plural = _("Tickets") |
||||
|
|
||||
|
def __str__(self): |
||||
|
if self.user: |
||||
|
return "Ticket from {}. Date: {}".format(self.user.surname,self.date) |
||||
|
else: |
||||
|
return "Anonymous Ticket. Date: {}".format(self.date) |
||||
|
|
||||
|
def publish_mail(self): |
||||
|
site_url = GeneralOption.objects.first().main_site_url |
||||
|
to_addr = Preferences.objects.first().publish_address |
||||
|
context = Context({'ticket':self,'site_url':site_url}) |
||||
|
|
||||
|
lang = Preferences.objects.first().mail_language |
||||
|
if(lang == 0): |
||||
|
obj = 'Nouvelle ouverture de ticket' |
||||
|
template = loader.get_template('tickets/publication_mail_fr') |
||||
|
else: |
||||
|
obj = 'New ticket opened' |
||||
|
template = loader.get_template('tickets/publication_mail_en') |
||||
|
send_mail( |
||||
|
obj, |
||||
|
template.render(context), |
||||
|
GeneralOption.get_cached_value('email_from'), |
||||
|
[to_addr], |
||||
|
fail_silently = False) |
||||
|
|
||||
|
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_ticket') and self.user != user_request): |
||||
|
return False, _("You don't have the right to view other tickets than yours.") |
||||
|
else: |
||||
|
return True, None |
||||
|
|
||||
|
@staticmethod |
||||
|
def can_view_all(user_request, *_args, **_kwargs): |
||||
|
""" Check that the user has access to the list of all tickets""" |
||||
|
return( |
||||
|
user_request.has_perm('tickets.view_tickets'), |
||||
|
_("You don't have the right to view the list of tickets.") |
||||
|
) |
||||
|
|
||||
|
def can_create(user_request,*_args, **_kwargs): |
||||
|
""" Authorise all users to open tickets """ |
||||
|
return True,None |
||||
|
|
||||
|
@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: |
||||
|
ticket = kwargs['instance'] |
||||
|
ticket.publish_mail() |
||||
@ -0,0 +1,11 @@ |
|||||
|
from django import forms |
||||
|
from django.forms import ModelForm, Form |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
from .models import Preferences |
||||
|
|
||||
|
class EditPreferencesForm(ModelForm): |
||||
|
""" Edit the ticket's settings""" |
||||
|
class Meta: |
||||
|
model = Preferences |
||||
|
fields = '__all__' |
||||
@ -0,0 +1,19 @@ |
|||||
|
from django.db import models |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
class Preferences(models.Model): |
||||
|
""" Definition of the ticket's settings""" |
||||
|
|
||||
|
publish_address = models.EmailField( |
||||
|
help_text = _("Email address to publish the new tickets (leave empty for no publications)"), |
||||
|
max_length = 1000, |
||||
|
null = True) |
||||
|
LANG_FR = 0 |
||||
|
LANG_EN = 1 |
||||
|
LANGUES = ( |
||||
|
(0,_("Français")), |
||||
|
(1,_("English")), |
||||
|
) |
||||
|
mail_language = models.IntegerField(choices=LANGUES,default = LANG_FR) |
||||
|
class Meta: |
||||
|
verbose_name = _("Ticket's settings") |
||||
@ -0,0 +1,82 @@ |
|||||
|
{% 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 Goulven Kermarec |
||||
|
Copyright © 2017 Augustin Lemesle |
||||
|
|
||||
|
This program is free software; you can redistribute it and/or modify |
||||
|
it under the terms of the GNU General Public License as published by |
||||
|
the Free Software Foundation; either version 2 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
This program is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License along |
||||
|
with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
{% endcomment %} |
||||
|
|
||||
|
{% load bootstrap3 %} |
||||
|
{% load i18n %} |
||||
|
{% load humanize %} |
||||
|
|
||||
|
{% block title %}{% trans "Tickets" %}{% endblock %} |
||||
|
|
||||
|
{% block content %} |
||||
|
|
||||
|
<h2> Ticket #{{ticket.id}} |
||||
|
{% if ticket.solved %} |
||||
|
<span class="badge badge-success">{% trans "Solved" %}</span> |
||||
|
{% else %} |
||||
|
<span class="badge badge-danger">{% trans "Not Solved" %}</span> |
||||
|
{% endif %} |
||||
|
</h2> |
||||
|
|
||||
|
<div class="panel panel-default"> |
||||
|
<div class="panel-heading"> |
||||
|
{% trans "Opened by" %} |
||||
|
{% if ticket.user %} |
||||
|
<a href="{% url 'users:profil' ticket.user.id%}"> |
||||
|
{{ ticket.user.get_full_name }} |
||||
|
</a> |
||||
|
{% else %} |
||||
|
{% trans "Anonymous User" %} |
||||
|
{% endif %} |
||||
|
{{ ticket.date | naturalday}}. |
||||
|
{% if not ticket.user %} |
||||
|
{% trans "Response address: " %}<A HREF="mailto:{{ticket.email}}?subject={% trans "Response to your ticket"%}">{{ticket.email}}</A> |
||||
|
{% endif %} |
||||
|
</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 %} |
||||
|
{% bootstrap_button "Mark as Solved" button_type="submit" button_class='btn-info' %} |
||||
|
{% else %} |
||||
|
{% bootstrap_button "Mark as not Solved" button_type="submit" button_class='btn-warning' %} |
||||
|
{% endif %} |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
<div class="text-right"> |
||||
|
<a type="button" href="{% url 'tickets:aff-tickets' %}" class="btn btn-primary"><p>{% trans "Tous les tickets" %}</p></a> |
||||
|
</div> |
||||
|
|
||||
|
{% endblock %} |
||||
@ -0,0 +1,89 @@ |
|||||
|
{% 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 Goulven Kermarec |
||||
|
Copyright © 2017 Augustin Lemesle |
||||
|
|
||||
|
This program is free software; you can redistribute it and/or modify |
||||
|
it under the terms of the GNU General Public License as published by |
||||
|
the Free Software Foundation; either version 2 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
This program is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License along |
||||
|
with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
{% endcomment %} |
||||
|
|
||||
|
{% load bootstrap3 %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block content %} |
||||
|
|
||||
|
|
||||
|
<div class="container-fluid"> |
||||
|
<hr class="col-sm-12"> |
||||
|
<div class="row justify-content-start"> |
||||
|
<div class="col-sm-4"> |
||||
|
<span class="badge badge-light">{{ nbr_tickets }}</span> {% trans "Tickets" %} |
||||
|
</div> |
||||
|
<div class="col-sm-4"> |
||||
|
<span class="badge badge-light"> {{ nbr_tickets_unsolved }}</span>{% trans "Not Solved Tickets" %} |
||||
|
</div> |
||||
|
<div class="col-sm-4"> |
||||
|
<span>{% trans "Last Ticket:" %} {{ last_ticket_date }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<hr class="col-sm-12"> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
|
||||
|
<div class="table-responsiv"> |
||||
|
|
||||
|
<table class="table"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th scope="col"></th> |
||||
|
<th scope="col">User</th> |
||||
|
<th scope="col">Titre</th> |
||||
|
<th scope="col">Date</th> |
||||
|
<th scope="col">Résolu</th> |
||||
|
</tr> |
||||
|
{% for ticket in tickets_list %} |
||||
|
<tr> |
||||
|
<td> |
||||
|
<a href="{% url 'tickets:aff-ticket' ticket.id%}" class="btn btn-primary btn-sm" role="button"> |
||||
|
<i class="fa fa-ticket"></i> |
||||
|
</a> |
||||
|
</td> |
||||
|
{% if ticket.user %} |
||||
|
<td><a href="{% url 'users:profil' ticket.user.id%}" role="button">{{ ticket.user.get_short_name }}</a></td> |
||||
|
{% else %} |
||||
|
<td> Anonyme </td> |
||||
|
{% endif %} |
||||
|
<td>{{ ticket.title }}</td> |
||||
|
<td>{{ ticket.date }}</td> |
||||
|
{% if ticket.solved %} |
||||
|
<td><i class="fa fa-check" style="color:green"></i></td> |
||||
|
{% else %} |
||||
|
<td><i class="fa fa-times" style="color:red"></i></td> |
||||
|
{% endif %} |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
|
||||
|
</thead> |
||||
|
</table> |
||||
|
|
||||
|
{% if tickets_list.paginator %} |
||||
|
{% include 'pagination.html' with list=tickets_list go_to_id="tickets" %} |
||||
|
{% endif %} |
||||
|
</div> |
||||
|
{% endblock %} |
||||
@ -0,0 +1,13 @@ |
|||||
|
{% load i18n %} |
||||
|
|
||||
|
<div class="panel panel-info"> |
||||
|
<div class="panel-heading"><h4>Tickets</h4></div> |
||||
|
<div class="panel-body"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-9"> |
||||
|
{% blocktrans %}If you are experiencing issues with the services offered by {{asso_name}}, you can open a ticket that will be taken care of. If you want to contact us on any other topic, please choose one address below.{% endblocktrans %} |
||||
|
</div> |
||||
|
<div class="col-sm-3"><a class="btn btn-primary" href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %}</a></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,48 @@ |
|||||
|
{% extends 'machines/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 Goulven 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 i18n %} |
||||
|
|
||||
|
{% block title %}{% trans "Ticket" %}{% endblock %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<h2> {% trans "Tickets settings modification" %}</h2> |
||||
|
|
||||
|
{% for message in messages %} |
||||
|
<div class="{{ message| bootstrap_message_classes }} alert-dismissable"> |
||||
|
<button type="button" class="close" data_dismiss="alert" aria-hidden="true">}</button> |
||||
|
{{ message | safe }} |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
<form class="form" method="post"> |
||||
|
{% csrf_token %} |
||||
|
{% bootstrap_field preferencesform.publish_address %} |
||||
|
{% bootstrap_field preferencesform.mail_language %} |
||||
|
{% bootstrap_button "Editer" button_type="submit" icon='ok' button_class='btn-success' %} |
||||
|
</form> |
||||
|
{% endblock %} |
||||
@ -0,0 +1,58 @@ |
|||||
|
{% extends 'machines/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 Goulven 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> Ouverture d'un Ticket </h2> |
||||
|
|
||||
|
<form class="form" method="post"> |
||||
|
{% csrf_token %} |
||||
|
{% if not user.is_authenticated %} |
||||
|
<p>{% trans "Vous n'êtes pas authentifié. Veuillez fournir une adresse mail afin que nous puissions vous recontacter." %}</p> |
||||
|
{% bootstrap_field ticketform.email %} |
||||
|
{% endif %} |
||||
|
{% bootstrap_field ticketform.title %} |
||||
|
<br> |
||||
|
<p>{% trans "Description de votre problème. Veuillez fournir le plus d'informations possible afin de faciliter la recherche de solution. Voici quelques informations dont nous pourions avoir besoin:" %}</p> |
||||
|
<ul class="list"> |
||||
|
<li> |
||||
|
<p> {% trans "Le type de votre problème (adhesion, connexion, paiement ou autre)." %}</p> |
||||
|
</li> |
||||
|
<li> |
||||
|
<p> {% trans "Les conditions dans lesquelles vous rencontrez le problème (Wifi/filaire, sur tout les apareils ou sur un seul. Est-ce une nouvelle machine ?" %}</p> |
||||
|
</li> |
||||
|
<li> |
||||
|
<p> {% trans "Les endroits dans lequels le problème survient (chez vous, dans une partie commune, dans un batiment en particulier)." %}</p> |
||||
|
</ul> |
||||
|
{% bootstrap_field ticketform.description %} |
||||
|
{% bootstrap_button "Ouvrir le Ticket" button_type="submit" icon='ok' button_class='btn-success' %} |
||||
|
</form> |
||||
|
{% endblock %} |
||||
@ -0,0 +1,34 @@ |
|||||
|
{% 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 Goulven Kermarec |
||||
|
Copyright © 2017 Augustin Lemesle |
||||
|
|
||||
|
This program is free software; you can redistribute it and/or modify |
||||
|
it under the terms of the GNU General Public License as published by |
||||
|
the Free Software Foundation; either version 2 of the License, or |
||||
|
(at your option) any later version. |
||||
|
|
||||
|
This program is distributed in the hope that it will be useful, |
||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
GNU General Public License for more details. |
||||
|
|
||||
|
You should have received a copy of the GNU General Public License along |
||||
|
with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
{% endcomment %} |
||||
|
|
||||
|
{% load bootstrap3 %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block title%}{% trans "Tickets" %}{% endblock %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<h2>{% trans "Tickets" %}</h2> |
||||
|
{% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} |
||||
|
{% endblock %} |
||||
@ -0,0 +1,2 @@ |
|||||
|
{% load i18n %} |
||||
|
<li><a href="{% url 'tickets:aff-tickets' %}"><i class="fa fa-ticket"></i>{% trans "Tickets" %}</a></li> |
||||
@ -0,0 +1,6 @@ |
|||||
|
{% load i18n %} |
||||
|
<li> |
||||
|
<a href="{% url 'tickets:new-ticket' %}"> |
||||
|
<i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %} |
||||
|
</a> |
||||
|
</li> |
||||
@ -0,0 +1,36 @@ |
|||||
|
{% load i18n %} |
||||
|
|
||||
|
<div class="panel panel-default" id="tickets"> |
||||
|
<div class="panel-heading" data-toggle="collapse" href="#collapse_tickets"> |
||||
|
<h4 class="panel-title"> |
||||
|
<a><i class="fa fa-ticket"></i> {% trans "Tickets" %}</a> |
||||
|
</h4> |
||||
|
</div> |
||||
|
|
||||
|
<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' %}"> |
||||
|
<i class="fa fa-edit"></i> |
||||
|
{% trans "Edit" %} |
||||
|
</a> |
||||
|
<p></p> |
||||
|
|
||||
|
<div class="table-responsive"> |
||||
|
<table class="table"> |
||||
|
<tr> |
||||
|
<th><p>{% trans "Publication email address"%}</p></th> |
||||
|
{% if preferences.publish_address %} |
||||
|
<td><p>{{ preferences.publish_address }}</p></td> |
||||
|
{% else %} |
||||
|
<td><p>{% trans "Pas d'adresse, les tickets ne sont pas annoncés" %}</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> |
||||
@ -0,0 +1,23 @@ |
|||||
|
{% load i18n %} |
||||
|
|
||||
|
<div class="panel panel-default"> |
||||
|
<div class="panel-heading clearfix profil" data-parent="#accordion" data-toggle="collapse" data-target="#ticket"> |
||||
|
<h3 class="panel-title pull-left"> |
||||
|
<i class="fa fa-ticket"></i>{% trans " Tickets" %} |
||||
|
</h3> |
||||
|
</div> |
||||
|
<div id="ticket" class="panel-collapse collapse"> |
||||
|
<div class="panel-body"> |
||||
|
<a class="btn btn-primary btn-sm" role="button" href="{% url 'tickets:new-ticket' %}"> |
||||
|
<i class="fa fa-ticket"></i>{% trans " Open a Ticket" %} |
||||
|
</a> |
||||
|
</div> |
||||
|
<div class="panel-body"> |
||||
|
{% if tickets_list %} |
||||
|
{% include 'tickets/aff_tickets.html' with tickets_list=tickets_list %} |
||||
|
{% else %} |
||||
|
<p>{% trans "No tickets" %}</p> |
||||
|
{% endif %} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,12 @@ |
|||||
|
{% if ticket.user %} {{ ticket.user.get_full_name }} opened a ticket. |
||||
|
Profil: {{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 %} |
||||
|
|
||||
|
Title: {{ticket.title}} |
||||
|
|
||||
|
Description: {{ticket.description}} |
||||
@ -0,0 +1,12 @@ |
|||||
|
{% if ticket.user %} {{ ticket.user.get_full_name }} à ouvert un ticket. |
||||
|
Profile: {{site_url}}{% url 'users:profil' ticket.user.id%} |
||||
|
Répondre à l'adresse: {{ticket.user.get_mail}}. |
||||
|
|
||||
|
{% else %} |
||||
|
Un utilisateur anonyme (non connecté) à ouvert un ticket. |
||||
|
Répondre à l'adresse: {{ticket.email}}. |
||||
|
{% endif %} |
||||
|
|
||||
|
Titre: {{ticket.title}} |
||||
|
|
||||
|
Description: {{ticket.description}} |
||||
@ -0,0 +1,3 @@ |
|||||
|
from django.test import TestCase |
||||
|
|
||||
|
# Create your tests here. |
||||
@ -0,0 +1,10 @@ |
|||||
|
from django.conf.urls import url |
||||
|
|
||||
|
from . import views |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
url(r'^$', views.aff_tickets, name='aff-tickets'), |
||||
|
url(r'^ticket/(?P<ticketid>[0-9]+)$', views.aff_ticket, name='aff-ticket'), |
||||
|
url(r'^ticket/edit-preferences-tickets$', views.edit_preferences, name='edit-preferences-tickets'), |
||||
|
url(r'^new_ticket/$',views.new_ticket,name='new-ticket'), |
||||
|
] |
||||
@ -0,0 +1,197 @@ |
|||||
|
# -*- mode: python; coding: utf-8 -*- |
||||
|
# Re2o est un logiciel d'administration développé initiallement au rezometz. Il |
||||
|
# se veut agnostique au réseau considéré, de manière à être installable en |
||||
|
# quelques clics. |
||||
|
# |
||||
|
# Copyright © 2017 Gabriel Détraz |
||||
|
# Copyright © 2017 Goulven Kermarec |
||||
|
# Copyright © 2017 Augustin Lemesle |
||||
|
# |
||||
|
# This program is free software; you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU General Public License as published by |
||||
|
# the Free Software Foundation; either version 2 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program; if not, write to the Free Software Foundation, Inc., |
||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||||
|
|
||||
|
# App de gestion des users pour re2o |
||||
|
# Goulven 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.views.decorators.cache import cache_page |
||||
|
from django.utils.translation import ugettext as _ |
||||
|
from django.urls import reverse |
||||
|
from django.forms import modelformset_factory |
||||
|
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 preferences.models import GeneralOption |
||||
|
|
||||
|
from .models import( |
||||
|
Ticket, |
||||
|
) |
||||
|
|
||||
|
from .preferences.models import( |
||||
|
Preferences, |
||||
|
) |
||||
|
|
||||
|
from .forms import ( |
||||
|
NewTicketForm, |
||||
|
ChangeStatusTicketForm, |
||||
|
) |
||||
|
|
||||
|
from .preferences.forms import ( |
||||
|
EditPreferencesForm, |
||||
|
) |
||||
|
|
||||
|
|
||||
|
|
||||
|
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) |
||||
|
if request.user.is_authenticated: |
||||
|
ticket.user = request.user |
||||
|
ticket.save() |
||||
|
messages.success(request,_('Your ticket has been succesfully open. 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 open. We will take care of it as soon as possible.')) |
||||
|
return redirect(reverse('index')) |
||||
|
else: |
||||
|
messages.error(request,_("You are not authenticated. Please login 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 |
||||
|
@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() |
||||
|
return render(request,'tickets/aff_ticket.html',{'ticket':ticket,'changestatusform':changestatusform}) |
||||
|
|
||||
|
@login_required |
||||
|
@can_view_all(Ticket) |
||||
|
def aff_tickets(request): |
||||
|
""" View to display all the tickets """ |
||||
|
tickets_list = Ticket.objects.all().order_by('-date') |
||||
|
nbr_tickets = tickets_list.count() |
||||
|
nbr_tickets_unsolved = tickets_list.filter(solved=False).count() |
||||
|
if nbr_tickets: |
||||
|
last_ticket_date = tickets_list.first().date |
||||
|
else: |
||||
|
last_ticket_date = _("Never") |
||||
|
|
||||
|
pagination_number = (GeneralOption |
||||
|
.get_cached_value('pagination_number')) |
||||
|
|
||||
|
tickets = re2o_paginator( |
||||
|
request, |
||||
|
tickets_list, |
||||
|
pagination_number, |
||||
|
) |
||||
|
|
||||
|
context = {'tickets_list':tickets, |
||||
|
'last_ticket_date':last_ticket_date, |
||||
|
'nbr_tickets':nbr_tickets, |
||||
|
'nbr_tickets_unsolved':nbr_tickets_unsolved} |
||||
|
|
||||
|
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,'Préférences des Tickets mises à jour') |
||||
|
return redirect(reverse('preferences:display-options',)) |
||||
|
else: |
||||
|
messages.error(request,'Formulaire Invalide') |
||||
|
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""" |
||||
|
tickets_list = Ticket.objects.filter(user=user).all().order_by('-date') |
||||
|
nbr_tickets = tickets_list.count() |
||||
|
nbr_tickets_unsolved = tickets_list.filter(solved=False).count() |
||||
|
if nbr_tickets: |
||||
|
last_ticket_date = tickets_list.first().date |
||||
|
else: |
||||
|
last_ticket_date = _("Never") |
||||
|
|
||||
|
pagination_number = (GeneralOption |
||||
|
.get_cached_value('pagination_large_number')) |
||||
|
|
||||
|
tickets = re2o_paginator( |
||||
|
request, |
||||
|
tickets_list, |
||||
|
pagination_number, |
||||
|
) |
||||
|
|
||||
|
context = {'tickets_list':tickets, |
||||
|
'last_ticket_date':last_ticket_date, |
||||
|
'nbr_tickets':nbr_tickets, |
||||
|
'nbr_tickets_unsolved':nbr_tickets_unsolved} |
||||
|
return render_to_string('tickets/profil.html', context=context, request=request, using=None) |
||||
|
|
||||
|
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""" |
||||
|
return render_to_string('tickets/contact.html') |
||||
|
|
||||
|
def navbar_user(request): |
||||
|
"""View to display the ticket link in thet user's dropdown in the navbar""" |
||||
|
return render_to_string('tickets/navbar.html') |
||||
|
|
||||
|
def navbar_logout(request): |
||||
|
"""View to display the ticket link to log out users""" |
||||
|
return render_to_string('tickets/navbar_logout.html') |
||||
Loading…
Reference in new issue