mirror of
https://gitlab2.federez.net/re2o/re2o
synced 2024-11-26 14:42:25 +00:00
Merge branch 'tickets' into 'dev'
Tickets See merge request federez/re2o!427
This commit is contained in:
commit
7f07b1ed48
35 changed files with 904 additions and 4 deletions
|
@ -503,5 +503,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% for template in optionnal_templates_list %}
|
||||||
|
{{ template }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
|
from importlib import import_module
|
||||||
|
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||||
from re2o.views import form
|
from re2o.views import form
|
||||||
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all, can_delete
|
from re2o.acl import can_create, can_edit, can_delete_set, can_view_all, can_delete
|
||||||
|
|
||||||
|
@ -94,6 +96,10 @@ def display_options(request):
|
||||||
radiusoptions, _ = RadiusOption.objects.get_or_create()
|
radiusoptions, _ = RadiusOption.objects.get_or_create()
|
||||||
cotisationsoptions, _created = CotisationsOption.objects.get_or_create()
|
cotisationsoptions, _created = CotisationsOption.objects.get_or_create()
|
||||||
document_template_list = DocumentTemplate.objects.order_by('name')
|
document_template_list = DocumentTemplate.objects.order_by('name')
|
||||||
|
|
||||||
|
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
|
||||||
|
optionnal_templates_list = [app.views.preferences(request) for app in optionnal_apps]
|
||||||
|
|
||||||
return form({
|
return form({
|
||||||
'useroptions': useroptions,
|
'useroptions': useroptions,
|
||||||
'machineoptions': machineoptions,
|
'machineoptions': machineoptions,
|
||||||
|
@ -109,6 +115,7 @@ def display_options(request):
|
||||||
'switchmanagementcred_list': switchmanagementcred_list,
|
'switchmanagementcred_list': switchmanagementcred_list,
|
||||||
'radiusoptions' : radiusoptions,
|
'radiusoptions' : radiusoptions,
|
||||||
'cotisationsoptions': cotisationsoptions,
|
'cotisationsoptions': cotisationsoptions,
|
||||||
|
'optionnal_templates_list': optionnal_templates_list,
|
||||||
'document_template_list': document_template_list,
|
'document_template_list': document_template_list,
|
||||||
}, 'preferences/display_preferences.html', request)
|
}, 'preferences/display_preferences.html', request)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ from django.contrib import messages
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from preferences.models import GeneralOption, OptionalMachine
|
from preferences.models import GeneralOption, OptionalMachine
|
||||||
from django.utils.translation import get_language
|
from django.utils.translation import get_language
|
||||||
|
from importlib import import_module
|
||||||
|
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||||
|
|
||||||
def context_user(request):
|
def context_user(request):
|
||||||
"""Fonction de context lorsqu'un user est logué (ou non),
|
"""Fonction de context lorsqu'un user est logué (ou non),
|
||||||
|
@ -57,6 +58,15 @@ def context_user(request):
|
||||||
'ipv6_enabled': OptionalMachine.get_cached_value('ipv6'),
|
'ipv6_enabled': OptionalMachine.get_cached_value('ipv6'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def context_optionnal_apps(request):
|
||||||
|
"""Fonction de context pour générer la navbar en fonction des
|
||||||
|
apps optionnels"""
|
||||||
|
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
|
||||||
|
optionnal_templates_navbar_user_list = [app.views.navbar_user(request) for app in optionnal_apps]
|
||||||
|
optionnal_templates_navbar_logout_list = [app.views.navbar_logout(request) for app in optionnal_apps]
|
||||||
|
return {'optionnal_templates_navbar_user_list':optionnal_templates_navbar_user_list,
|
||||||
|
'optionnal_templates_navbar_logout_list':optionnal_templates_navbar_logout_list}
|
||||||
|
|
||||||
|
|
||||||
def date_now(request):
|
def date_now(request):
|
||||||
"""Add the current date in the context for quick informations and
|
"""Add the current date in the context for quick informations and
|
||||||
|
|
|
@ -62,6 +62,7 @@ DJANGO_CONTRIB_APPS = (
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django.contrib.humanize',
|
||||||
)
|
)
|
||||||
EXTERNAL_CONTRIB_APPS = (
|
EXTERNAL_CONTRIB_APPS = (
|
||||||
'bootstrap3',
|
'bootstrap3',
|
||||||
|
@ -131,6 +132,7 @@ TEMPLATES = [
|
||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
'django.template.context_processors.request',
|
'django.template.context_processors.request',
|
||||||
're2o.context_processors.context_user',
|
're2o.context_processors.context_user',
|
||||||
|
're2o.context_processors.context_optionnal_apps',
|
||||||
're2o.context_processors.date_now',
|
're2o.context_processors.date_now',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -108,5 +108,8 @@ GID_RANGES = {
|
||||||
'posix': [501, 600],
|
'posix': [501, 600],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Some optionnal Re2o Apps
|
||||||
|
OPTIONNAL_APPS_RE2O = ()
|
||||||
|
|
||||||
# Some Django apps you want to add in you local project
|
# Some Django apps you want to add in you local project
|
||||||
OPTIONNAL_APPS = ()
|
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + ()
|
||||||
|
|
|
@ -32,6 +32,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
<h2>{% blocktrans %}Contact the organisation {{asso_name}}{% endblocktrans %}</h2>
|
<h2>{% blocktrans %}Contact the organisation {{asso_name}}{% endblocktrans %}</h2>
|
||||||
</br>
|
</br>
|
||||||
|
|
||||||
|
{% for template in optionnal_templates_contact_list %}
|
||||||
|
{{template}}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% for contact in contacts %}
|
{% for contact in contacts %}
|
||||||
|
|
||||||
<div class="panel panel-info">
|
<div class="panel panel-info">
|
||||||
|
|
|
@ -49,6 +49,8 @@ from django.contrib import admin
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
|
from .settings_local import OPTIONNAL_APPS_RE2O
|
||||||
|
|
||||||
from .views import index, about_page, contact_page
|
from .views import index, about_page, contact_page
|
||||||
|
|
||||||
# Admin site configuration
|
# Admin site configuration
|
||||||
|
@ -83,6 +85,10 @@ urlpatterns = [
|
||||||
url(r'^admin/login/$', RedirectView.as_view(pattern_name='login')),
|
url(r'^admin/login/$', RedirectView.as_view(pattern_name='login')),
|
||||||
url(r'^admin/', include(admin.site.urls)),
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns += [url(r'^{}/'.format(app), include('{}.urls'.format(app), namespace=app)) for app in OPTIONNAL_APPS_RE2O]
|
||||||
|
|
||||||
# Add debug_toolbar URLs if activated
|
# Add debug_toolbar URLs if activated
|
||||||
if 'debug_toolbar' in settings.INSTALLED_APPS:
|
if 'debug_toolbar' in settings.INSTALLED_APPS:
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
|
|
|
@ -43,6 +43,8 @@ from preferences.models import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from .contributors import CONTRIBUTORS
|
from .contributors import CONTRIBUTORS
|
||||||
|
from importlib import import_module
|
||||||
|
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||||
|
|
||||||
|
|
||||||
def form(ctx, template, request):
|
def form(ctx, template, request):
|
||||||
|
@ -113,12 +115,16 @@ def contact_page(request):
|
||||||
"""
|
"""
|
||||||
address = MailContact.objects.all()
|
address = MailContact.objects.all()
|
||||||
|
|
||||||
|
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
|
||||||
|
optionnal_templates_contact_list = [app.views.contact(request) for app in optionnal_apps]
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
"re2o/contact.html",
|
"re2o/contact.html",
|
||||||
{
|
{
|
||||||
'contacts': address,
|
'contacts': address,
|
||||||
'asso_name': AssoOption.objects.first().name
|
'asso_name': AssoOption.objects.first().name,
|
||||||
|
'optionnal_templates_contact_list':optionnal_templates_contact_list,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
{% can_view_app cotisations %}
|
{% can_view_app cotisations %}
|
||||||
<li><a href="{% url 'cotisations:index' %}"><i class="fa fa-eur"></i> {% trans "Manage the subscriptions" %}</a></li>
|
<li><a href="{% url 'cotisations:index' %}"><i class="fa fa-eur"></i> {% trans "Manage the subscriptions" %}</a></li>
|
||||||
{% acl_end %}
|
{% acl_end %}
|
||||||
|
|
||||||
|
{% for template in optionnal_templates_navbar_user_list%}
|
||||||
|
{{ template }}
|
||||||
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% acl_end %}
|
{% acl_end %}
|
||||||
|
@ -126,13 +130,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-info"></i> {% trans "More information" %}<span class="caret"></span></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><i class="fa fa-info"></i> {% trans "Information and contact" %}<span class="caret"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> {% trans "About" %}</a></li>
|
<li><a href="{% url 'about' %}"><i class="fa fa-info-circle"></i> {% trans "About" %}</a></li>
|
||||||
<li><a href="{% url 'contact' %}"><i class="fa fa-at"></i> {% trans "Contact" %}</a></li>
|
<li><a href="{% url 'contact' %}"><i class="fa fa-at"></i> {% trans "Contact" %}</a></li>
|
||||||
|
{% comment %}
|
||||||
|
<li><a href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %}</a><li>
|
||||||
|
{% endcomment %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
{% if not request.user.is_authenticated %}
|
{% if not request.user.is_authenticated %}
|
||||||
|
{% for template in optionnal_templates_navbar_logout_list %}
|
||||||
|
{{ template }}
|
||||||
|
{% endfor %}
|
||||||
{% if var_sa %}
|
{% if var_sa %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'users:new-user' %}">
|
<a href="{% url 'users:new-user' %}">
|
||||||
|
|
0
tickets/__init__.py
Normal file
0
tickets/__init__.py
Normal file
4
tickets/admin.py
Normal file
4
tickets/admin.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from django.contrib import admin
|
||||||
|
from .models import Ticket
|
||||||
|
admin.site.register(Ticket)
|
||||||
|
# Register your models here.
|
5
tickets/apps.py
Normal file
5
tickets/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class TicketsConfig(AppConfig):
|
||||||
|
name = 'tickets'
|
24
tickets/forms.py
Normal file
24
tickets/forms.py
Normal file
|
@ -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 = []
|
||||||
|
|
48
tickets/migrations/0001_initial.py
Normal file
48
tickets/migrations/0001_initial.py
Normal file
|
@ -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
tickets/migrations/__init__.py
Normal file
0
tickets/migrations/__init__.py
Normal file
97
tickets/models.py
Normal file
97
tickets/models.py
Normal file
|
@ -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()
|
11
tickets/preferences/forms.py
Normal file
11
tickets/preferences/forms.py
Normal file
|
@ -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__'
|
19
tickets/preferences/models.py
Normal file
19
tickets/preferences/models.py
Normal file
|
@ -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")
|
82
tickets/templates/tickets/aff_ticket.html
Normal file
82
tickets/templates/tickets/aff_ticket.html
Normal file
|
@ -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 %}
|
89
tickets/templates/tickets/aff_tickets.html
Normal file
89
tickets/templates/tickets/aff_tickets.html
Normal file
|
@ -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 %}
|
13
tickets/templates/tickets/contact.html
Normal file
13
tickets/templates/tickets/contact.html
Normal file
|
@ -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>
|
48
tickets/templates/tickets/form_preferences.html
Normal file
48
tickets/templates/tickets/form_preferences.html
Normal file
|
@ -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 %}
|
58
tickets/templates/tickets/form_ticket.html
Normal file
58
tickets/templates/tickets/form_ticket.html
Normal file
|
@ -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 %}
|
34
tickets/templates/tickets/index.html
Normal file
34
tickets/templates/tickets/index.html
Normal file
|
@ -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 %}
|
2
tickets/templates/tickets/navbar.html
Normal file
2
tickets/templates/tickets/navbar.html
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
{% load i18n %}
|
||||||
|
<li><a href="{% url 'tickets:aff-tickets' %}"><i class="fa fa-ticket"></i>{% trans "Tickets" %}</a></li>
|
6
tickets/templates/tickets/navbar_logout.html
Normal file
6
tickets/templates/tickets/navbar_logout.html
Normal file
|
@ -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>
|
36
tickets/templates/tickets/preferences.html
Normal file
36
tickets/templates/tickets/preferences.html
Normal file
|
@ -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>
|
23
tickets/templates/tickets/profil.html
Normal file
23
tickets/templates/tickets/profil.html
Normal file
|
@ -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>
|
12
tickets/templates/tickets/publication_mail_en
Normal file
12
tickets/templates/tickets/publication_mail_en
Normal file
|
@ -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}}
|
12
tickets/templates/tickets/publication_mail_fr
Normal file
12
tickets/templates/tickets/publication_mail_fr
Normal file
|
@ -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}}
|
3
tickets/tests.py
Normal file
3
tickets/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
10
tickets/urls.py
Normal file
10
tickets/urls.py
Normal file
|
@ -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'),
|
||||||
|
]
|
197
tickets/views.py
Normal file
197
tickets/views.py
Normal file
|
@ -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')
|
|
@ -119,6 +119,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="panel-group" id="accordion">
|
<div class="panel-group" id="accordion">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading clearfix profil" data-parent="#accordion" data-toggle="collapse"
|
<div class="panel-heading clearfix profil" data-parent="#accordion" data-toggle="collapse"
|
||||||
|
@ -527,6 +528,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% for template in optionnal_templates_list %}
|
||||||
|
{{ template }}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,17 @@ from django.http import HttpResponse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.template import loader
|
||||||
|
|
||||||
from rest_framework.renderers import JSONRenderer
|
from rest_framework.renderers import JSONRenderer
|
||||||
from reversion import revisions as reversion
|
from reversion import revisions as reversion
|
||||||
|
|
||||||
from cotisations.models import Facture, Paiement
|
from cotisations.models import Facture, Paiement
|
||||||
from machines.models import Machine
|
from machines.models import Machine
|
||||||
|
|
||||||
from preferences.models import OptionalUser, GeneralOption, AssoOption
|
from preferences.models import OptionalUser, GeneralOption, AssoOption
|
||||||
|
from importlib import import_module
|
||||||
|
from re2o.settings_local import OPTIONNAL_APPS_RE2O
|
||||||
from re2o.views import form
|
from re2o.views import form
|
||||||
from re2o.utils import (
|
from re2o.utils import (
|
||||||
all_has_access,
|
all_has_access,
|
||||||
|
@ -974,6 +978,10 @@ def profil(request, users, **_kwargs):
|
||||||
request.GET.get('order'),
|
request.GET.get('order'),
|
||||||
SortTable.MACHINES_INDEX
|
SortTable.MACHINES_INDEX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
optionnal_apps = [import_module(app) for app in OPTIONNAL_APPS_RE2O]
|
||||||
|
optionnal_templates_list = [app.views.profil(request,users) for app in optionnal_apps]
|
||||||
|
|
||||||
pagination_large_number = GeneralOption.get_cached_value(
|
pagination_large_number = GeneralOption.get_cached_value(
|
||||||
'pagination_large_number'
|
'pagination_large_number'
|
||||||
)
|
)
|
||||||
|
@ -1016,6 +1024,7 @@ def profil(request, users, **_kwargs):
|
||||||
'users': users,
|
'users': users,
|
||||||
'machines_list': machines,
|
'machines_list': machines,
|
||||||
'nb_machines': nb_machines,
|
'nb_machines': nb_machines,
|
||||||
|
'optionnal_templates_list': optionnal_templates_list,
|
||||||
'facture_list': factures,
|
'facture_list': factures,
|
||||||
'ban_list': bans,
|
'ban_list': bans,
|
||||||
'white_list': whitelists,
|
'white_list': whitelists,
|
||||||
|
|
Loading…
Reference in a new issue