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

Add comment to tikets + send_notif mails

This commit is contained in:
Gabriel Detraz 2020-04-23 02:42:18 +02:00
parent d68a0bd627
commit 2f018cf11b
15 changed files with 524 additions and 76 deletions

View file

@ -25,13 +25,15 @@ Ticket preferences model
from django.contrib import admin
from .models import Ticket
from .models import Ticket, CommentTicket
from reversion.admin import VersionAdmin
class TicketAdmin(VersionAdmin):
"""Gestion des ticket"""
pass
class CommentTicketAdmin(VersionAdmin):
pass
admin.site.register(Ticket, TicketAdmin)
admin.site.register(CommentTicket, CommentTicketAdmin)

View file

@ -31,7 +31,7 @@ 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(FormRevMixin, ModelForm):
@ -48,7 +48,7 @@ class NewTicketForm(FormRevMixin, ModelForm):
self.fields.pop('email')
self.instance.user = request.user
self.fields['description'].help_text = render_to_string('tickets/help_text.html')
self.instance.request = request
self.instance.language = getattr(request, "LANGUAGE_CODE", "en")
class EditTicketForm(FormRevMixin, ModelForm):
@ -62,3 +62,16 @@ class EditTicketForm(FormRevMixin, ModelForm):
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):
prefix = kwargs.pop("prefix", self.Meta.model.__name__)
super(CommentTicketForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields["comment"].label = _("comment")

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 22:06+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,44 +30,68 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: tickets/models.py:54
#: tickets/forms.py:76
msgid "comment"
msgstr "commentaire"
#: tickets/models.py:57
msgid "Title of the ticket."
msgstr "Titre du ticket."
#: tickets/models.py:63
#: tickets/models.py:66
msgid "An email address to get back to you."
msgstr "Une adresse mail pour vous recontacter."
#: tickets/models.py:69
#: 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:70
#: tickets/models.py:75 tickets/models.py:171
msgid "ticket"
msgstr "ticket"
#: tickets/models.py:71
#: tickets/models.py:76 tickets/models.py:172
msgid "tickets"
msgstr "tickets"
#: tickets/models.py:75
#: 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:77
#: tickets/models.py:82
#, python-format
msgid "Anonymous ticket. Date: %s."
msgstr "Ticket anonyme. Date : %s."
#: tickets/models.py:111
#: 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:123
#: 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/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"
@ -87,7 +111,7 @@ msgstr "Options des tickets"
msgid "Can view tickets options"
msgstr "Peut voir les options des tickets"
#: tickets/templates/tickets/aff_ticket.html:31
#: 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
@ -95,57 +119,79 @@ msgstr "Peut voir les options des tickets"
msgid "Tickets"
msgstr "Tickets"
#: tickets/templates/tickets/aff_ticket.html:35
#: tickets/templates/tickets/aff_ticket.html:36
#, python-format
msgid "Ticket #%(id)s"
msgstr "Ticket #%(id)s"
#: tickets/templates/tickets/aff_ticket.html:37
#: 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:39
#: tickets/templates/tickets/aff_ticket.html:40
msgid "Not solved"
msgstr "Non résolu"
#: tickets/templates/tickets/aff_ticket.html:45
#: tickets/templates/tickets/aff_ticket.html:46
msgid "Opened by"
msgstr "Ouvert par"
#: tickets/templates/tickets/aff_ticket.html:51
msgid "Anonymous user"
msgstr "Utilisateur anonyme"
#: tickets/templates/tickets/aff_ticket.html:55
#: tickets/templates/tickets/aff_ticket.html:56
msgid "Response address: "
msgstr "Adresse de réponse : "
#: tickets/templates/tickets/aff_ticket.html:55
#: tickets/templates/tickets/aff_ticket.html:56
msgid "Response to your ticket"
msgstr "Réponse à votre ticket"
#: tickets/templates/tickets/aff_ticket.html:60
msgid "Title:"
msgstr "Titre :"
#: tickets/templates/tickets/aff_ticket.html:61
msgid "Description:"
msgstr "Description :"
msgid "Add a comment "
msgstr "Ajouter un commentaire"
#: tickets/templates/tickets/aff_ticket.html:65
msgid "Edit this ticket"
msgstr "Modifier le ticket."
#: 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:67
#: tickets/templates/tickets/aff_ticket.html:66
msgid "Mark as solved"
msgstr "Marquer comme résolu"
#: tickets/templates/tickets/aff_ticket.html:69
#: tickets/templates/tickets/aff_ticket.html:68
msgid "Mark as unsolved"
msgstr "Marquer comme non résolu"
#: tickets/templates/tickets/aff_ticket.html:78
#: 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"
@ -200,6 +246,21 @@ msgstr ""
msgid "Open a ticket"
msgstr "Ouvrir un ticket"
#: tickets/templates/tickets/delete.html:29
msgid "Deletion of tickets"
msgstr "Suppression de tickets"
#: 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/delete.html:36
msgid "Confirm"
msgstr "Confirmer"
#: tickets/templates/tickets/edit.html:34
msgid "Ticket opening"
msgstr "Ouverture de ticket"
@ -242,10 +303,6 @@ msgstr "Liste des tickets"
msgid "Manage the tickets"
msgstr "Gérer les tickets"
#: tickets/templates/tickets/preferences.html:14
msgid "Edit"
msgstr "Modifier"
#: tickets/templates/tickets/preferences.html:21
msgid "Publication email address"
msgstr "Adresse mail de publication"
@ -258,18 +315,38 @@ msgstr "Pas d'adresse mail, les tickets ne seront pas publiés."
msgid "No tickets"
msgstr "Pas de tickets"
#: tickets/views.py:56
#: 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:102
#: tickets/views.py:109
msgid "Ticket has been updated successfully"
msgstr "Le ticket a été mis à jour"
#: tickets/views.py:123 tickets/views.py:148
#: 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"
@ -298,9 +375,6 @@ msgstr "Jamais"
#~ "Vous n'êtes pas authentifié. Veuillez vous connecter ou fournir une "
#~ "adresse mail pour que nous puissions vous recontacter."
#~ msgid "Open the ticket"
#~ msgstr "Ouvrir le ticket"
#~ msgid "Email language"
#~ msgstr "Langue du mail"

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

@ -29,6 +29,9 @@ 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 django.core.mail import EmailMessage
@ -63,10 +66,12 @@ 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)
request = None
language = models.CharField(
max_length=16, help_text=_("Language of the ticket."), default="en"
)
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")
@ -76,13 +81,25 @@ class Ticket(AclMixin, models.Model):
else:
return _("Anonymous ticket. Date: %s.") % (self.date)
@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}
language = getattr(self.request, "LANGUAGE_CODE", "en")
if language == "fr":
if self.language == "fr":
obj = "Nouveau ticket ouvert"
template = loader.get_template("tickets/publication_mail_fr")
else:
@ -94,7 +111,7 @@ class Ticket(AclMixin, models.Model):
template.render(context),
GeneralOption.get_cached_value("email_from"),
[to_addr],
reply_to=[self.email],
reply_to=[self.get_mail],
)
mail_to_send.send(fail_silently=False)
@ -103,13 +120,13 @@ class Ticket(AclMixin, models.Model):
""" 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
@ -117,13 +134,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):
@ -131,6 +148,97 @@ 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",
)
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):
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],
)
mail_to_send.send(fail_silently=False)
@receiver(post_save, sender=Ticket)
def ticket_post_save(**kwargs):
""" Send the mail to publish the new ticket """
@ -138,3 +246,12 @@ def ticket_post_save(**kwargs):
if TicketOption.get_cached_value("publish_address"):
ticket = kwargs["instance"]
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

@ -26,6 +26,7 @@ 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 %}
@ -54,28 +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 | linebreaks }}</p>
<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 ticket %}
<a type="button" href="{% url 'tickets:edit-ticket' ticket.id %}" class="btn btn-info"><p>{% trans "Edit this ticket" %}</p></a>
{% if not ticket.solved %}
<a type="button" href="{% url 'tickets:change-ticket-status' ticket.id %}" class="btn btn-success"><p>{% trans "Mark as solved" %}</p></a>
{% else %}
<a type="button" href="{% url 'tickets:change-ticket-status' ticket.id %}" class="btn btn-warning"><p>{% trans "Mark as unsolved" %}</p></a>
{% endif %}
{% 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,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 | safe }}
Description: {{ ticket.description | safe }}

View file

@ -1,11 +1,11 @@
{% 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 | 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

@ -39,4 +39,7 @@ urlpatterns = [
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

@ -36,13 +36,19 @@ 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 .forms import NewTicketForm, EditTicketForm
from .forms import NewTicketForm, EditTicketForm, CommentTicketForm
def new_ticket(request):
@ -71,10 +77,11 @@ def new_ticket(request):
@can_view(Ticket)
def aff_ticket(request, ticket, ticketid):
"""View to display only one ticket"""
comments = CommentTicket.objects.filter(parent_ticket=ticket)
return render(
request,
"tickets/aff_ticket.html",
{"ticket": ticket},
{"ticket": ticket, "comments": comments},
)
@ -110,6 +117,59 @@ def edit_ticket(request, ticket, ticketid):
)
@login_required
@can_view(Ticket)
def add_comment(request, ticket, ticketid):
""" Add a comment to a ticket"""
commentticket = CommentTicketForm(request.POST or None)
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
)
@login_required
@can_view_all(Ticket)
def aff_tickets(request):