From bba67c7dbea48c4ff79379749056cdfe35273d6c Mon Sep 17 00:00:00 2001
From: Thomas Steen Rasmussen
Date: Wed, 25 Aug 2021 02:19:28 +0200
Subject: [PATCH 1/4] needs moderation
---
src/villages/urls.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/villages/urls.py b/src/villages/urls.py
index 581178cc..772499f0 100644
--- a/src/villages/urls.py
+++ b/src/villages/urls.py
@@ -1,7 +1,6 @@
from django.urls import path
from .views import (
- VillageCreateView,
VillageDeleteView,
VillageDetailView,
VillageListView,
@@ -12,7 +11,7 @@ app_name = "villages"
urlpatterns = [
path("", VillageListView.as_view(), name="list"),
- path("create/", VillageCreateView.as_view(), name="create"),
+ # path("create/", VillageCreateView.as_view(), name="create"),
path("/delete/", VillageDeleteView.as_view(), name="delete"),
path("/edit/", VillageUpdateView.as_view(), name="update"),
path("/", VillageDetailView.as_view(), name="detail"),
--
2.43.4
From 3420394a0f51605eef2e26a4f9b511ac712be0d2 Mon Sep 17 00:00:00 2001
From: Thomas Steen Rasmussen
Date: Wed, 25 Aug 2021 02:36:26 +0200
Subject: [PATCH 2/4] needs moderation
---
src/bornhack/urls.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/bornhack/urls.py b/src/bornhack/urls.py
index f4c9b7b9..16a70392 100644
--- a/src/bornhack/urls.py
+++ b/src/bornhack/urls.py
@@ -13,7 +13,6 @@ from info.views import CampInfoView
from people.views import PeopleView
from sponsors.views import SponsorsView
from villages.views import (
- VillageCreateView,
VillageDeleteView,
VillageDetailView,
VillageListView,
@@ -118,11 +117,6 @@ urlpatterns = [
include(
[
path("", VillageListView.as_view(), name="village_list"),
- path(
- "create/",
- VillageCreateView.as_view(),
- name="village_create",
- ),
path(
"/delete/",
VillageDeleteView.as_view(),
--
2.43.4
From b3f127f197cf0a8803e946cdde967d1c0cd93257 Mon Sep 17 00:00:00 2001
From: Thomas Steen Rasmussen
Date: Wed, 25 Aug 2021 02:39:04 +0200
Subject: [PATCH 3/4] needs moderation
---
src/villages/templates/village_list.html | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/villages/templates/village_list.html b/src/villages/templates/village_list.html
index b8e93c1c..06621ea5 100644
--- a/src/villages/templates/village_list.html
+++ b/src/villages/templates/village_list.html
@@ -16,10 +16,6 @@ Villages | {{ block.super }}
tent, chairs and tables in the shop!
-{% if user.is_authenticated and not camp.read_only %}
-Create a new {{ camp.title }} village
-{% endif %}
-
{% if villages %}
--
2.43.4
From 005431d6f6e07ebcba9321c71a3cc45a02bf09c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Reynir=20Bj=C3=B6rnsson?=
Date: Tue, 24 Aug 2021 18:07:58 +0200
Subject: [PATCH 4/4] team shifts: implement marking shifts for sale
A common occurence is that not enough people volunteer for shifts at
first, and then the few volunteers take all the shifts (too many). Then
late comers aren't able to take any shifts.
This commit implements a third state for shift assignment: for sale. A
shift marked for sale means the team member is able to take the shift if
need be, but would rather someone else takes the shift. Another team
member will be able to take shifts at the same time even if the required
number of people are met.
The current semantics is for-sale shifts are replaced eagerly. Another
possible implementation would be to only replace for-sale shifts if the
number of required people is met.
---
src/teams/models.py | 20 +++++++++++++++++++-
src/teams/templates/team_shift_list.html | 8 ++++++--
src/teams/templates/team_user_shifts.html | 6 +++++-
src/teams/urls.py | 5 +++++
src/teams/views/shifts.py | 20 ++++++++++++++++++++
5 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/src/teams/models.py b/src/teams/models.py
index 6e0862f4..3366926f 100644
--- a/src/teams/models.py
+++ b/src/teams/models.py
@@ -401,7 +401,7 @@ class TeamShift(CampRelatedModel):
shift_range = DateTimeRangeField()
- team_members = models.ManyToManyField(TeamMember, blank=True)
+ team_members = models.ManyToManyField(TeamMember, blank=True, through=TeamShiftAssignment)
people_required = models.IntegerField(default=1)
@@ -420,3 +420,21 @@ class TeamShift(CampRelatedModel):
@property
def users(self):
return [member.user for member in self.team_members.all()]
+
+class TeamShiftAssignment(CampRelatedModel):
+ team_shift = models.ForeignKey(
+ "teams.TeamShift",
+ on_delete=models.CASCADE,
+ help_text="The shift",
+ )
+
+ team_member = models.ForeignKey(
+ "teams.TeamMember",
+ on_delete=models.CASCADE,
+ help_text="The team member on shift",
+ )
+
+ for_sale = models.BooleanField(
+ default=False,
+ help_text="Is the shift assignment for sale?",
+ )
diff --git a/src/teams/templates/team_shift_list.html b/src/teams/templates/team_shift_list.html
index 360e66a9..e8bbf025 100644
--- a/src/teams/templates/team_shift_list.html
+++ b/src/teams/templates/team_shift_list.html
@@ -50,7 +50,7 @@ Shifts | {{ block.super }}
{{ shift.people_required }}
{% for member in shift.team_members.all %}
- {{ member.user.profile.get_public_credit_name }}{% if not forloop.last %},{% endif %}
+ {{ member.user.profile.get_public_credit_name }}{% if member.for_sale %} (for sale!){% endif %}{% if not forloop.last %},{% endif %}
{% empty %}
None!
{% endfor %}
@@ -71,7 +71,11 @@ Shifts | {{ block.super }}
href="{% url 'teams:shift_member_drop' camp_slug=camp.slug team_slug=team.slug pk=shift.pk %}">
Unassign me
- {% elif shift.people_required > shift.team_members.count %}
+
+ Sell shift
+
+ {% elif shift.people_required > shift.team_members.filter(for_sale=False).count %}
Assign me
diff --git a/src/teams/templates/team_user_shifts.html b/src/teams/templates/team_user_shifts.html
index 745fd2bb..e3311b90 100644
--- a/src/teams/templates/team_user_shifts.html
+++ b/src/teams/templates/team_user_shifts.html
@@ -34,6 +34,10 @@ Your shifts | {{ block.super }}
|
{{ shift.shift_range.upper|date:'H:i' }}
|
+
+
+ Sell shift
|
@@ -45,4 +49,4 @@ Your shifts | {{ block.super }}
|
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/src/teams/urls.py b/src/teams/urls.py
index 92ef4e03..33bdc7c7 100644
--- a/src/teams/urls.py
+++ b/src/teams/urls.py
@@ -179,6 +179,11 @@ urlpatterns = [
MemberDropsShift.as_view(),
name="shift_member_drop",
),
+ path(
+ "sell",
+ MemberSellsShift.as_view(),
+ name="shift_member_sell",
+ ),
]
),
),
diff --git a/src/teams/views/shifts.py b/src/teams/views/shifts.py
index eaa44fc8..72d0ede9 100644
--- a/src/teams/views/shifts.py
+++ b/src/teams/views/shifts.py
@@ -274,6 +274,9 @@ class MemberTakesShift(LoginRequiredMixin, CampViewMixin, View):
request, template.render(Context({"shifts": overlapping_shifts}))
)
else:
+ # Remove at most one shift assignment for sale
+ for shift_assignment in shift.team_members.filter(for_sale=True)[:1]:
+ shift_assignment.delete()
shift.team_members.add(team_member)
kwargs.pop("pk")
@@ -297,6 +300,23 @@ class MemberDropsShift(LoginRequiredMixin, CampViewMixin, View):
return HttpResponseRedirect(reverse("teams:shifts", kwargs=kwargs))
+class MemberSellsShift(LoginRequiredMixin, CampViewMixin, View):
+
+ http_methods = ["get"]
+
+ def get(self, request, **kwargs):
+ shift = TeamShift.objects.get(id=kwargs["pk"])
+ team = Team.objects.get(camp=self.camp, slug=kwargs["team_slug"])
+
+ team_member = TeamMember.objects.get(team=team, user=request.user)
+
+ shift_assignment = shift.team_members.get(team_member = team_member.pk)
+ shift_assignment.for_sale = True
+ shift_assignment.save()
+
+ kwargs.pop("pk")
+
+ return HttpResponseRedirect(reverse("teams:shifts", kwargs=kwargs))
class UserShifts(CampViewMixin, TemplateView):
template_name = "team_user_shifts.html"
--
2.43.4