diff --git a/src/teams/admin.py b/src/teams/admin.py
index 54f32c9d..c56d48de 100644
--- a/src/teams/admin.py
+++ b/src/teams/admin.py
@@ -1,8 +1,18 @@
from django.contrib import admin
-from .models import Team, TeamArea, TeamMember
+from .models import Team, TeamArea, TeamMember, TeamTask
from .email import add_added_membership_email, add_removed_membership_email
+@admin.register(TeamTask)
+class TeamTaskAdmin(admin.ModelAdmin):
+ list_display = [
+ 'id',
+ 'team',
+ 'name',
+ 'description',
+ ]
+
+
@admin.register(Team)
class TeamAdmin(admin.ModelAdmin):
def get_responsible(self, obj):
diff --git a/src/teams/migrations/0017_auto_20171122_1928.py b/src/teams/migrations/0017_auto_20171122_1928.py
new file mode 100644
index 00000000..fd093ea9
--- /dev/null
+++ b/src/teams/migrations/0017_auto_20171122_1928.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-11-22 18:28
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('teams', '0016_auto_20170711_2247'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TeamTask',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ('updated', models.DateTimeField(auto_now=True)),
+ ('name', models.CharField(help_text='Short name of this task', max_length=100)),
+ ('slug', models.SlugField(blank=True, help_text='url slug, leave blank to autogenerate', max_length=255)),
+ ('description', models.TextField(help_text='Description of the task. Markdown is supported.')),
+ ('team', models.ForeignKey(help_text='The team this task belongs to', on_delete=django.db.models.deletion.CASCADE, to='teams.Team')),
+ ],
+ options={
+ 'ordering': ['name'],
+ },
+ ),
+ migrations.AlterUniqueTogether(
+ name='teamtask',
+ unique_together=set([('slug', 'team'), ('name', 'team')]),
+ ),
+ ]
diff --git a/src/teams/migrations/0018_auto_20171122_2204.py b/src/teams/migrations/0018_auto_20171122_2204.py
new file mode 100644
index 00000000..d1a727f8
--- /dev/null
+++ b/src/teams/migrations/0018_auto_20171122_2204.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-11-22 21:04
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('teams', '0017_auto_20171122_1928'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='teamtask',
+ name='team',
+ field=models.ForeignKey(help_text='The team this task belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to='teams.Team'),
+ ),
+ ]
diff --git a/src/teams/models.py b/src/teams/models.py
index 21016777..5b30a123 100644
--- a/src/teams/models.py
+++ b/src/teams/models.py
@@ -115,3 +115,38 @@ def add_responsible_email(sender, instance, created, **kwargs):
if created:
if not add_new_membership_email(instance):
logger.error('Error adding email to outgoing queue')
+
+
+class TeamTask(CampRelatedModel):
+ team = models.ForeignKey(
+ 'teams.Team',
+ related_name='tasks',
+ help_text='The team this task belongs to',
+ )
+ name = models.CharField(
+ max_length=100,
+ help_text='Short name of this task',
+ )
+ slug = models.SlugField(
+ max_length=255,
+ blank=True,
+ help_text='url slug, leave blank to autogenerate',
+ )
+ description = models.TextField(
+ help_text='Description of the task. Markdown is supported.'
+ )
+
+ class Meta:
+ ordering = ['name']
+ unique_together = (('name', 'team'), ('slug', 'team'))
+
+ @property
+ def camp(self):
+ return self.team.camp
+
+ def save(self, **kwargs):
+ if not self.slug:
+ slug = slugify(self.name)
+ self.slug = slug
+ super().save(**kwargs)
+
diff --git a/src/teams/templates/task_detail.html b/src/teams/templates/task_detail.html
new file mode 100644
index 00000000..4de2715a
--- /dev/null
+++ b/src/teams/templates/task_detail.html
@@ -0,0 +1,17 @@
+{% extends 'base.html' %}
+{% load commonmark %}
+
+{% block title %}
+{{ task.name }}
+{% endblock %}
+
+{% block content %}
+
+
Task: {{ task.name }}
+
{{ task.description|commonmark }}
+
+
+
+
+{% endblock %}
+
diff --git a/src/teams/templates/team_detail.html b/src/teams/templates/team_detail.html
index 85d5e915..60f4b711 100644
--- a/src/teams/templates/team_detail.html
+++ b/src/teams/templates/team_detail.html
@@ -9,56 +9,81 @@ Team: {{ team.name }} | {{ block.super }}
{% block content %}
-
{{ team.name }} Team ({{ team.area.name }} area)
+
+
{{ team.name }} Team
+
+ {{ team.description|unsafecommonmark }}
+ {% if request.user in team.responsible.all %}
+
Manage Team
+ {% endif %}
-{{ team.description|unsafecommonmark }}
-
Currently {{ team.approvedmembers.count }} people are members of this team{% if request.user in team.members.all %} (including you){% endif %}.
+
-{% if request.user in team.members.all %}
-
Your team status: {% membershipstatus request.user team %}
-{% endif %}
+
Members
+
The following {{ team.approvedmembers.count }} people are members of the {{ team.name }} team :
+
+
+
+
+ Name
+
+
+ Status
+
+
+
+
+ {% for teammember in team.approvedmembers.all %}
+
+
+ {% if teammember.user.profile.approved_public_credit_name %}
+ {{ teammember.user.profile.approved_public_credit_name }}
+ {% else %}
+ anonymous
+ {% endif %}
+
+
+ {% if teammember.responsible %}Team Responsible{% else %}Team Member{% endif %}
+
+
+ {% endfor %}
+
+
-{% if request.user in team.members.all %}
-
Leave Team
-{% else %}
- {% if team.needs_members %}
-
Join Team
- {% endif %}
-{% endif %}
+ {% if request.user in team.members.all %}
+
Your membership status: {% membershipstatus request.user team %}
+ {% endif %}
+
+ {% if request.user in team.members.all %}
+
Leave Team
+ {% else %}
+ {% if team.needs_members %}
+
This team is looking for members! Join Team
+ {% endif %}
+ {% endif %}
+
+
+
+
Tasks
+
This team is responsible for the following tasks
+
+
+
+ Name
+ Description
+
+
+
+ {% for task in team.tasks.all %}
+
+ {{ task.name }}
+ {{ task.description }}
+
+ {% endfor %}
+
+
+
+
+
-{% if request.user in team.responsible.all %}
-
Manage Team
-{% endif %}
-
-
Team Members
-
The following people are members of the {{ team.name }} team :
-
-
-
-
- Name
-
-
- Status
-
-
-
-
- {% for teammember in team.approvedmembers.all %}
- {% if teammember.user.profile.approved_public_credit_name and teammember.approved or teammember.responsible %}
-
-
- {{ teammember.user.profile.approved_public_credit_name }}
-
-
- {% if teammember.responsible %}Team Responsible{% else %}Team Member{% endif %}
-
-
- {% endif %}
- {% endfor %}
-
-
-{% if team.anoncount %}
-
Plus {{ team.anoncount }} member(s) who prefer to remain anonymous.
-{% endif %}
{% endblock %}
diff --git a/src/teams/templates/team_join.html b/src/teams/templates/team_join.html
index 467536af..ac4e8fd0 100644
--- a/src/teams/templates/team_join.html
+++ b/src/teams/templates/team_join.html
@@ -13,6 +13,6 @@ Join Team: {{ team.name }} | {{ block.super }}
{% csrf_token %}
{{ form }}
Join {{ team.name }} Team
-
Cancel
+
Cancel
{% endblock %}
diff --git a/src/teams/templates/team_leave.html b/src/teams/templates/team_leave.html
index 9cfd418e..9d904f54 100644
--- a/src/teams/templates/team_leave.html
+++ b/src/teams/templates/team_leave.html
@@ -13,6 +13,6 @@ Leave Team: {{ team.name }} | {{ block.super }}
{% csrf_token %}
{{ form }}
Leave {{ team.name }} Team
-
Cancel
+
Cancel
{% endblock %}
diff --git a/src/teams/templates/team_list.html b/src/teams/templates/team_list.html
index 0cca4aa0..a0ade942 100644
--- a/src/teams/templates/team_list.html
+++ b/src/teams/templates/team_list.html
@@ -22,6 +22,7 @@ Teams | {{ block.super }}
Description
Responsible
Members
+
Tasks
{% if request.user.is_authenticated %}
Member?
Actions
@@ -32,7 +33,7 @@ Teams | {{ block.super }}
{% for team in teams %}
-
+
{{ team.name }} Team
@@ -51,6 +52,10 @@ Teams | {{ block.super }}
{% if team.needs_members %}(more needed){% endif %}
+
+ {{ team.tasks.count }}
+
+
{% if request.user.is_authenticated %}
{% membershipstatus request.user team as membership_status %}
@@ -67,15 +72,15 @@ Teams | {{ block.super }}
{% if request.user in team.members.all %}
- Leave
+ Leave
{% else %}
{% if team.needs_members %}
- Join
+ Join
{% endif %}
{% endif %}
{% if request.user in team.responsible.all %}
- Manage
+ Manage
{% endif %}
{% endif %}
diff --git a/src/teams/templates/team_manage.html b/src/teams/templates/team_manage.html
index 0cdd73b2..57c80348 100644
--- a/src/teams/templates/team_manage.html
+++ b/src/teams/templates/team_manage.html
@@ -71,10 +71,10 @@ Manage Team: {{ team.name }} | {{ block.super }}
{% if membership.approved %}
- Remove
+ Remove
{% else %}
- Remove
- Approve
+ Remove
+ Approve
{% endif %}
diff --git a/src/teams/templates/teammember_approve.html b/src/teams/templates/teammember_approve.html
index c1154d89..c25b0ff6 100644
--- a/src/teams/templates/teammember_approve.html
+++ b/src/teams/templates/teammember_approve.html
@@ -13,6 +13,6 @@ Approve team member {{ teammember.user.profile.name }} for the {{ teammember.tea
{% csrf_token %}
{{ form }}
Add teammember
-
Cancel
+
Cancel
{% endblock %}
diff --git a/src/teams/templates/teammember_remove.html b/src/teams/templates/teammember_remove.html
index 9e49c15b..d0288437 100644
--- a/src/teams/templates/teammember_remove.html
+++ b/src/teams/templates/teammember_remove.html
@@ -13,6 +13,6 @@ Remove member {{ teammember.user.profile.name }} from the {{ teammember.team.nam
{% csrf_token %}
{{ form }}
Remove teammember
-
Cancel
+
Cancel
{% endblock %}
diff --git a/src/teams/urls.py b/src/teams/urls.py
new file mode 100644
index 00000000..3c479bca
--- /dev/null
+++ b/src/teams/urls.py
@@ -0,0 +1,47 @@
+from django.conf.urls import url
+from .views import *
+
+urlpatterns = [
+ url(
+ r'^$',
+ TeamListView.as_view(),
+ name='list'
+ ),
+ url(
+ r'^members/(?P
[0-9]+)/remove/$',
+ TeamMemberRemoveView.as_view(),
+ name='teammember_remove',
+ ),
+ url(
+ r'^members/(?P[0-9]+)/approve/$',
+ TeamMemberApproveView.as_view(),
+ name='teammember_approve',
+ ),
+ url(
+ r'(?P[-_\w+]+)/tasks/(?P[-_\w+]+)/$',
+ TaskDetailView.as_view(),
+ name='task_detail',
+ ),
+ url(
+ r'(?P[-_\w+]+)/join/$',
+ TeamJoinView.as_view(),
+ name='join'
+ ),
+ url(
+ r'(?P[-_\w+]+)/leave/$',
+ TeamLeaveView.as_view(),
+ name='leave'
+ ),
+ url(
+ r'(?P[-_\w+]+)/manage/$',
+ TeamManageView.as_view(),
+ name='manage'
+ ),
+ # this has to be the last url in the list
+ url(
+ r'(?P[-_\w+]+)/$',
+ TeamDetailView.as_view(),
+ name='detail'
+ ),
+]
+
diff --git a/src/teams/views.py b/src/teams/views.py
index a34f5a40..96be4e33 100644
--- a/src/teams/views.py
+++ b/src/teams/views.py
@@ -1,7 +1,7 @@
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, FormView
from camps.mixins import CampViewMixin
-from .models import Team, TeamMember
+from .models import Team, TeamMember, TeamTask
from .forms import ManageTeamForm
from .email import add_added_membership_email, add_removed_membership_email
from django.contrib.auth.mixins import LoginRequiredMixin
@@ -62,22 +62,22 @@ class TeamJoinView(LoginRequiredMixin, CampViewMixin, UpdateView):
request,
"Please fill the description in your profile before joining a team"
)
- return redirect('team_list', camp_slug=self.camp.slug)
+ return redirect('teams:list', camp_slug=self.camp.slug)
if request.user in self.get_object().members.all():
messages.warning(request, "You are already a member of this team")
- return redirect('team_list', camp_slug=self.camp.slug)
+ return redirect('teams:list', camp_slug=self.camp.slug)
if not self.get_object().needs_members:
messages.warning(request, "This team does not need members right now")
- return redirect('team_list', camp_slug=self.get_object().camp.slug)
+ return redirect('teams:list', camp_slug=self.get_object().camp.slug)
return super().get(request, *args, **kwargs)
def form_valid(self, form):
TeamMember.objects.create(team=self.get_object(), user=self.request.user)
messages.success(self.request, "You request to join the team %s has been registered, thank you." % self.get_object().name)
- return redirect('team_list', camp_slug=self.get_object().camp.slug)
+ return redirect('teams:list', camp_slug=self.get_object().camp.slug)
class TeamLeaveView(LoginRequiredMixin, CampViewMixin, UpdateView):
@@ -88,14 +88,14 @@ class TeamLeaveView(LoginRequiredMixin, CampViewMixin, UpdateView):
def get(self, request, *args, **kwargs):
if request.user not in self.get_object().members.all():
messages.warning(request, "You are not a member of this team")
- return redirect('team_list', camp_slug=self.get_object().camp.slug)
+ return redirect('teams:list', camp_slug=self.get_object().camp.slug)
return super().get(request, *args, **kwargs)
def form_valid(self, form):
TeamMember.objects.filter(team=self.get_object(), user=self.request.user).delete()
messages.success(self.request, "You are no longer a member of the team %s" % self.get_object().name)
- return redirect('team_list', camp_slug=self.get_object().camp.slug)
+ return redirect('teams:list', camp_slug=self.get_object().camp.slug)
class EnsureTeamMemberResponsibleMixin(SingleObjectMixin):
@@ -145,3 +145,9 @@ class TeamMemberApproveView(LoginRequiredMixin, CampViewMixin, EnsureTeamMemberR
)
return redirect('team_detail', camp_slug=self.camp.slug, slug=form.instance.team.slug)
+
+class TaskDetailView(CampViewMixin, DetailView):
+ template_name = "task_detail.html"
+ context_object_name = "task"
+ model = TeamTask
+
diff --git a/src/templates/base.html b/src/templates/base.html
index 2360aff8..4e66eb27 100644
--- a/src/templates/base.html
+++ b/src/templates/base.html
@@ -91,7 +91,7 @@
-
+
@@ -99,7 +99,7 @@
-
+