Topic reviewers are User instead of Participation
This commit is contained in:
parent
c555859896
commit
b214ba448c
|
@ -3,10 +3,12 @@ from django.forms.models import modelform_factory
|
||||||
|
|
||||||
from proposals.models import Talk, Topic
|
from proposals.models import Talk, Topic
|
||||||
|
|
||||||
__all__ = ['TalkForm', 'TopicForm']
|
__all__ = ['TalkForm', 'TopicCreateForm', 'TopicUpdateForm']
|
||||||
|
|
||||||
|
|
||||||
TalkForm = modelform_factory(Talk, fields=['title', 'description', 'topics', 'event', 'speakers'],
|
TalkForm = modelform_factory(Talk, fields=['title', 'description', 'topics', 'event', 'speakers'],
|
||||||
widgets={'topics': CheckboxSelectMultiple()})
|
widgets={'topics': CheckboxSelectMultiple()})
|
||||||
|
|
||||||
TopicForm = modelform_factory(Topic, fields=['name'])
|
TopicCreateForm = modelform_factory(Topic, fields=['name', 'reviewers'])
|
||||||
|
|
||||||
|
TopicUpdateForm = modelform_factory(Topic, fields=['reviewers'])
|
||||||
|
|
21
proposals/migrations/0005_auto_20160709_1457.py
Normal file
21
proposals/migrations/0005_auto_20160709_1457.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.7 on 2016-07-09 14:57
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('proposals', '0004_auto_20160706_1446'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='topic',
|
||||||
|
name='reviewers',
|
||||||
|
field=models.ManyToManyField(blank=True, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
|
@ -25,7 +25,7 @@ class Topic(PonyConfModel):
|
||||||
name = models.CharField(max_length=128, verbose_name='Name', unique=True)
|
name = models.CharField(max_length=128, verbose_name='Name', unique=True)
|
||||||
slug = AutoSlugField(populate_from='name', unique=True)
|
slug = AutoSlugField(populate_from='name', unique=True)
|
||||||
|
|
||||||
reviewers = models.ManyToManyField(Participation, blank=True)
|
reviewers = models.ManyToManyField(User, blank=True)
|
||||||
|
|
||||||
objects = models.Manager()
|
objects = models.Manager()
|
||||||
on_site = CurrentSiteManager()
|
on_site = CurrentSiteManager()
|
||||||
|
@ -38,7 +38,7 @@ class Topic(PonyConfModel):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('show-topic', kwargs={'slug': self.slug})
|
return reverse('list-talks-by-topic', kwargs={'topic': self.slug})
|
||||||
|
|
||||||
|
|
||||||
class Talk(PonyConfModel):
|
class Talk(PonyConfModel):
|
||||||
|
@ -72,7 +72,7 @@ class Talk(PonyConfModel):
|
||||||
participation = Participation.on_site.get(user=user)
|
participation = Participation.on_site.get(user=user)
|
||||||
except Participation.DoesNotExists:
|
except Participation.DoesNotExists:
|
||||||
return False
|
return False
|
||||||
return participation.orga or self.topics.filter(reviewers=participation).exists()
|
return participation.orga or self.topics.filter(reviewers=participation.user).exists()
|
||||||
|
|
||||||
def is_editable_by(self, user):
|
def is_editable_by(self, user):
|
||||||
return user == self.proposer or user in self.speakers.all() or self.is_moderable_by(user)
|
return user == self.proposer or user in self.speakers.all() or self.is_moderable_by(user)
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal, receiver
|
||||||
|
from django.db.models.signals import m2m_changed
|
||||||
|
|
||||||
|
|
||||||
|
from .models import Topic
|
||||||
|
from accounts.models import Participation
|
||||||
|
|
||||||
|
|
||||||
__all__ = [ 'talk_added', 'talk_edited' ]
|
__all__ = [ 'talk_added', 'talk_edited' ]
|
||||||
|
@ -6,3 +11,11 @@ __all__ = [ 'talk_added', 'talk_edited' ]
|
||||||
|
|
||||||
talk_added = Signal(providing_args=["sender", "instance", "author"])
|
talk_added = Signal(providing_args=["sender", "instance", "author"])
|
||||||
talk_edited = Signal(providing_args=["sender", "instance", "author"])
|
talk_edited = Signal(providing_args=["sender", "instance", "author"])
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(m2m_changed, sender=Topic.reviewers.through, dispatch_uid="Create Participation for reviewers")
|
||||||
|
def create_participation_for_reviewers(sender, instance, action, reverse, model, pk_set, using, **kwargs):
|
||||||
|
if action != "pre_add":
|
||||||
|
pass
|
||||||
|
for reviewer in instance.reviewers.all():
|
||||||
|
Participation.objects.get_or_create(user=reviewer, site=instance.site)
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
{% extends 'base.html' %}
|
|
||||||
|
|
||||||
{% load staticfiles accounts_tags %}
|
|
||||||
|
|
||||||
{% block topictab %} class="active"{% endblock %}
|
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
{{ block.super }}
|
|
||||||
<link rel="stylesheet" href="{% static 'jquery-ui/themes/base/jquery-ui.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'jquery-ui/themes/base/autocomplete.css' %}">
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>{{ topic }}</h1>
|
|
||||||
|
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<a href="{% url 'edit-talk' topic.slug %}">edit</a><br />
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'list-talks-by-topic' topic.slug %}">{{ topic.talks.count }} talk{{ topic.talks.count|pluralize }}</a><br />
|
|
||||||
|
|
||||||
Reviewers:
|
|
||||||
<ul>
|
|
||||||
{% for reviewer in topic.reviewers.all %}
|
|
||||||
<li>
|
|
||||||
{{ reviewer }}
|
|
||||||
{% if request|orga %} - <a href="{% url 'remove-reviewer' topic.slug reviewer.user.username %}">remove</a>{% endif %}
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li><i>No reviewers.</i></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% if request|orga %}
|
|
||||||
<form class="form-inline" method="post" action="{% url 'add-reviewer' topic.slug %}" role="form" id="add-reviewer-form">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="input-group ui-widget">
|
|
||||||
<input type="text" class="form-control" name="user" placeholder="add reviewer" value="">
|
|
||||||
<div class="input-group-addon">
|
|
||||||
<a href="javascript:void(0);" onclick="$('#add-reviewer-form').submit();"><span class="glyphicon glyphicon-plus"></span></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js_end %}
|
|
||||||
{{ block.super }}
|
|
||||||
<script src="{% static 'jquery-ui/ui/minified/core.min.js' %}"></script>
|
|
||||||
<script src="{% static 'jquery-ui/ui/minified/widget.min.js' %}"></script>
|
|
||||||
<script src="{% static 'jquery-ui/ui/minified/position.min.js' %}"></script>
|
|
||||||
<script src="{% static 'jquery-ui/ui/minified/menu.min.js' %}"></script>
|
|
||||||
<script src="{% static 'jquery-ui/ui/minified/autocomplete.min.js' %}"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
$('input[name="user"]').autocomplete({
|
|
||||||
source: "{% url 'add-reviewer' topic.slug %}",
|
|
||||||
onSelect: function (data) {
|
|
||||||
$('input[name="user"]').val(data.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
|
@ -13,13 +13,12 @@
|
||||||
<li>
|
<li>
|
||||||
{% if request|staff %}
|
{% if request|staff %}
|
||||||
{{ topic }}:
|
{{ topic }}:
|
||||||
<a href="{{ topic.get_absolute_url }}">{{ topic.reviewers.count }} reviewer{{ topic.reviewers.count|pluralize }}</a>
|
<a href="{% url 'edit-topic' topic.slug %}">{{ topic.reviewers.count }} reviewer{{ topic.reviewers.count|pluralize }}</a>
|
||||||
and
|
and
|
||||||
<a href="{% url 'list-talks-by-topic' topic.slug %}">{{ topic.talks.count }} talk{{ topic.talks.count|pluralize }}</a>
|
<a href="{{ topic.get_absolute_url }}">{{ topic.talks.count }} talk{{ topic.talks.count|pluralize }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'list-talks-by-topic' topic.slug %}">{{ topic }}</a>
|
<a href="{{ topic.get_absolute_url }}">{{ topic }}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.user.is_superuser %} - <a href="{% url 'edit-topic' topic.slug %}">edit</a>{% endif %}
|
|
||||||
</li>
|
</li>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<li><i>No topics.</i></li>
|
<li><i>No topics.</i></li>
|
||||||
|
|
|
@ -12,10 +12,7 @@ urlpatterns = [
|
||||||
url(r'^talk/by-topic/(?P<topic>[-\w]+)$', views.talk_list_by_topic, name='list-talks-by-topic'),
|
url(r'^talk/by-topic/(?P<topic>[-\w]+)$', views.talk_list_by_topic, name='list-talks-by-topic'),
|
||||||
url(r'^topic/$', views.TopicList.as_view(), name='list-topics'),
|
url(r'^topic/$', views.TopicList.as_view(), name='list-topics'),
|
||||||
url(r'^topic/add/$', views.TopicCreate.as_view(), name='add-topic'),
|
url(r'^topic/add/$', views.TopicCreate.as_view(), name='add-topic'),
|
||||||
url(r'^topic/(?P<slug>[-\w]+)/$', views.TopicDetail.as_view(), name='show-topic'),
|
|
||||||
url(r'^topic/(?P<slug>[-\w]+)/edit/$', views.TopicUpdate.as_view(), name='edit-topic'),
|
url(r'^topic/(?P<slug>[-\w]+)/edit/$', views.TopicUpdate.as_view(), name='edit-topic'),
|
||||||
url(r'^topic/(?P<slug>[-\w]+)/add-reviewer/$', views.topic_add_reviewer, name='add-reviewer'),
|
|
||||||
url(r'^topic/(?P<slug>[-\w]+)/remove-reviewer/(?P<username>[\w.@+-]+)/$', views.topic_remove_reviewer, name='remove-reviewer'),
|
|
||||||
url(r'^speakers/$', views.SpeakerList.as_view(), name='list-speakers'),
|
url(r'^speakers/$', views.SpeakerList.as_view(), name='list-speakers'),
|
||||||
url(r'^speaker/(?P<username>[\w.@+-]+)$', views.user_details, name='show-speaker'),
|
url(r'^speaker/(?P<username>[\w.@+-]+)$', views.user_details, name='show-speaker'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -11,5 +11,5 @@ def query_sum(queryset, field):
|
||||||
def allowed_talks(talks, request):
|
def allowed_talks(talks, request):
|
||||||
participation = Participation.on_site.get(user=request.user)
|
participation = Participation.on_site.get(user=request.user)
|
||||||
if not participation.is_orga():
|
if not participation.is_orga():
|
||||||
talks = talks.filter(Q(topics__reviewers=participation) | Q(speakers=request.user) | Q(proposer=request.user))
|
talks = talks.filter(Q(topics__reviewers=participation.user) | Q(speakers=request.user) | Q(proposer=request.user))
|
||||||
return talks.distinct()
|
return talks.distinct()
|
||||||
|
|
|
@ -15,7 +15,7 @@ from accounts.mixins import OrgaRequiredMixin, StaffRequiredMixin, SuperuserRequ
|
||||||
from accounts.models import Participation
|
from accounts.models import Participation
|
||||||
from accounts.utils import is_orga
|
from accounts.utils import is_orga
|
||||||
|
|
||||||
from .forms import TalkForm, TopicForm
|
from .forms import TalkForm, TopicCreateForm, TopicUpdateForm
|
||||||
from .models import Talk, Topic, Vote
|
from .models import Talk, Topic, Vote
|
||||||
from .utils import allowed_talks
|
from .utils import allowed_talks
|
||||||
from .signals import *
|
from .signals import *
|
||||||
|
@ -86,7 +86,6 @@ class TalkDetail(LoginRequiredMixin, DetailView):
|
||||||
class TopicMixin(object):
|
class TopicMixin(object):
|
||||||
model = Topic
|
model = Topic
|
||||||
queryset = Topic.on_site.all()
|
queryset = Topic.on_site.all()
|
||||||
form_class = TopicForm
|
|
||||||
|
|
||||||
|
|
||||||
class TopicList(LoginRequiredMixin, TopicMixin, ListView):
|
class TopicList(LoginRequiredMixin, TopicMixin, ListView):
|
||||||
|
@ -94,69 +93,15 @@ class TopicList(LoginRequiredMixin, TopicMixin, ListView):
|
||||||
|
|
||||||
|
|
||||||
class TopicCreate(OrgaRequiredMixin, TopicMixin, CreateView):
|
class TopicCreate(OrgaRequiredMixin, TopicMixin, CreateView):
|
||||||
|
form_class = TopicCreateForm
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
form.instance.site = get_current_site(self.request)
|
form.instance.site = get_current_site(self.request)
|
||||||
return super(TopicCreate, self).form_valid(form)
|
return super(TopicCreate, self).form_valid(form)
|
||||||
|
|
||||||
|
|
||||||
class TopicUpdate(SuperuserRequiredMixin, TopicMixin, UpdateView):
|
class TopicUpdate(OrgaRequiredMixin, TopicMixin, UpdateView):
|
||||||
pass
|
def get_form_class(self):
|
||||||
|
return TopicCreateForm if self.request.user.is_superuser else TopicUpdateForm
|
||||||
|
|
||||||
class TopicDetail(StaffRequiredMixin, TopicMixin, DetailView):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def topic_add_reviewer(request, slug):
|
|
||||||
if not Participation.objects.get(user=request.user).is_orga():
|
|
||||||
raise PermissionDenied()
|
|
||||||
|
|
||||||
topic = get_object_or_404(Topic, slug=slug)
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
|
||||||
user = request.POST.get('user')
|
|
||||||
try:
|
|
||||||
user = User.objects.get(username=user)
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
messages.error(request, 'User not found.')
|
|
||||||
else:
|
|
||||||
participation, created = Participation.on_site.get_or_create(user=user, site=get_current_site(request))
|
|
||||||
if participation in topic.reviewers.all():
|
|
||||||
messages.info(request, '%s is already a reviewer of this topic.' % participation)
|
|
||||||
else:
|
|
||||||
topic.reviewers.add(participation)
|
|
||||||
topic.save()
|
|
||||||
messages.success(request, '%s added to reviewers!' % participation)
|
|
||||||
return redirect(topic.get_absolute_url())
|
|
||||||
else:
|
|
||||||
term = request.GET.get('term')
|
|
||||||
if not term:
|
|
||||||
raise Http404()
|
|
||||||
query = Q(username__icontains=term) \
|
|
||||||
| Q(first_name__icontains=term) \
|
|
||||||
| Q(last_name__icontains=term)
|
|
||||||
users = User.objects \
|
|
||||||
.exclude(id__in=topic.reviewers.values('user__id')) \
|
|
||||||
.filter(query)[:10]
|
|
||||||
response = []
|
|
||||||
for user in users:
|
|
||||||
response += [{
|
|
||||||
'label': str(user.profile),
|
|
||||||
'value': user.username,
|
|
||||||
}]
|
|
||||||
return JsonResponse(response, safe=False)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def topic_remove_reviewer(request, slug, username):
|
|
||||||
if not Participation.objects.get(user=request.user).is_orga():
|
|
||||||
raise PermissionDenied()
|
|
||||||
topic = get_object_or_404(Topic, slug=slug)
|
|
||||||
participation = get_object_or_404(Participation, user__username=username)
|
|
||||||
topic.reviewers.remove(participation)
|
|
||||||
messages.success(request, '%s removed from reviewers!' % participation)
|
|
||||||
return redirect(topic.get_absolute_url())
|
|
||||||
|
|
||||||
|
|
||||||
class SpeakerList(StaffRequiredMixin, ListView):
|
class SpeakerList(StaffRequiredMixin, ListView):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user