Reorganize views for better clarity. Add editing capabilities for Info Items.

This commit is contained in:
Víðir Valberg Guðmundsson 2018-05-05 00:19:24 +02:00
parent 735f17b1f1
commit b668ac0694
11 changed files with 249 additions and 88 deletions

View file

@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
from reversion.admin import VersionAdmin
from .models import ( from .models import (
InfoItem, InfoItem,
InfoCategory InfoCategory
@ -6,7 +7,7 @@ from .models import (
@admin.register(InfoItem) @admin.register(InfoItem)
class InfoItemAdmin(admin.ModelAdmin): class InfoItemAdmin(VersionAdmin):
list_filter = ['category', 'category__camp',] list_filter = ['category', 'category__camp',]
list_display = ['headline',] list_display = ['headline',]

View file

@ -37,6 +37,7 @@ class InfoCategory(CampRelatedModel):
blank=True, blank=True,
help_text='The team responsible for this info category.', help_text='The team responsible for this info category.',
on_delete=models.PROTECT, on_delete=models.PROTECT,
related_name='info_categories'
) )
def clean(self): def clean(self):

View file

@ -109,6 +109,9 @@ class Team(CampRelatedModel):
def __str__(self): def __str__(self):
return '{} ({})'.format(self.name, self.camp) return '{} ({})'.format(self.name, self.camp)
def get_absolute_url(self):
return reverse_lazy('teams:detail', kwargs={'camp_slug': self.camp.slug, 'team_slug': self.slug})
def save(self, **kwargs): def save(self, **kwargs):
# generate slug if needed # generate slug if needed
if not self.pk or not self.slug: if not self.pk or not self.slug:

View file

@ -0,0 +1,35 @@
{% extends 'base.html' %}
{% load commonmark %}
{% load bootstrap3 %}
{% block title %}
{% if form.instance.id %}
Edit Info Item: {{ form.instance.headline }}
{% else %}
Create Info item
{% endif %}
for in {{ form.instance.category.headline }}
{% endblock %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">
<h4>
{% if form.instance.id %}
Edit Info Item: {{ form.instance.name }}
{% else %}
Create Info Item
{% endif %}
for in {{ form.instance.category.headline }}
</h4>
</div>
<div class="panel-body">
<form method="POST">
{% csrf_token %}
{% bootstrap_form form %}
<button type="submit" class="btn btn-primary">{% if form.instance.id %}Save{% else %}Create{% endif %}</button>
</form>
</div>
<div class="panel-footer"><i>This info item belongs to the <a href="{% url 'teams:detail' team_slug=team.slug camp_slug=team.camp.slug %}">{{ team.name }} Team</a></i></div>
</div>
{% endblock %}

View file

@ -115,6 +115,41 @@ Team: {{ team.name }} | {{ block.super }}
{% if request.user in team.responsible_members.all %} {% if request.user in team.responsible_members.all %}
<a href="{% url 'teams:task_create' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fa fa-plus"></i> Create Task</a> <a href="{% url 'teams:task_create' camp_slug=camp.slug team_slug=team.slug %}" class="btn btn-primary"><i class="fa fa-plus"></i> Create Task</a>
{% endif %} {% endif %}
{# Team info categories section - only visible for team responsible #}
{% if request.user in team.responsible_members.all %}
<hr />
<h4>Info categories</h4>
{% for info_category in team.info_categories.all %}
{{ info_category.headline }}
<table class="table table-hover">
<thead>
<tr>
<th>Item name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for item in info_category.infoitems.all %}
<tr>
<td>{{ item.headline }}</td>
<td>
<a href="{% url 'teams:info_item_update' camp_slug=camp.slug team_slug=team.slug anchor=item.anchor %}"
class="btn btn-primary btn-sm">
<i class="fa fa-edit"></i> Edit Task
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% endif %}
</div> </div>
</div> </div>

View file

@ -1,6 +1,22 @@
from django.conf.urls import url, include from django.conf.urls import url, include
from .views import *
from teams.views.base import (
TeamListView,
TeamMemberRemoveView,
TeamMemberApproveView,
TeamDetailView,
TeamJoinView,
TeamLeaveView,
TeamManageView,
FixIrcAclView,
)
from teams.views.info import InfoItemUpdateView
from teams.views.tasks import (
TaskCreateView,
TaskDetailView,
TaskUpdateView,
)
app_name = 'teams' app_name = 'teams'
@ -75,6 +91,24 @@ urlpatterns = [
]), ]),
), ),
url(
r'^info_items/', include([
url(
r'^(?P<anchor>[-_\w+]+)/', include([
# url(
# r'^$',
# TaskDetailView.as_view(),
# name='task_detail',
# ),
url(
r'^update/$',
InfoItemUpdateView.as_view(),
name='info_item_update',
),
]),
),
])
)
]), ]),
), ),
] ]

View file

View file

@ -1,52 +1,22 @@
from django.views.generic import ListView, DetailView from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView from django.views.generic.edit import UpdateView
from camps.mixins import CampViewMixin from camps.mixins import CampViewMixin
from .models import Team, TeamMember, TeamTask
from .email import add_added_membership_email, add_removed_membership_email
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import redirect from django.shortcuts import redirect
from django.contrib import messages from django.contrib import messages
from django.http import HttpResponseRedirect
from django.views.generic.detail import SingleObjectMixin
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.conf import settings from django.conf import settings
from profiles.models import Profile from profiles.models import Profile
from .mixins import EnsureTeamResponsibleMixin, EnsureTeamMemberResponsibleMixin
from ..models import Team, TeamMember
from ..email import add_added_membership_email, add_removed_membership_email
import logging import logging
logger = logging.getLogger("bornhack.%s" % __name__) logger = logging.getLogger("bornhack.%s" % __name__)
class EnsureTeamResponsibleMixin(object):
"""
Use to make sure request.user is responsible for the team specified by kwargs['team_slug']
"""
def dispatch(self, request, *args, **kwargs):
self.team = Team.objects.get(slug=kwargs['team_slug'], camp=self.camp)
if request.user not in self.team.responsible_members.all():
messages.error(request, 'No thanks')
return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=self.team.slug)
return super().dispatch(
request, *args, **kwargs
)
class EnsureTeamMemberResponsibleMixin(SingleObjectMixin):
"""
Use to make sure request.user is responsible for the team which TeamMember belongs to
"""
model = TeamMember
def dispatch(self, request, *args, **kwargs):
if request.user not in self.get_object().team.responsible_members.all():
messages.error(request, 'No thanks')
return redirect('teams:detail', camp_slug=self.get_object().team.camp.slug, team_slug=self.get_object().team.slug)
return super().dispatch(
request, *args, **kwargs
)
class TeamListView(CampViewMixin, ListView): class TeamListView(CampViewMixin, ListView):
template_name = "team_list.html" template_name = "team_list.html"
model = Team model = Team
@ -165,56 +135,6 @@ class TeamMemberApproveView(LoginRequiredMixin, CampViewMixin, EnsureTeamMemberR
return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=form.instance.team.slug) return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=form.instance.team.slug)
class TaskDetailView(CampViewMixin, DetailView):
template_name = "task_detail.html"
context_object_name = "task"
model = TeamTask
class TaskCreateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, CreateView):
model = TeamTask
template_name = "task_form.html"
fields = ['name', 'description']
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['team'] = self.team
return context
def form_valid(self, form):
task = form.save(commit=False)
task.team = self.team
if not task.name:
task.name = "noname"
task.save()
return HttpResponseRedirect(task.get_absolute_url())
def get_success_url(self):
return self.get_object().get_absolute_url()
class TaskUpdateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, UpdateView):
model = TeamTask
template_name = "task_form.html"
fields = ['name', 'description']
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['team'] = self.team
return context
def form_valid(self, form):
task = form.save(commit=False)
task.team = self.team
if not task.name:
task.name = "noname"
task.save()
return HttpResponseRedirect(task.get_absolute_url())
def get_success_url(self):
return self.get_object().get_absolute_url()
class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView): class FixIrcAclView(LoginRequiredMixin, CampViewMixin, UpdateView):
template_name = "fix_irc_acl.html" template_name = "fix_irc_acl.html"
model = Team model = Team

39
src/teams/views/info.py Normal file
View file

@ -0,0 +1,39 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView, UpdateView
from reversion.views import RevisionMixin
from camps.mixins import CampViewMixin
from info.models import InfoItem
from teams.views.mixins import EnsureTeamResponsibleMixin
class InfoItemCreateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, CreateView):
model = InfoItem
template_name = "info_item_form.html"
fields = ['headline', 'body', 'anchor', 'weight']
slug_field = 'anchor'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['team'] = self.object.category.team
return context
def get_success_url(self):
return self.object.category.team.get_absolute_url()
class InfoItemUpdateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, RevisionMixin, UpdateView):
model = InfoItem
template_name = "info_item_form.html"
fields = ['headline', 'body', 'anchor', 'weight']
slug_field = 'anchor'
slug_url_kwarg = 'anchor'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['team'] = self.object.category.team
return context
def get_success_url(self):
return self.object.category.team.get_absolute_url()

36
src/teams/views/mixins.py Normal file
View file

@ -0,0 +1,36 @@
from django.contrib import messages
from django.shortcuts import redirect
from django.views.generic.detail import SingleObjectMixin
from teams.models import Team, TeamMember
class EnsureTeamResponsibleMixin(object):
"""
Use to make sure request.user is responsible for the team specified by kwargs['team_slug']
"""
def dispatch(self, request, *args, **kwargs):
self.team = Team.objects.get(slug=kwargs['team_slug'], camp=self.camp)
if request.user not in self.team.responsible_members.all():
messages.error(request, 'No thanks')
return redirect('teams:detail', camp_slug=self.camp.slug, team_slug=self.team.slug)
return super().dispatch(
request, *args, **kwargs
)
class EnsureTeamMemberResponsibleMixin(SingleObjectMixin):
"""
Use to make sure request.user is responsible for the team which TeamMember belongs to
"""
model = TeamMember
def dispatch(self, request, *args, **kwargs):
if request.user not in self.get_object().team.responsible_members.all():
messages.error(request, 'No thanks')
return redirect('teams:detail', camp_slug=self.get_object().team.camp.slug, team_slug=self.get_object().team.slug)
return super().dispatch(
request, *args, **kwargs
)

57
src/teams/views/tasks.py Normal file
View file

@ -0,0 +1,57 @@
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.views.generic import DetailView, CreateView, UpdateView
from camps.mixins import CampViewMixin
from ..models import TeamTask
from .mixins import EnsureTeamResponsibleMixin
class TaskDetailView(CampViewMixin, DetailView):
template_name = "task_detail.html"
context_object_name = "task"
model = TeamTask
class TaskCreateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, CreateView):
model = TeamTask
template_name = "task_form.html"
fields = ['name', 'description']
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['team'] = self.team
return context
def form_valid(self, form):
task = form.save(commit=False)
task.team = self.team
if not task.name:
task.name = "noname"
task.save()
return HttpResponseRedirect(task.get_absolute_url())
def get_success_url(self):
return self.get_object().get_absolute_url()
class TaskUpdateView(LoginRequiredMixin, CampViewMixin, EnsureTeamResponsibleMixin, UpdateView):
model = TeamTask
template_name = "task_form.html"
fields = ['name', 'description']
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(**kwargs)
context['team'] = self.team
return context
def form_valid(self, form):
task = form.save(commit=False)
task.team = self.team
if not task.name:
task.name = "noname"
task.save()
return HttpResponseRedirect(task.get_absolute_url())
def get_success_url(self):
return self.get_object().get_absolute_url()