diff --git a/src/backoffice/templates/infodesk.html b/src/backoffice/templates/infodesk.html index 753ff625..080c6a68 100644 --- a/src/backoffice/templates/infodesk.html +++ b/src/backoffice/templates/infodesk.html @@ -10,7 +10,7 @@

Infodesk Backoffice

- Orders with one or more Products that are not handed out + Paid (and not later refunded) orders with at least one product that is not yet handed out
diff --git a/src/bornhack/urls.py b/src/bornhack/urls.py index 6341b83e..5b4d6f0f 100644 --- a/src/bornhack/urls.py +++ b/src/bornhack/urls.py @@ -297,6 +297,7 @@ urlpatterns = [ VillageUpdateView.as_view(), name='village_update' ), + # this has to be the last url in the list url( r'(?P[-_\w+]+)/$', VillageDetailView.as_view(), @@ -306,45 +307,11 @@ urlpatterns = [ ), url( - r'^teams/', include([ - url( - r'^$', - TeamListView.as_view(), - name='team_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+]+)/join/$', - TeamJoinView.as_view(), - name='team_join' - ), - url( - r'(?P[-_\w+]+)/leave/$', - TeamLeaveView.as_view(), - name='team_leave' - ), - url( - r'(?P[-_\w+]+)/manage/$', - TeamManageView.as_view(), - name='team_manage' - ), - # this has to be the last url in the list - url( - r'(?P[-_\w+]+)/$', - TeamDetailView.as_view(), - name='team_detail' - ), - ]) + r'^teams/', + include('teams.urls', namespace='teams') ), + + ]) ) ] diff --git a/src/camps/templates/bornhack-2017_camp_detail.html b/src/camps/templates/bornhack-2017_camp_detail.html index f5eb33a3..826622dd 100644 --- a/src/camps/templates/bornhack-2017_camp_detail.html +++ b/src/camps/templates/bornhack-2017_camp_detail.html @@ -37,7 +37,7 @@
- The BornHack team looks forward to organising another great event for the hacker community. We still need volunteers, so please let us know if you want to help! + The BornHack team looks forward to organising another great event for the hacker community. We still need volunteers, so please let us know if you want to help!
diff --git a/src/camps/templates/bornhack-2018_camp_detail.html b/src/camps/templates/bornhack-2018_camp_detail.html index 87cd8630..e3efbdb0 100644 --- a/src/camps/templates/bornhack-2018_camp_detail.html +++ b/src/camps/templates/bornhack-2018_camp_detail.html @@ -37,7 +37,7 @@
- The BornHack team looks forward to organising another great event for the hacker community. We still need volunteers, so please let us know if you want to help! + The BornHack team looks forward to organising another great event for the hacker community. We still need volunteers, so please let us know if you want to help!
diff --git a/src/camps/templates/bornhack-2019_camp_detail.html b/src/camps/templates/bornhack-2019_camp_detail.html index a5daa7c2..774fcd29 100644 --- a/src/camps/templates/bornhack-2019_camp_detail.html +++ b/src/camps/templates/bornhack-2019_camp_detail.html @@ -37,7 +37,7 @@
- The BornHack team looks forward to organising another great event for the hacker community. We still need volunteers, so please let us know if you want to help! + The BornHack team looks forward to organising another great event for the hacker community. We still need volunteers, so please let us know if you want to help!
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:

+ + + + + + + + + {% for teammember in team.approvedmembers.all %} + + + + + {% endfor %} + +
+ Name + + Status +
+ {% 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 %} +
-{% 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

+ + + + + + + + + {% for task in team.tasks.all %} + + + + + {% endfor %} + +
NameDescription
{{ task.name }}{{ task.description }}
+ +
+
-{% if request.user in team.responsible.all %} - Manage Team -{% endif %} -
-

Team Members

-

The following people are members of the {{ team.name }} team:

- - - - - - - - - {% for teammember in team.approvedmembers.all %} - {% if teammember.user.profile.approved_public_credit_name and teammember.approved or teammember.responsible %} - - - - - {% endif %} - {% endfor %} - -
- Name - - Status -
- {{ teammember.user.profile.approved_public_credit_name }} - - {% if teammember.responsible %}Team Responsible{% else %}Team Member{% endif %} -
-{% 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 }} - 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 }} - 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 }} - 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 }} - 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 @@ Program Villages Sponsors - Teams + Teams