Reorganize views for better clarity. Add editing capabilities for Info Items.
This commit is contained in:
parent
735f17b1f1
commit
b668ac0694
|
@ -1,4 +1,5 @@
|
|||
from django.contrib import admin
|
||||
from reversion.admin import VersionAdmin
|
||||
from .models import (
|
||||
InfoItem,
|
||||
InfoCategory
|
||||
|
@ -6,7 +7,7 @@ from .models import (
|
|||
|
||||
|
||||
@admin.register(InfoItem)
|
||||
class InfoItemAdmin(admin.ModelAdmin):
|
||||
class InfoItemAdmin(VersionAdmin):
|
||||
list_filter = ['category', 'category__camp',]
|
||||
list_display = ['headline',]
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ class InfoCategory(CampRelatedModel):
|
|||
blank=True,
|
||||
help_text='The team responsible for this info category.',
|
||||
on_delete=models.PROTECT,
|
||||
related_name='info_categories'
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
|
|
|
@ -109,6 +109,9 @@ class Team(CampRelatedModel):
|
|||
def __str__(self):
|
||||
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):
|
||||
# generate slug if needed
|
||||
if not self.pk or not self.slug:
|
||||
|
|
35
src/teams/templates/info_item_form.html
Normal file
35
src/teams/templates/info_item_form.html
Normal 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 %}
|
|
@ -115,6 +115,41 @@ Team: {{ team.name }} | {{ block.super }}
|
|||
{% 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>
|
||||
{% 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>
|
||||
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
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'
|
||||
|
||||
|
@ -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',
|
||||
),
|
||||
]),
|
||||
),
|
||||
])
|
||||
)
|
||||
]),
|
||||
),
|
||||
]
|
||||
|
|
0
src/teams/views/__init__.py
Normal file
0
src/teams/views/__init__.py
Normal file
|
@ -1,52 +1,22 @@
|
|||
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 .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.shortcuts import redirect
|
||||
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.conf import settings
|
||||
|
||||
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
|
||||
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):
|
||||
template_name = "team_list.html"
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
template_name = "fix_irc_acl.html"
|
||||
model = Team
|
39
src/teams/views/info.py
Normal file
39
src/teams/views/info.py
Normal 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
36
src/teams/views/mixins.py
Normal 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
57
src/teams/views/tasks.py
Normal 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()
|
Loading…
Reference in a new issue