Various Stuffs
- unified orga forms - unified staff / orga | util / mixin / filter - moved a signal into its signals.py - profile edition now edits User / Profile / Participation - topic can be edited - orga can set topics reviewers - removed view list-talks-by-speaker (his talks appears on his page) - everybody can see topics (template show more stuff the more permissions you have)
This commit is contained in:
parent
ed12a0a214
commit
d9b3846cf1
|
@ -3,13 +3,16 @@ from django.forms.models import modelform_factory
|
|||
|
||||
from .models import Participation, Profile
|
||||
|
||||
__all__ = ['UserForm', 'ProfileForm', 'ProfileOrgaForm']
|
||||
__all__ = ['UserForm', 'ProfileForm', 'ProfileOrgaForm', 'ParticipationOrgaForm']
|
||||
|
||||
|
||||
UserForm = modelform_factory(User, fields=['first_name', 'last_name', 'email', 'username'])
|
||||
|
||||
ParticipationForm = modelform_factory(Participation, fields=['transport', 'connector', 'sound', 'constraints'])
|
||||
|
||||
ProfileForm = modelform_factory(Profile, fields=['biography'])
|
||||
|
||||
ParticipationForm = modelform_factory(Participation, fields=['transport', 'connector', 'sound', 'constraints'])
|
||||
|
||||
ProfileOrgaForm = modelform_factory(Profile, fields=['biography', 'notes'])
|
||||
|
||||
ParticipationOrgaForm = modelform_factory(Participation,
|
||||
fields=['transport', 'connector', 'sound', 'constraints', 'orga'])
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
from django.contrib.auth.mixins import UserPassesTestMixin
|
||||
|
||||
from .utils import is_staff
|
||||
from .utils import is_orga, is_staff
|
||||
|
||||
|
||||
class OrgaRequiredMixin(UserPassesTestMixin):
|
||||
def test_func(self):
|
||||
return is_orga(self.request, self.request.user)
|
||||
|
||||
|
||||
class StaffRequiredMixin(UserPassesTestMixin):
|
||||
|
|
|
@ -59,10 +59,3 @@ class Participation(PonyConfModel):
|
|||
|
||||
def is_staff(self):
|
||||
return self.user.is_superuser or self.orga or self.topic_set.exists()
|
||||
|
||||
|
||||
def create_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
Profile.objects.create(user=instance)
|
||||
|
||||
models.signals.post_save.connect(create_profile, sender=User, weak=False, dispatch_uid='create_profile')
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.signals import user_logged_in, user_logged_out
|
||||
from django.contrib.sites.shortcuts import get_current_site
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from .models import Participation
|
||||
from .models import Participation, Profile
|
||||
|
||||
|
||||
@receiver(user_logged_in)
|
||||
|
@ -17,3 +19,10 @@ def on_user_logged_in(sender, request, user, **kwargs):
|
|||
@receiver(user_logged_out)
|
||||
def on_user_logged_out(sender, request, **kwargs):
|
||||
messages.success(request, 'Goodbye!', fail_silently=True) # FIXME
|
||||
|
||||
|
||||
def create_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
Profile.objects.create(user=instance)
|
||||
|
||||
post_save.connect(create_profile, sender=User, weak=False, dispatch_uid='create_profile')
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
from django import template
|
||||
|
||||
from accounts.utils import can_edit_profile, is_staff
|
||||
from accounts.utils import can_edit_profile, is_orga, is_staff
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def orga(request):
|
||||
return is_orga(request, request.user)
|
||||
|
||||
|
||||
@register.filter
|
||||
def staff(request):
|
||||
return is_staff(request, request.user)
|
||||
|
|
|
@ -58,5 +58,8 @@ class AccountTests(TestCase):
|
|||
{'biography': 'foo', 'nootes': 'bar'}).status_code, 200)
|
||||
self.assertEqual(User.objects.get(username='a').profile.biography, '')
|
||||
self.assertEqual(self.client.post(reverse('edit-participant', kwargs={'username': 'a'}),
|
||||
{'biography': 'foo', 'notes': 'bar'}).status_code, 200)
|
||||
{'biography': 'foo', 'notes': 'bar', 'first_name': 'Jules', 'username': 'a',
|
||||
'last_name': 'César', 'email': 'a@example.org', 'transport': 1,
|
||||
'connector': 1, 'constraints': 'nope', 'orga': 0,
|
||||
}).status_code, 200)
|
||||
self.assertEqual(User.objects.get(username='a').profile.biography, 'foo')
|
||||
|
|
|
@ -6,6 +6,10 @@ def generate_user_uid():
|
|||
return get_random_string(length=12, allowed_chars='abcdefghijklmnopqrstuvwxyz0123456789')
|
||||
|
||||
|
||||
def is_orga(request, user):
|
||||
return user.is_authenticated() and user.participation_set.get(site=get_current_site(request)).orga
|
||||
|
||||
|
||||
def is_staff(request, user):
|
||||
return user.is_authenticated() and user.participation_set.get(site=get_current_site(request)).is_staff()
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ from django.views.generic import ListView
|
|||
|
||||
from registration.backends.default.views import RegistrationView
|
||||
|
||||
from .forms import ParticipationForm, ProfileForm, ProfileOrgaForm, UserForm
|
||||
from .forms import ParticipationForm, ParticipationOrgaForm, ProfileForm, ProfileOrgaForm, UserForm
|
||||
from .mixins import StaffRequiredMixin
|
||||
from .models import Participation, Profile
|
||||
from .utils import can_edit_profile
|
||||
from .utils import can_edit_profile, is_orga
|
||||
|
||||
RESET_PASSWORD_BUTTON = ('password_reset', 'warning', 'Reset your password')
|
||||
CHANGE_PASSWORD_BUTTON = ('password_change', 'warning', 'Change password')
|
||||
|
@ -49,13 +49,17 @@ def edit(request, username):
|
|||
if not can_edit_profile(request, profile):
|
||||
raise PermissionDenied()
|
||||
|
||||
form = ProfileOrgaForm(request.POST or None, instance=profile)
|
||||
participation_form_class = ParticipationOrgaForm if is_orga(request, request.user) else ParticipationForm
|
||||
forms = [UserForm(request.POST or None, instance=profile.user),
|
||||
ProfileOrgaForm(request.POST or None, instance=profile),
|
||||
participation_form_class(request.POST or None, instance=Participation.on_site.get(user=profile.user))]
|
||||
|
||||
if request.method == 'POST':
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
if all(form.is_valid() for form in forms):
|
||||
for form in forms:
|
||||
form.save()
|
||||
messages.success(request, 'Profile updated successfully.')
|
||||
else:
|
||||
messages.error(request, 'Please correct those errors.')
|
||||
|
||||
return render(request, 'accounts/edit_profile.html', {'form': form, 'profile': profile})
|
||||
return render(request, 'accounts/edit_profile.html', {'forms': forms, 'profile': profile})
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
- [ ] virer l’username
|
||||
- [ ] premier login -> redirection profile
|
||||
- [x] premier login -> redirection profile
|
||||
- [x] temps prévu (20 min / 40 min)
|
||||
- [x] proposer des talks pour les autres
|
||||
- [ ] gestion staff
|
||||
- [x] gestion staff
|
||||
- [x] autre couleur change password
|
||||
- [x] 3ième formulaire profile pour les infos de participation
|
||||
- [x] changer le widget des topics pour des cases à cocher
|
||||
|
@ -15,7 +15,7 @@
|
|||
- [ ] notif modification conf …
|
||||
- [x] modif de conf : pas de modifs des topics
|
||||
- [x] rajouter les created sur un peu tous les modèles
|
||||
- [ ] UI reviewers (pour le staff pour nommer des reviewers)
|
||||
- [x] UI reviewers (pour le staff pour nommer des reviewers)
|
||||
- [x] topic : permettre au staff d’en rajouter
|
||||
- [x] topic : qui est reviewer
|
||||
- [x] visibilité des talks
|
|
@ -1,10 +1,14 @@
|
|||
from django.forms import CheckboxSelectMultiple
|
||||
from django.forms.models import modelform_factory
|
||||
|
||||
from proposals.models import Talk
|
||||
from proposals.models import Talk, Topic
|
||||
|
||||
__all__ = ['TalkForm']
|
||||
__all__ = ['TalkForm', 'TopicForm', 'TopicOrgaForm']
|
||||
|
||||
|
||||
TalkForm = modelform_factory(Talk, fields=['title', 'description', 'topics', 'event', 'speakers'],
|
||||
widgets={'topics': CheckboxSelectMultiple()})
|
||||
|
||||
TopicForm = modelform_factory(Topic, fields=['name'])
|
||||
|
||||
TopicOrgaForm = modelform_factory(Topic, fields=['name', 'reviewers'])
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
<h1>Speakers:</h1>
|
||||
|
||||
<ul>
|
||||
{% for speaker in user_list %}
|
||||
<li><a href="{% url 'show-speaker' username=speaker.username %}">{{ speaker }}</a></li>
|
||||
{% for speaker in participation_list %}
|
||||
<li><a href="{% url 'show-speaker' username=speaker.user.username %}">{{ speaker }}</a></li>
|
||||
{% empty %}
|
||||
<li><i>No speakers.</i></li>
|
||||
{% endfor %}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
{% block content %}
|
||||
|
||||
<h1>Propose a Topic</h1>
|
||||
<h1>Topic</h1>
|
||||
|
||||
{% include "_form.html" %}
|
||||
|
||||
|
|
|
@ -10,8 +10,13 @@
|
|||
|
||||
<ul>
|
||||
{% for topic in topic_list %}
|
||||
<li>{{ topic.get_link }}{% if request|staff %} ({% for reviewer in topic.reviewers.all %}
|
||||
{{ reviewer.get_link }}{% if not forloop.last %}, {% endif %}{% endfor %} ){% endif %}</li>
|
||||
<li>
|
||||
{{ topic.get_link }}
|
||||
{% if request|staff %} ({% for reviewer in topic.reviewers.all %} {{ reviewer.get_link }}
|
||||
{% if not forloop.last %}, {% endif %}{% endfor %} )
|
||||
{% if request|orga %} - <a href="{% url 'edit-topic' topic.slug %}">edit</a>{% endif %}
|
||||
{% endif %}
|
||||
</li>
|
||||
{% empty %}
|
||||
<li><i>No topic.</i></li>
|
||||
{% endfor %}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<p>{{ profile.biography }}</p>
|
||||
|
||||
<h2>Talks</h2>
|
||||
<a href="{% url 'list-talks-by-speaker' profile.user.username %}">See the list of talks with this speaker</a>
|
||||
{% include "proposals/_talk_list.html" %}
|
||||
|
||||
{% if request|edit_profile:profile %}
|
||||
<h2>Notes</h2>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
from django.contrib.auth.models import User
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
|
||||
|
@ -11,7 +10,6 @@ from .models import Talk, Topic, Vote
|
|||
class ProposalsTests(TestCase):
|
||||
def setUp(self):
|
||||
a, b, c = (User.objects.create_user(guy, email='%s@example.org' % guy, password=guy) for guy in 'abc')
|
||||
Participation.objects.create(user=a, site=Site.objects.first())
|
||||
Topic.objects.create(name='topipo')
|
||||
c.is_superuser = True
|
||||
c.save()
|
||||
|
@ -35,7 +33,6 @@ class ProposalsTests(TestCase):
|
|||
self.assertEqual(self.client.get(reverse(view)).status_code, 302 if view == 'list-speakers' else 200)
|
||||
self.assertEqual(self.client.get(reverse('edit-talk', kwargs={'talk': talk.slug})).status_code, 200)
|
||||
self.assertEqual(self.client.get(reverse('show-talk', kwargs={'slug': talk.slug})).status_code, 200)
|
||||
self.assertEqual(self.client.get(reverse('list-talks-by-speaker', kwargs={'speaker': 'a'})).status_code, 200)
|
||||
self.assertEqual(self.client.get(reverse('show-speaker', kwargs={'username': 'a'})).status_code, 200)
|
||||
|
||||
self.client.login(username='b', password='b')
|
||||
|
@ -66,3 +63,10 @@ class ProposalsTests(TestCase):
|
|||
{'title': 'mega talk', 'description': 'mega', 'event': 1, 'speakers': "2,1"})
|
||||
self.assertTrue(talk.is_editable_by(b))
|
||||
self.assertFalse(talk.is_moderable_by(b))
|
||||
|
||||
# Only orga can edit topics
|
||||
self.client.login(username='c', password='c')
|
||||
self.assertEqual(self.client.get(reverse('edit-topic', kwargs={'slug': 'topipo'})).status_code, 302)
|
||||
Participation.on_site.filter(user=c).update(orga=True)
|
||||
self.assertEqual(self.client.get(reverse('edit-topic', kwargs={'slug': 'topipo'})).status_code, 200)
|
||||
self.assertEqual(self.client.get(reverse('list-topics')).status_code, 200)
|
||||
|
|
|
@ -10,9 +10,9 @@ urlpatterns = [
|
|||
url(r'^talk/vote/(?P<talk>[-\w]+)/(?P<score>[-0-2]+)$', views.vote, name='vote'),
|
||||
url(r'^talk/details/(?P<slug>[-\w]+)$', views.TalkDetail.as_view(), name='show-talk'),
|
||||
url(r'^talk/by-topic/(?P<topic>[-\w]+)$', views.talk_list_by_topic, name='list-talks-by-topic'),
|
||||
url(r'^talk/by-speaker/(?P<speaker>[\w.@+-]+)$', views.talk_list_by_speaker, name='list-talks-by-speaker'),
|
||||
url(r'^topic/$', views.TopicList.as_view(), name='list-topics'),
|
||||
url(r'^topic/add/$', views.TopicCreate.as_view(), name='add-topic'),
|
||||
url(r'^topic/edit/(?P<slug>[-\w]+)/$', views.TopicUpdate.as_view(), name='edit-topic'),
|
||||
url(r'^speakers/$', views.SpeakerList.as_view(), name='list-speakers'),
|
||||
url(r'^speaker/(?P<username>[\w.@+-]+)$', views.user_details, name='show-speaker'),
|
||||
]
|
||||
|
|
|
@ -12,4 +12,4 @@ def allowed_talks(talks, request):
|
|||
participation = Participation.on_site.get(user=request.user)
|
||||
if not participation.orga:
|
||||
talks = talks.filter(Q(topics__reviewers=participation) | Q(speakers=request.user) | Q(proposer=request.user))
|
||||
return talks
|
||||
return talks.distinct()
|
||||
|
|
|
@ -7,12 +7,13 @@ from django.core.exceptions import PermissionDenied
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.views.generic import CreateView, DetailView, ListView
|
||||
from django.views.generic import CreateView, DetailView, ListView, UpdateView
|
||||
|
||||
from accounts.mixins import StaffRequiredMixin
|
||||
from accounts.mixins import OrgaRequiredMixin, StaffRequiredMixin
|
||||
from accounts.models import Participation
|
||||
from accounts.utils import is_orga
|
||||
|
||||
from .forms import TalkForm
|
||||
from .forms import TalkForm, TopicForm, TopicOrgaForm
|
||||
from .models import Talk, Topic, Vote
|
||||
from .signals import new_talk
|
||||
from .utils import allowed_talks
|
||||
|
@ -25,7 +26,7 @@ def home(request):
|
|||
@login_required
|
||||
def talk_list(request):
|
||||
return render(request, 'proposals/talks.html', {
|
||||
'my_talks': Talk.on_site.filter(Q(speakers=request.user) | Q(proposer=request.user)),
|
||||
'my_talks': Talk.on_site.filter(Q(speakers=request.user) | Q(proposer=request.user)).distinct(),
|
||||
'other_talks': allowed_talks(Talk.on_site.exclude(speakers=request.user, proposer=request.user), request)
|
||||
})
|
||||
|
||||
|
@ -37,13 +38,6 @@ def talk_list_by_topic(request, topic):
|
|||
return render(request, 'proposals/talk_list.html', {'title': 'Talks related to %s:' % topic, 'talk_list': talks})
|
||||
|
||||
|
||||
@login_required
|
||||
def talk_list_by_speaker(request, speaker):
|
||||
speaker = get_object_or_404(User, username=speaker)
|
||||
talks = allowed_talks(Talk.on_site.filter(speakers=speaker), request)
|
||||
return render(request, 'proposals/talk_list.html', {'title': 'Talks with %s:' % speaker, 'talk_list': talks})
|
||||
|
||||
|
||||
@login_required
|
||||
def talk_edit(request, talk=None):
|
||||
if talk:
|
||||
|
@ -86,17 +80,27 @@ class TalkDetail(LoginRequiredMixin, DetailView):
|
|||
return super().get_context_data(**ctx)
|
||||
|
||||
|
||||
class TopicList(LoginRequiredMixin, ListView):
|
||||
class TopicList(ListView):
|
||||
model = Topic
|
||||
|
||||
|
||||
class TopicCreate(StaffRequiredMixin, CreateView):
|
||||
class TopicMixin(object):
|
||||
model = Topic
|
||||
fields = ['name']
|
||||
|
||||
def get_form_class(self):
|
||||
return TopicOrgaForm if is_orga(self.request, self.request.user) else TopicForm
|
||||
|
||||
|
||||
class TopicCreate(StaffRequiredMixin, TopicMixin, CreateView):
|
||||
pass
|
||||
|
||||
|
||||
class TopicUpdate(OrgaRequiredMixin, TopicMixin, UpdateView):
|
||||
pass
|
||||
|
||||
|
||||
class SpeakerList(StaffRequiredMixin, ListView):
|
||||
queryset = User.objects.filter(talk__in=Talk.on_site.all()).distinct()
|
||||
queryset = Participation.on_site.filter(user__talk__in=Talk.on_site.all()).distinct()
|
||||
template_name = 'proposals/speaker_list.html'
|
||||
|
||||
|
||||
|
@ -116,6 +120,8 @@ def vote(request, talk, score):
|
|||
|
||||
@login_required
|
||||
def user_details(request, username):
|
||||
speaker = get_object_or_404(User, username=username)
|
||||
return render(request, 'proposals/user_details.html', {
|
||||
'profile': get_object_or_404(User, username=username).profile,
|
||||
'profile': speaker.profile,
|
||||
'talk_list': allowed_talks(Talk.on_site.filter(speakers=speaker), request),
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue