Commit 7f07b1ed authored by Grizzly's avatar Grizzly

Merge branch 'tickets' into 'dev'

Tickets

See merge request federez/re2o!427
parents ebe3a9a6 2777537d
Pipeline #1470 passed with stage
in 3 minutes and 28 seconds
......@@ -503,5 +503,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</div>
</div>
{% for template in optionnal_templates_list %}
{{ template }}
{% endfor %}
{% endblock %}
......@@ -40,6 +40,8 @@ from django.utils.translation import ugettext as _
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.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()
cotisationsoptions, _created = CotisationsOption.objects.get_or_create()
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({
'useroptions': useroptions,
'machineoptions': machineoptions,
......@@ -109,6 +115,7 @@ def display_options(request):
'switchmanagementcred_list': switchmanagementcred_list,
'radiusoptions' : radiusoptions,
'cotisationsoptions': cotisationsoptions,
'optionnal_templates_list': optionnal_templates_list,
'document_template_list': document_template_list,
}, 'preferences/display_preferences.html', request)
......
......@@ -29,7 +29,8 @@ from django.contrib import messages
from django.http import HttpRequest
from preferences.models import GeneralOption, OptionalMachine
from django.utils.translation import get_language
from importlib import import_module
from re2o.settings_local import OPTIONNAL_APPS_RE2O
def context_user(request):
"""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'),
}
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):
"""Add the current date in the context for quick informations and
......
......@@ -62,6 +62,7 @@ DJANGO_CONTRIB_APPS = (
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.humanize',
)
EXTERNAL_CONTRIB_APPS = (
'bootstrap3',
......@@ -131,6 +132,7 @@ TEMPLATES = [
'django.contrib.messages.context_processors.messages',
'django.template.context_processors.request',
're2o.context_processors.context_user',
're2o.context_processors.context_optionnal_apps',
're2o.context_processors.date_now',
],
},
......
......@@ -108,5 +108,8 @@ GID_RANGES = {
'posix': [501, 600],
}
# Some optionnal Re2o Apps
OPTIONNAL_APPS_RE2O = ()
# Some Django apps you want to add in you local project
OPTIONNAL_APPS = ()
OPTIONNAL_APPS = OPTIONNAL_APPS_RE2O + ()
......@@ -31,6 +31,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% block content %}
<h2>{% blocktrans %}Contact the organisation {{asso_name}}{% endblocktrans %}</h2>
</br>
{% for template in optionnal_templates_contact_list %}
{{template}}
{% endfor %}
{% for contact in contacts %}
......
......@@ -49,6 +49,8 @@ from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from django.views.generic import RedirectView
from .settings_local import OPTIONNAL_APPS_RE2O
from .views import index, about_page, contact_page
# Admin site configuration
......@@ -83,6 +85,10 @@ urlpatterns = [
url(r'^admin/login/$', RedirectView.as_view(pattern_name='login')),
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
if 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar
......
......@@ -43,6 +43,8 @@ from preferences.models import (
)
from .contributors import CONTRIBUTORS
from importlib import import_module
from re2o.settings_local import OPTIONNAL_APPS_RE2O
def form(ctx, template, request):
......@@ -113,12 +115,16 @@ def contact_page(request):
"""
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(
request,
"re2o/contact.html",
{
'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 %}
<li><a href="{% url 'cotisations:index' %}"><i class="fa fa-eur"></i> {% trans "Manage the subscriptions" %}</a></li>
{% acl_end %}
{% for template in optionnal_templates_navbar_user_list%}
{{ template }}
{% endfor %}
</ul>
</li>
{% acl_end %}
......@@ -126,13 +130,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
</ul>
<ul class="nav navbar-nav navbar-right">
<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">
<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>
{% comment %}
<li><a href="{% url 'tickets:new-ticket' %}"><i class="fa fa-ticket"></i> {% trans "Ouvrir un ticket" %}</a><li>
{% endcomment %}
</ul>
</li>
{% if not request.user.is_authenticated %}
{% for template in optionnal_templates_navbar_logout_list %}
{{ template }}
{% endfor %}
{% if var_sa %}
<li>
<a href="{% url 'users:new-user' %}">
......
from django.contrib import admin
from .models import Ticket
admin.site.register(Ticket)
# Register your models here.
from django.apps import AppConfig
class TicketsConfig(AppConfig):
name = 'tickets'
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 = []
# -*- 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),
),
]
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()
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__'
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")
{% 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 %}
{% 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 %}
{% 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>
{% 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">&#125;</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 %}
{% 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 %}
{% 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 %}