Compare commits

..

3 commits

Author SHA1 Message Date
Maurice Debray
84af71a6c7 linting 2022-02-26 12:44:47 +01:00
Maurice Debray
f8b96586db Merge branch 'master' into mdebray/repondre_aux_sondages_a_la_place_des_fanfarons 2022-02-26 12:44:01 +01:00
Maurice Debray
b49accf96e Repondre à la place des fanfarons 2022-02-26 12:42:45 +01:00
33 changed files with 41 additions and 772 deletions

View file

@ -35,7 +35,6 @@ ACCOUNT_CREATION_PASS = import_secret("ACCOUNT_CREATION_PASS")
BASE_DIR = os.path.join(os.path.dirname(__file__), "..", "..")
INSTALLED_APPS = [
"propositions",
"trombonoscope",
"actu",
"colorful",

View file

@ -3,26 +3,14 @@ from django.contrib import admin
from .models import Event, Participants
class ParticipantsAdmin(admin.ModelAdmin):
fields = [
"event",
"participant",
"reponse",
"instrument",
"instrument_autre",
"dont_play_main",
"details",
"creationDate",
"updateDate",
]
readonly_fields = ["creationDate", "updateDate"]
list_display = ["participant", "event", "reponse", "creationDate", "updateDate"]
def has_add_permission(self, req):
return False
def has_change_permission(self,obj, change=False):
return False
# Add event by admin page return a 502 error
admin.site.register(Event)
class ParticipantsAdmin(admin.ModelAdmin):
autocomplete_fields = ["event", "participant"]
class EventAdmin(admin.ModelAdmin):
search_fields = ["nom", "nomcourt", "lieu", "description", "desc_users"]
admin.site.register(Event, EventAdmin)
admin.site.register(Participants, ParticipantsAdmin)

View file

@ -1,8 +1,8 @@
from django import forms
from django.utils.translation import gettext_lazy as _
from gestion.models import ErnestoUser
from calendrier.models import Event, Participants
from gestion.models import ErnestoUser
class ModifEventForm(forms.ModelForm):

View file

@ -1,31 +0,0 @@
# Generated by Django 2.2.25 on 2022-03-14 23:20
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("calendrier", "0006_auto_20210929_1629"),
]
operations = [
migrations.AddField(
model_name="participants",
name="creationDate",
field=models.DateTimeField(
auto_now_add=True,
default=django.utils.timezone.now,
verbose_name="Date de création",
),
preserve_default=False,
),
migrations.AddField(
model_name="participants",
name="updateDate",
field=models.DateTimeField(
auto_now=True, verbose_name="Dernière mise à jour"
),
),
]

View file

@ -1,17 +0,0 @@
# Generated by Django 2.2.27 on 2022-03-22 13:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('calendrier', '0007_auto_20220314_2320'),
]
operations = [
migrations.AddConstraint(
model_name='participants',
constraint=models.UniqueConstraint(fields=('event', 'participant'), name='reponse unique aux event'),
),
]

View file

@ -2,6 +2,7 @@ import uuid
from django.db import models
from django.utils.translation import gettext_lazy as _
from gestion.models import INSTRU_CHOICES, ErnestoUser
ANSWERS = (
@ -72,11 +73,3 @@ class Participants(models.Model):
choices=[("Non", _("Non")), ("Oui", _("Oui"))],
)
details = models.CharField(max_length=50, blank=True)
creationDate = models.DateTimeField(
auto_now_add=True, verbose_name=_("Date de création")
)
updateDate = models.DateTimeField(
auto_now=True, verbose_name=_("Dernière mise à jour")
)
class Meta:
constraints = [ models.UniqueConstraint(fields=['event', 'participant'], name='reponse unique aux event') ]

View file

@ -223,9 +223,6 @@
</div>
</section>
</div>
{% if event.id == 573 %}
<div class="fireworks" style="pointer-events: none; position:fixed; top: 0; left: 0; right: 0; bottom: 0; height: 100%; weight: 100%;"></div>
{% endif %}
{% endblock %}
{% block script %}
<script>
@ -267,13 +264,5 @@ singleEvent.setOption({ lang: 'fr' });
singleEvent.setOption({ lang: 'en' });
{% endifequal %}
</script>
{% if event.id == 573 %}
<script src="https://unpkg.com/fireworks-js@2.x/dist/index.umd.js"></script>
<script>
const container = document.querySelector('.fireworks');
const fireworks = new Fireworks.default(container);
fireworks.updateOptions({ acceleration: 1.01, traceSpeed: 5 });
fireworks.start();
</script>
{% endif %}
{% endblock %}

View file

@ -4,6 +4,7 @@ from django.contrib.auth import get_user_model
from django.template.defaultfilters import urlencode
from django.test import Client, TestCase
from django.utils import timezone
from gestion.models import ErnestoUser
from ..models import Event

View file

@ -4,20 +4,20 @@ from calendar import monthrange
from collections import defaultdict
from datetime import date, datetime
from actu.models import Actu
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy
from django.utils.safestring import mark_safe
from django.views.generic import DeleteView, TemplateView, UpdateView
from gestion.mixins import ChefEventRequiredMixin
from gestion.models import Photo
from actu.models import Actu
from calendrier.calend import EventCalendar
from calendrier.forms import (ChangeDoodleName, EventForm, ModifEventForm,
ParticipantsForm)
from calendrier.models import Event, Participants
from gestion.mixins import ChefEventRequiredMixin, ChefRequiredMixin
from gestion.models import Photo
def generer(*args):
@ -212,7 +212,6 @@ class ViewEvent(LoginRequiredMixin, TemplateView):
else:
instru = participant.instrument
instru = "" if instru is None else instru
sure, maybe, namesoui, namespe, namesnon = instrument_count[instru]
if participant.reponse == "oui":
@ -374,16 +373,16 @@ class ReponseEvent(LoginRequiredMixin, TemplateView):
return context
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
ev = get_object_or_404(Event, id=self.kwargs["id"])
part = request.user.profile
try:
p = Participants.objects.get(event=ev, participant=part)
except Participants.DoesNotExist:
p = None
form = self.form_class(request.POST, instance=p)
if form.is_valid():
try:
p = Participants.objects.get(event=ev, participant=part)
p.delete()
except Participants.DoesNotExist:
pass
obj = form.save(commit=False)
# Si la participation existe déjà, ces 2 ligne sont redondantes
obj.event = ev
obj.participant = part
obj.save()

View file

@ -114,8 +114,19 @@ class UserProfileAdmin(UserAdmin):
user.save()
class ErnestoUserAdmin(admin.ModelAdmin):
search_fields = [
"user__username",
"user__first_name",
"user__last_name",
"phone",
"instru",
]
admin.site.unregister(User)
admin.site.register(User, UserProfileAdmin)
admin.site.register(ErnestoUser, ErnestoUserAdmin)
admin.site.register(VideoGallery)
admin.site.register(Photo)
admin.site.register(Actu)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View file

@ -145,10 +145,6 @@
<!-- Footer -->
<footer id="footer" style="background-color:rgb(228, 82, 47);">
<div class="copyright">
<ul class="icons">
<li><a target="_blank" href="https://cvec.etudiant.gouv.fr/"><img alt="Logo de la CVEC" src='{% static "images/cvec.png" %}' width="100px"/></a></li>
</ul>
<ul class="icons">
<li><a target="_blank" href="https://www.facebook.com/ernestophone"

View file

View file

@ -1,38 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('gestion', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Prop',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('nom', models.CharField(max_length=100)),
('artiste', models.CharField(max_length=100, blank=True)),
('lien', models.URLField(blank=True)),
('nboui', models.IntegerField(verbose_name='oui', default=0)),
('nbnon', models.IntegerField(verbose_name='non', default=0)),
('user', models.ForeignKey(verbose_name='Proposé par', to='gestion.ErnestoUser', on_delete=models.CASCADE)),
],
options={
'verbose_name': 'Proposition',
},
),
migrations.CreateModel(
name='Reponses',
fields=[
('id', models.AutoField(primary_key=True, verbose_name='ID', auto_created=True, serialize=False)),
('reponse', models.CharField(verbose_name='Réponse', choices=[('oui', 'Oui'), ('non', 'Non')], max_length=20, blank=True)),
('part', models.ForeignKey(to='gestion.ErnestoUser', on_delete=models.CASCADE)),
('prop', models.ForeignKey(to='propositions.Prop', on_delete=models.CASCADE)),
],
),
]

View file

@ -1,18 +0,0 @@
# Generated by Django 2.2.9 on 2020-01-04 23:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('propositions', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='prop',
name='nom',
field=models.CharField(max_length=100, verbose_name='nom du morceau'),
),
]

View file

@ -1,75 +0,0 @@
# Generated by Django 2.2.9 on 2020-01-05 13:32
from django.conf import settings
from django.db import migrations, models
def move_profile_to_user(apps, schema_editor):
Reponses = apps.get_model("propositions", "reponses")
for answer in Reponses.objects.all():
answer.user = answer.part.user
answer.save()
def move_user_to_profile(apps, schema_editor):
# One should do something similar to ``move_profile_to_user`` AND make the
# ``part`` field temporarily nullable in the operations below.
# => Grosse flemme
raise NotImplementedError("Who uses migrations backwards anyway?")
class Migration(migrations.Migration):
dependencies = [
("gestion", "0001_initial"),
("propositions", "0002_nom_verbose_name"),
]
operations = [
migrations.AlterModelOptions(
name="reponses",
options={
"verbose_name": "Réponse à une proposition",
"verbose_name_plural": "Réponses à une proposition",
},
),
migrations.RenameField(
model_name="reponses", old_name="prop", new_name="proposition",
),
migrations.AddField(
model_name="reponses",
name="user",
field=models.ForeignKey(
on_delete=models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
null=True,
),
),
migrations.RunPython(move_profile_to_user, move_user_to_profile),
migrations.AlterField(
model_name="reponses",
name="user",
field=models.ForeignKey(
on_delete=models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
null=False,
),
),
migrations.RemoveField(model_name="reponses", name="part"),
migrations.AddField(
model_name="reponses",
name="answer",
field=models.CharField(
choices=[("oui", "Oui"), ("non", "Non")],
default="non",
max_length=3,
verbose_name="Réponse",
),
preserve_default=False,
),
migrations.AlterUniqueTogether(
name="reponses", unique_together={("proposition", "user")},
),
migrations.RemoveField(model_name="reponses", name="reponse",),
migrations.RenameModel(old_name="reponses", new_name="answer"),
]

View file

@ -1,43 +0,0 @@
# Generated by Django 2.2.9 on 2020-01-05 14:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("propositions", "0003_reponse_renaming_and_cleaning"),
]
operations = [
migrations.AlterModelOptions(
name="prop",
options={
"verbose_name": "Proposition de morceau",
"verbose_name_plural": "Propositions de morceaux",
},
),
migrations.RenameField(
model_name="prop", old_name="artiste", new_name="artist",
),
migrations.RenameField(model_name="prop", old_name="lien", new_name="link"),
migrations.RenameField(model_name="prop", old_name="nom", new_name="name"),
migrations.RenameField(model_name="prop", old_name="nbnon", new_name="nb_no"),
migrations.RenameField(model_name="prop", old_name="nboui", new_name="nb_yes"),
migrations.AlterField(
model_name="prop",
name="nb_no",
field=models.IntegerField(default=0, verbose_name="nombre de réponses non"),
),
migrations.AlterField(
model_name="prop",
name="nb_yes",
field=models.IntegerField(default=0, verbose_name="nombre de réponses oui"),
),
migrations.RenameModel(old_name="prop", new_name="proposition"),
migrations.AlterField(
model_name='answer',
name='proposition',
field=models.ForeignKey(on_delete=models.deletion.CASCADE, to='propositions.Proposition'),
),
]

View file

@ -1,24 +0,0 @@
# Generated by Django 2.2.9 on 2020-01-05 15:26
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("propositions", "0004_prop_renaming_and_cleaning"),
]
operations = [
migrations.RemoveField(model_name="proposition", name="nb_no",),
migrations.RemoveField(model_name="proposition", name="nb_yes",),
migrations.AlterField(
model_name="answer",
name="proposition",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="propositions.Proposition",
),
),
]

View file

@ -1,53 +0,0 @@
# Generated by Django 2.2.9 on 2020-01-05 16:28
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
def move_profile_to_user(apps, schema_editor):
Proposition = apps.get_model("propositions", "Proposition")
for proposition in Proposition.objects.all():
proposition.user = proposition.profile.user
proposition.save()
def move_user_to_profile(apps, schema_editor):
# One should do something similar to ``move_profile_to_user`` AND make the
# ``profile`` field temporarily nullable in the operations below.
# => Grosse flemme
raise NotImplementedError("Who uses migrations backwards anyway?")
class Migration(migrations.Migration):
dependencies = [
("propositions", "0005_remove_nb_yes_no_fields"),
]
operations = [
migrations.RenameField(
model_name="proposition", old_name="user", new_name="profile"
),
migrations.AddField(
model_name="proposition",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
verbose_name="Proposé par",
null=True,
),
),
migrations.RunPython(move_profile_to_user, move_user_to_profile),
migrations.RemoveField(model_name="proposition", name="profile"),
migrations.AlterField(
model_name="proposition",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
verbose_name="Proposé par",
),
),
]

View file

@ -1,19 +0,0 @@
# Generated by Django 2.2.27 on 2022-03-22 13:55
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('propositions', '0006_proposition_profile_to_user'),
]
operations = [
migrations.AlterField(
model_name='answer',
name='proposition',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='propositions.Proposition'),
),
]

View file

@ -1,19 +0,0 @@
# Generated by Django 2.2.27 on 2022-09-14 10:44
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('propositions', '0007_auto_20220322_1455'),
]
operations = [
migrations.AlterField(
model_name='answer',
name='proposition',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='propositions.Proposition'),
),
]

View file

@ -1,19 +0,0 @@
# Generated by Django 2.2.28 on 2024-06-15 13:03
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('propositions', '0008_auto_20220914_1244'),
]
operations = [
migrations.AlterField(
model_name='answer',
name='proposition',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='propositions.Proposition'),
),
]

View file

@ -1,34 +0,0 @@
from django.contrib.auth import get_user_model
from django.db import models
User = get_user_model()
class Proposition(models.Model):
name = models.CharField(max_length=100, verbose_name="nom du morceau")
artist = models.CharField(blank=True, max_length=100)
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="Proposé par")
link = models.URLField(blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Proposition de morceau"
verbose_name_plural = "Propositions de morceaux"
class Answer(models.Model):
YES = "oui"
NO = "non"
REP_CHOICES = [(YES, "Oui"), (NO, "Non")]
proposition = models.ForeignKey(Proposition, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
answer = models.CharField("Réponse", max_length=3, choices=REP_CHOICES)
class Meta:
unique_together = ("proposition", "user")
verbose_name = "Réponse à une proposition"
verbose_name_plural = "Réponses à une proposition"

View file

@ -1,14 +0,0 @@
{% extends "gestion/base.html" %}
{% block titre %}Proposition de morceau{% endblock %}
{% block content %}
<p><a href="{% url "propositions:list" %}">Retour aux propositions</a></p>
<form action="{% url "propositions:create" %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Enregistrer" />
</form>
{% endblock %}

View file

@ -1,10 +0,0 @@
{% extends "gestion/base.html" %}
{% block titre %}Suppression d'une proposition{% endblock %}
{% block content %}<form action="" method="post">
{% csrf_token %}
<p><a href="{% url "propositions:list" %}">Retour aux propositions</a></p>
<p>Voulez vous vraiment supprimer la proposition {{ object }}?</p>
<input type="submit" value="Oui" />
</form>
{% endblock %}

View file

@ -1,44 +0,0 @@
{% extends "gestion/base.html" %}
{% block titre %}Propositions de morceau{% endblock %}
{% block content %}
<h1>Liste des propositions</h1>
<p><a href="{% url "propositions:create" %}">Proposer un morceau</a></p>
{% if propositions.exists %}
<table>
<tr>
<th></th>
<th>Oui</th>
<th>Non</th>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
{% for p in propositions %}
<tr class="prop">
<td>
{% if p.link %}<a href={{ p.link }}>{% endif %}
<b>{{ p.name }}</b>{% if p.artist %} - {{ p.artist }}{% endif %}
{% if p.link %}</a>{% endif %}
</td>
<td>{{ p.nb_yes }}</td>
<td>{{ p.nb_no }}</td>
<td><a href="{% url "propositions:oui" p.id %}">Oui</a></td>
<td><a href="{% url "propositions:non" p.id %}">Non</a></td>
<td>{% if p.user_answer %}Vous avez voté {{ p.user_answer }}{% endif %}</td>
<td>
{% if p.user == request.user or request.user.profile.is_chef %}
<a class="supprimer" href="{% url "propositions:delete" p.id %}">Supprimer</a>
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% else %}
Pas de proposition pour le moment
{% endif %}
{% endblock %}

View file

@ -1,165 +0,0 @@
from django.contrib.auth import get_user_model
from django.test import Client, TestCase
from django.urls import reverse_lazy, reverse
from gestion.models import ErnestoUser
from propositions.models import Answer, Proposition
User = get_user_model()
def new_user(username):
u = User.objects.create_user(username=username)
ErnestoUser.objects.create(user=u, slug=username, is_ernesto=True)
return u
class PropositionCreateTest(TestCase):
url = reverse_lazy("propositions:create")
def test_anonymous_cannot_get(self):
response = Client().get(self.url)
self.assertRedirects(response, "/login?next={}".format(self.url))
def test_ernesto_user_can_get(self):
user = new_user("toto")
client = Client()
client.force_login(user)
response = client.get(self.url)
self.assertEqual(response.status_code, 200)
def test_ernesto_user_can_post(self):
user = new_user("toto")
client = Client()
client.force_login(user)
data = {"name": "foo", "artist": "bar", "link": "example.com"}
client.post(self.url, data)
proposition = Proposition.objects.all()
self.assertEqual(1, proposition.count())
proposition = proposition.get()
self.assertEqual(proposition.name, "foo")
self.assertEqual(proposition.artist, "bar")
self.assertEqual(proposition.link, "http://example.com")
self.assertEqual(proposition.user, user)
class PropositionDeleteTest(TestCase):
def setUp(self):
self.owner = new_user("owner")
self.random_user = new_user("toto")
self.chef = new_user("chef")
self.chef.profile.is_chef = True
self.chef.profile.save()
proposition = Proposition.objects.create(name="prop", user=self.owner)
self.url = reverse("propositions:delete", args=(proposition.id,))
def test_anonymous_cannot_get(self):
response = Client().get(self.url)
self.assertRedirects(response, "/login?next={}".format(self.url))
def test_anonymous_cannot_post(self):
response = Client().post(self.url, {})
self.assertRedirects(response, "/login?next={}".format(self.url))
self.assertTrue(Proposition.objects.exists())
def test_random_user_cannot_get(self):
client = Client()
client.force_login(self.random_user)
response = client.get(self.url)
self.assertEqual(response.status_code, 403)
def test_not_owner_cannot_post(self):
client = Client()
client.force_login(self.random_user)
response = client.post(self.url, {})
self.assertEqual(response.status_code, 403)
self.assertTrue(Proposition.objects.exists())
def test_chef_can_get(self):
client = Client()
client.force_login(self.chef)
response = client.get(self.url)
self.assertEqual(response.status_code, 200)
def test_chef_can_post(self):
client = Client()
client.force_login(self.chef)
client.post(self.url, {})
self.assertFalse(Proposition.objects.exists())
def test_owner_can_get(self):
client = Client()
client.force_login(self.owner)
response = client.get(self.url)
self.assertEqual(response.status_code, 200)
def test_owner_can_post(self):
client = Client()
client.force_login(self.owner)
client.post(self.url, {})
self.assertFalse(Proposition.objects.exists())
class PropositionListTest(TestCase):
url = reverse_lazy("propositions:list")
def setUp(self):
self.user = new_user("toto")
for name in ["foo", "bar", "baz"]:
p = Proposition.objects.create(name=name, user=self.user)
Answer.objects.create(proposition=p, user=self.user, answer=Answer.YES)
for name in ["oof", "rab", "zab"]:
p = Proposition.objects.create(name=name, user=self.user)
Answer.objects.create(proposition=p, user=self.user, answer=Answer.NO)
def test_anonymous_cannot_get(self):
response = Client().get(self.url)
self.assertRedirects(response, "/login?next={}".format(self.url))
def test_ernesto_user_can_get(self):
client = Client()
client.force_login(self.user)
response = client.get(self.url)
self.assertEqual(response.status_code, 200)
class ReponseTest(TestCase):
def setUp(self):
self.user = new_user("toto")
self.prop = Proposition.objects.create(name="foo", user=self.user)
def _url(self, rep):
assert rep in Answer.REP_CHOICES
return reverse("propositions:{}".format(rep), args=(self.prop.id,))
def test_anonymous_cannot_get(self):
client = Client()
url = reverse("propositions:oui", args=(self.prop.id,))
response = client.get(url)
self.assertRedirects(response, "/login?next={}".format(url))
url = reverse("propositions:non", args=(self.prop.id,))
response = client.get(url)
self.assertRedirects(response, "/login?next={}".format(url))
def test_ernesto_user_can_get(self):
client = Client()
client.force_login(self.user)
client.get(reverse("propositions:oui", args=(self.prop.id,)))
self.prop.refresh_from_db()
self.assertEqual(
list(self.prop.answer_set.values_list("answer", flat=True)), [Answer.YES],
)
client.get(reverse("propositions:non", args=(self.prop.id,)))
self.prop.refresh_from_db()
self.assertEqual(
list(self.prop.answer_set.values_list("answer", flat=True)), [Answer.NO]
)

View file

@ -1,13 +0,0 @@
from django.urls import path
from propositions import views
from propositions.models import Answer
app_name = "propositions"
urlpatterns = [
path("", views.PropositionList.as_view(), name="list"),
path("new", views.PropositionCreate.as_view(), name="create"),
path("<int:id>/oui", views.answer, {"ans": "oui"}, name=Answer.YES),
path("<int:id>/non", views.answer, {"ans": "non"}, name=Answer.NO),
path("<int:pk>/supprimer", views.PropositionDelete.as_view(), name="delete"),
]

View file

@ -1,8 +0,0 @@
import string
import random
def generer(*args):
caracteres = string.ascii_letters + string.digits
aleatoire = [random.choice(caracteres) for _ in range(6)]
return ''.join(aleatoire)

View file

@ -1,63 +0,0 @@
from django.shortcuts import redirect, get_object_or_404
from django.urls import reverse_lazy
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.db.models import Count, OuterRef, Q, Subquery
from django.views.generic import CreateView, DeleteView, ListView
from django.http import HttpResponseRedirect
from propositions.models import Answer, Proposition
class PropositionCreate(LoginRequiredMixin, CreateView):
template_name = "propositions/create.html"
success_url = reverse_lazy("propositions:list")
model = Proposition
fields = ["name", "artist", "link"]
def form_valid(self, form):
proposition = form.save(commit=False)
proposition.user = self.request.user
proposition.save()
return HttpResponseRedirect(self.success_url)
class PropositionList(LoginRequiredMixin, ListView):
template_name = "propositions/liste.html"
context_object_name = "propositions"
model = Proposition
def get_queryset(self):
user = self.request.user
user_answers = (
Answer.objects
.filter(proposition=OuterRef("id"), user=user)
.values_list("answer", flat=True)
)
return (
Proposition.objects
.annotate(nb_yes=Count("answer", filter=Q(answer__answer=Answer.YES)))
.annotate(nb_no=Count("answer", filter=Q(answer__answer=Answer.NO)))
.annotate(user_answer=Subquery(user_answers[:1]))
.order_by("-nb_yes", "nb_no", "name")
)
class PropositionDelete(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Proposition
template_name = "propositions/delete.html"
success_url = reverse_lazy("propositions:list")
def test_func(self):
proposition = self.get_object()
user = self.request.user
return (proposition.user == user or user.profile.is_chef)
@login_required
def answer(request, id, ans):
proposition = get_object_or_404(Proposition, id=id)
user = request.user
Answer.objects.filter(proposition=proposition, user=user).delete()
Answer.objects.create(proposition=proposition, user=user, answer=ans)
return redirect("propositions:list")

View file

@ -1,8 +1,8 @@
Django==2.2.28
django-appconf==1.0.4
django-avatar==5.0.0
django-colorful==1.3
gunicorn==20.1.0
Pillow==9.2.0
#Pour le prod
#psycopg2==2.8.6
Django==2.2.*
# Pour la prod
#psycopg2
gunicorn
django-colorful
Pillow
django-avatar==5.0.*