From 73e7697a3c6e50e9093d2c8ff21413b1d105cb40 Mon Sep 17 00:00:00 2001 From: nanoy Date: Thu, 12 Sep 2019 09:40:43 +0200 Subject: [PATCH] Improvements --- coopeV3/settings.py | 4 +- preferences/admin.py | 14 +++- preferences/forms.py | 10 ++- preferences/migrations/0019_improvement.py | 31 ++++++++ .../migrations/0020_auto_20190908_1217.py | 39 ++++++++++ preferences/models.py | 28 +++++++ .../preferences/improvement_profile.html | 21 ++++++ .../preferences/improvements_index.html | 68 +++++++++++++++++ preferences/urls.py | 9 ++- preferences/views.py | 75 ++++++++++++++++++- templates/nav.html | 8 ++ 11 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 preferences/migrations/0019_improvement.py create mode 100644 preferences/migrations/0020_auto_20190908_1217.py create mode 100644 preferences/templates/preferences/improvement_profile.html create mode 100644 preferences/templates/preferences/improvements_index.html diff --git a/coopeV3/settings.py b/coopeV3/settings.py index 7b3448b..4a75236 100644 --- a/coopeV3/settings.py +++ b/coopeV3/settings.py @@ -129,4 +129,6 @@ LOGIN_URL = '/users/login' MEDIA_ROOT = os.path.join(BASE_DIR, 'mediafiles') MEDIA_URL = '/media/' -INTERNAL_IPS = ["127.0.0.1"] \ No newline at end of file +INTERNAL_IPS = ["127.0.0.1"] + +EMAIL_SUBJECT_PREFIX = "[Coope Admin] " \ No newline at end of file diff --git a/preferences/admin.py b/preferences/admin.py index 626fa75..239dc61 100644 --- a/preferences/admin.py +++ b/preferences/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin from simple_history.admin import SimpleHistoryAdmin -from .models import PaymentMethod, GeneralPreferences, Cotisation, DivideHistory, PriceProfile +from .models import PaymentMethod, GeneralPreferences, Cotisation, DivideHistory, PriceProfile, Improvement class CotisationAdmin(SimpleHistoryAdmin): """ @@ -40,8 +40,18 @@ class DivideHistoryAdmin(SimpleHistoryAdmin): list_display = ('date', 'total_cotisations', 'total_cotisations_amount', 'total_ptm_amount', 'coopeman') ordering = ('-date',) +class ImprovementAdmin(SimpleHistoryAdmin): + """ + The admin class for Improvement. + """ + list_display = ('title', 'mode', 'seen', 'done', 'date') + ordering = ('-date',) + search_fields = ('title', 'description') + list_filter = ('mode', 'seen', 'done') + admin.site.register(PaymentMethod, PaymentMethodAdmin) admin.site.register(GeneralPreferences, GeneralPreferencesAdmin) admin.site.register(Cotisation, CotisationAdmin) admin.site.register(PriceProfile, PriceProfileAdmin) -admin.site.register(DivideHistory, DivideHistoryAdmin) \ No newline at end of file +admin.site.register(DivideHistory, DivideHistoryAdmin) +admin.site.register(Improvement, ImprovementAdmin) \ No newline at end of file diff --git a/preferences/forms.py b/preferences/forms.py index 1ccd939..089269f 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -1,7 +1,7 @@ from django import forms from django.core.exceptions import ValidationError -from .models import Cotisation, PaymentMethod, GeneralPreferences, PriceProfile +from .models import Cotisation, PaymentMethod, GeneralPreferences, PriceProfile, Improvement class CotisationForm(forms.ModelForm): """ @@ -50,3 +50,11 @@ class GeneralPreferencesForm(forms.ModelForm): 'home_text': forms.Textarea(attrs={'placeholder': 'Ce message sera affiché sur la page d\'accueil'}) } + +class ImprovementForm(forms.ModelForm): + """ + Form to create an improvement + """ + class Meta: + model = Improvement + fields = ["title", "mode", "description"] diff --git a/preferences/migrations/0019_improvement.py b/preferences/migrations/0019_improvement.py new file mode 100644 index 0000000..6e24176 --- /dev/null +++ b/preferences/migrations/0019_improvement.py @@ -0,0 +1,31 @@ +# Generated by Django 2.1 on 2019-09-08 09:59 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('preferences', '0018_auto_20190627_2302'), + ] + + operations = [ + migrations.CreateModel( + name='Improvement', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=255)), + ('mode', models.IntegerField(choices=[(0, 'Bug'), (1, 'Amélioration'), (2, 'Nouvelle fonctionnalité')])), + ('description', models.TextField()), + ('seen', models.BooleanField(default=False)), + ('done', models.BooleanField(default=False)), + ('coopeman', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='improvement_submitted', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'Amélioration', + }, + ), + ] diff --git a/preferences/migrations/0020_auto_20190908_1217.py b/preferences/migrations/0020_auto_20190908_1217.py new file mode 100644 index 0000000..f246c11 --- /dev/null +++ b/preferences/migrations/0020_auto_20190908_1217.py @@ -0,0 +1,39 @@ +# Generated by Django 2.1 on 2019-09-08 10:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0019_improvement'), + ] + + operations = [ + migrations.AddField( + model_name='improvement', + name='date', + field=models.DateTimeField(auto_now_add=True, default='2019-09-08 00:00'), + preserve_default=False, + ), + migrations.AlterField( + model_name='improvement', + name='done', + field=models.BooleanField(default=False, verbose_name='Fait ?'), + ), + migrations.AlterField( + model_name='improvement', + name='mode', + field=models.IntegerField(choices=[(0, 'Bug'), (1, 'Amélioration'), (2, 'Nouvelle fonctionnalité')], verbose_name='Type'), + ), + migrations.AlterField( + model_name='improvement', + name='seen', + field=models.BooleanField(default=False, verbose_name='Vu ?'), + ), + migrations.AlterField( + model_name='improvement', + name='title', + field=models.CharField(max_length=255, verbose_name='Titre'), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index 161b079..4ffc74e 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -202,3 +202,31 @@ class PriceProfile(models.Model): def __str__(self): return self.name + +class Improvement(models.Model): + """ + Stores bugs and amelioration proposals. + """ + + BUG = 0 + AMELIORATION = 1 + NEWFEATURE = 2 + + MODES = ( + (BUG, "Bug"), + (AMELIORATION, "Amélioration"), + (NEWFEATURE, "Nouvelle fonctionnalité") + ) + + class Meta: + verbose_name = "Amélioration" + + title = models.CharField(max_length=255, verbose_name="Titre") + mode = models.IntegerField(choices=MODES, verbose_name="Type") + description = models.TextField() + seen = models.BooleanField(default=False, verbose_name="Vu ?") + done = models.BooleanField(default=False, verbose_name="Fait ?") + coopeman = models.ForeignKey(User, on_delete=models.PROTECT, related_name="improvement_submitted") + date = models.DateTimeField(auto_now_add=True) + + \ No newline at end of file diff --git a/preferences/templates/preferences/improvement_profile.html b/preferences/templates/preferences/improvement_profile.html new file mode 100644 index 0000000..ff2af09 --- /dev/null +++ b/preferences/templates/preferences/improvement_profile.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} +{% block entete %}Amélioration {{improvement.title}}{% endblock %} +{% block navbar %} + +{% endblock %} +{% block content %} +
+
+

{{improvement.title}}

+
+ Retour à la liste des améliorations

+ Titre : {{improvement.title}}
+ Type : {{improvement.get_mode_display}}
+ Date : {{improvement.date}}
+ Fait : {{improvement.done|yesno:"Oui,Non"}}
+ Coopeman : {{improvement.coopeman}}
+ Description : {{improvement.description}}
+
+{% endblock %} diff --git a/preferences/templates/preferences/improvements_index.html b/preferences/templates/preferences/improvements_index.html new file mode 100644 index 0000000..930b158 --- /dev/null +++ b/preferences/templates/preferences/improvements_index.html @@ -0,0 +1,68 @@ +{% extends "base.html" %} +{% block entete %}Améliorations{% endblock %} +{% block navbar %} + +{% endblock %} +{% block content %} +
+
+

Liste des améliorations à faire

+
+
+ + + + + + + + + + + + {% for improvement in todo_improvements %} + + + + + + + + {% endfor %} + +
TitreTypeVu ?DateAdministration
{{improvement.title}}{{improvement.get_mode_display}}{{improvement.seen|yesno:"Oui,Non"}}{{improvement.date}} Voir Passer en fait Supprimer
+
+
+
+
+

Liste des améliorations faîtes

+
+
+ + + + + + + + + + + + {% for improvement in done_improvements %} + + + + + + + + {% endfor %} + +
TitreTypeVu ?DateAdministration
{{improvement.title}}{{improvement.get_mode_display}}{{improvement.seen|yesno:"Oui,Non"}}{{improvement.date}} Voir Passer en non fait Supprimer
+
+
+{% endblock %} diff --git a/preferences/urls.py b/preferences/urls.py index fa31467..ddf0878 100644 --- a/preferences/urls.py +++ b/preferences/urls.py @@ -19,5 +19,10 @@ urlpatterns = [ path('deletePriceProfile/', views.delete_price_profile, name="deletePriceProfile"), path('inactive', views.inactive, name="inactive"), path('getConfig', views.get_config, name="getConfig"), - path('getCotisation/', views.get_cotisation, name="getCotisation") -,] + path('getCotisation/', views.get_cotisation, name="getCotisation"), + path('addImprovement', views.add_improvement, name="addImprovement"), + path('improvementsIndex', views.improvements_index, name="improvementsIndex"), + path('improvementProfile/', views.improvement_profile, name="improvementProfile"), + path('deleteImprovement/', views.delete_improvement, name="deleteImprovement"), + path('changeImprovementState/', views.change_improvement_state, name="changeImprovementState"), +] diff --git a/preferences/views.py b/preferences/views.py index ffeda09..12fe461 100644 --- a/preferences/views.py +++ b/preferences/views.py @@ -7,12 +7,13 @@ from django.contrib.auth.decorators import login_required, permission_required from django.http import HttpResponse from django.forms.models import model_to_dict from django.http import Http404 +from django.core.mail import mail_admins from coopeV3.acl import active_required -from .models import GeneralPreferences, Cotisation, PaymentMethod, PriceProfile +from .models import GeneralPreferences, Cotisation, PaymentMethod, PriceProfile, Improvement -from .forms import CotisationForm, PaymentMethodForm, GeneralPreferencesForm, PriceProfileForm +from .forms import CotisationForm, PaymentMethodForm, GeneralPreferencesForm, PriceProfileForm, ImprovementForm @active_required @login_required @@ -245,3 +246,73 @@ def delete_price_profile(request,pk): price_profile.delete() messages.success(request, message) return redirect(reverse('preferences:priceProfilesIndex')) + + +########## Improvements ########## + +@active_required +@login_required +def add_improvement(request): + """ + Display a form to create an improvement. Any logged user can access it + """ + form = ImprovementForm(request.POST or None) + if form.is_valid(): + improvement = form.save(commit=False) + improvement.coopeman = request.user + improvement.save() + mail_admins("Nouvelle proposition d'amélioration", "Une nouvelle proposition d'amélioration a été postée (" + improvement.title + ", " + improvement.get_mode_display() + "). Le corps est le suivant : " + improvement.description) + messages.success(request, "Votre proposition a bien été envoyée") + return redirect(reverse('home')) + return render(request, "form.html", {"form": form, "form_title": "Proposition d'amélioration", "form_button": "Envoyer", "form_button_icon": "bug"}) + + +@active_required +@login_required +@permission_required('preferences.view_improvement') +def improvements_index(request): + """ + Display all improvements + """ + todo_improvements = Improvement.objects.filter(done=False) + done_improvements = Improvement.objects.filter(done=True) + return render(request, "preferences/improvements_index.html", {"todo_improvements": todo_improvements, "done_improvements": done_improvements}) + + +@active_required +@login_required +@permission_required('preferences.view_improvement') +@permission_required('preferences.change_improvement') +def improvement_profile(request, pk): + """ + Display an improvement + """ + improvement = get_object_or_404(Improvement, pk=pk) + improvement.seen = 1 + improvement.save() + return render(request, "preferences/improvement_profile.html", {"improvement": improvement}) + +@active_required +@login_required +@permission_required('preferences.change_improvement') +def change_improvement_state(request, pk): + """ + Change done state of an improvement + """ + improvement = get_object_or_404(Improvement, pk=pk) + improvement.done = 1 - improvement.done + improvement.save() + messages.success(request, "L'état a bien été changé") + return redirect(reverse('preferences:improvementsIndex')) + +@active_required +@login_required +@permission_required('preferences.delete_improvement') +def delete_improvement(request, pk): + """ + Delete an improvement + """ + improvement = get_object_or_404(Improvement, pk=pk) + improvement.delete() + messages.success(request, "L'amélioration a bien été supprimée.") + return redirect(reverse('preferences:improvementsIndex')) \ No newline at end of file diff --git a/templates/nav.html b/templates/nav.html index c8583bd..1443214 100644 --- a/templates/nav.html +++ b/templates/nav.html @@ -70,6 +70,14 @@ Calcul de prix {% endif %} + + Proposition d'amélioration + +{% if perms.preferences.view_improvement %} + + Améliorations + +{% endif %} Deconnexion