Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2024.8.1 release #384

Merged
merged 11 commits into from
Aug 13, 2024
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# CHANGELOG


## [unreleased]

## [2024.8.1] - 2024-08-13
### Added
- Schedules
- Allergy resolver counting allergies per day based on shifts

## [2024.03.8] - 2024-03-08
### Added
- Organization
Expand Down
2 changes: 1 addition & 1 deletion ksg_nett/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@
DEPOSIT_TIME_RESTRICTION_HOUR = os.environ.get("DEPOSIT_TIME_RESTRICTION_HOUR", 20)
LANGUAGE_SESSION_KEY = "language"

VERSION = "2024.03.8"
VERSION = "2024.8.1"

# Feature flag keys
STRIPE_INTEGRATION_FEATURE_FLAG = "stripe_integration"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.7 on 2024-07-23 22:06

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('schedules', '0007_auto_20230426_2317'),
]

operations = [
migrations.AlterField(
model_name='shift',
name='location',
field=models.CharField(blank=True, choices=[('EDGAR', 'Edgar'), ('BODEGAEN', 'Bodegaen'), ('RUNDHALLEN', 'Rundhallen'), ('KLUBBEN', 'Klubben'), ('LYCHE_BAR', 'Lyche Bar'), ('LYCHE_KJOKKEN', 'Lyche Kjøkken'), ('STORSALEN', 'Storsalen'), ('SELSKAPSSIDEN', 'Selskapssiden'), ('SERVERING_C', 'Servering C'), ('SERVERING_D', 'Servering D'), ('SERVERING_K', 'Servering K'), ('STROSSA', 'Strossa'), ('DAGLIGHALLEN_BAR', 'Daglighallen Bar'), ('KONTORET', 'Kontoret')], max_length=64, null=True),
),
migrations.AlterField(
model_name='shifttemplate',
name='location',
field=models.CharField(blank=True, choices=[('EDGAR', 'Edgar'), ('BODEGAEN', 'Bodegaen'), ('RUNDHALLEN', 'Rundhallen'), ('KLUBBEN', 'Klubben'), ('LYCHE_BAR', 'Lyche Bar'), ('LYCHE_KJOKKEN', 'Lyche Kjøkken'), ('STORSALEN', 'Storsalen'), ('SELSKAPSSIDEN', 'Selskapssiden'), ('SERVERING_C', 'Servering C'), ('SERVERING_D', 'Servering D'), ('SERVERING_K', 'Servering K'), ('STROSSA', 'Strossa'), ('DAGLIGHALLEN_BAR', 'Daglighallen Bar'), ('KONTORET', 'Kontoret')], max_length=64, null=True),
),
]
3 changes: 3 additions & 0 deletions schedules/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ class Location(models.TextChoices):
LYCHE_KJOKKEN = "LYCHE_KJOKKEN", _("Lyche Kjøkken")
STORSALEN = "STORSALEN", _("Storsalen")
SELSKAPSSIDEN = "SELSKAPSSIDEN", _("Selskapssiden")
SERVERING_C = "SERVERING_C", _("Servering C")
SERVERING_D = "SERVERING_D", _("Servering D")
SERVERING_K = "SERVERING_K", _("Servering K")
STROSSA = "STROSSA", _("Strossa")
DAGLIGHALLEN_BAR = "DAGLIGHALLEN_BAR", _("Daglighallen Bar")
KONTORET = "KONTORET", _("Kontoret")
Expand Down
103 changes: 102 additions & 1 deletion schedules/schemas/schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@
)
from schedules.utils.schedules import normalize_shifts, send_given_shift_email
from schedules.utils.templates import apply_schedule_template
from users.models import User
from users.models import User, Allergy as UserAllergy
from django.utils import timezone
from django.conf import settings

from django.db.models import Count
from django.db.models.functions import TruncDate


class ShiftInterestNode(DjangoObjectType):
class Meta:
Expand Down Expand Up @@ -83,6 +86,17 @@ def get_node(cls, info, id):
return Shift.objects.get(pk=id)


class Allergy(graphene.ObjectType):
name = graphene.String()
count = graphene.Int()


class DayAllergyNode(graphene.ObjectType):
date = graphene.Date()
allergy_list = graphene.NonNull(graphene.List(graphene.NonNull(Allergy)))
total_user_count = graphene.NonNull(graphene.Int)


class ScheduleNode(DjangoObjectType):
class Meta:
model = Schedule
Expand Down Expand Up @@ -113,10 +127,97 @@ def get_node(cls, info, id):
class ScheduleQuery(graphene.ObjectType):
schedule = Node.Field(ScheduleNode)
all_schedules = graphene.NonNull(graphene.List(ScheduleNode, required=True))
schedule_allergies = graphene.List(DayAllergyNode, shifts_from=graphene.Date())

def resolve_all_schedules(self, info, *args, **kwargs):
return Schedule.objects.all().order_by("name")

def resolve_schedule_allergies(self, info, shifts_from, *args, **kwargs):
monday = shifts_from - timezone.timedelta(days=shifts_from.weekday())
monday = timezone.datetime(
year=monday.year,
month=monday.month,
day=monday.day,
)
monday = timezone.make_aware(monday, timezone=pytz.timezone(settings.TIME_ZONE))
sunday = monday + timezone.timedelta(days=6, hours=23, minutes=59, seconds=59)

filtered_shifts = Shift.objects.filter(
datetime_start__range=(monday, sunday), slots__user__isnull=False
)
allergy_filtered_shifts = Shift.objects.filter(
datetime_start__range=(monday, sunday),
slots__user__isnull=False,
slots__user__allergies__name__isnull=False,
)

allergy_counts = (
allergy_filtered_shifts.annotate(shift_date=TruncDate("datetime_start"))
.values("shift_date", "slots__user__allergies__name")
.annotate(
allergy_count=Count(
"slots__user__allergies",
)
)
.order_by("shift_date", "slots__user__allergies__name")
)

people_at_work_count = filtered_shifts.annotate(
shift_date=TruncDate("datetime_start")
).annotate(horse=Count("slots"))

count_dict = {}
for item in people_at_work_count.all():
shift_date = item.shift_date
shift_date_key = shift_date.strftime("%Y-%m-%d")
user_count = count_dict.get(shift_date_key, 0)
user_count += item.horse
count_dict[shift_date_key] = user_count

results = [
{
"shift_date": entry["shift_date"],
"allergy": entry["slots__user__allergies__name"],
"count": entry["allergy_count"],
# "total_users_at_work": entry["total_users_at_work"],
}
for entry in allergy_counts
]

result_dict = {}
for item in results:
shift_date = item["shift_date"]
shift_date_key = shift_date.strftime("%Y-%m-%d")
allergy_list = result_dict.get(shift_date_key, (shift_date, []))[1]
allergy_name = item["allergy"]
allergy_count = item["count"]

allergy_list.append((allergy_name, allergy_count))
result_dict[shift_date_key] = (
shift_date,
allergy_list,
)

final_list = []
for key in result_dict.keys():
date_obj, allergies = result_dict[key]

day_list = []
for allergu_tuple in allergies:
allergy_name, allergy_count = allergu_tuple
day_list.append(Allergy(name=allergy_name, count=allergy_count))

shift_date_key = date_obj.strftime("%Y-%m-%d")
total_user_count = count_dict.get(shift_date_key, 0)
final_list.append(
DayAllergyNode(
date=date_obj,
allergy_list=day_list,
total_user_count=total_user_count,
)
)
return final_list


# === Single location grouping types ===
class ShiftDayGroup(graphene.ObjectType):
Expand Down
37 changes: 37 additions & 0 deletions schedules/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import pytz
from django.test import TestCase
from django.utils.timezone import make_aware
from django.core import mail

from schedules.utils.templates import (
apply_schedule_template,
shift_template_timestamps_to_datetime,
)
from schedules.utils.schedules import send_given_shift_email
from schedules.tests.factories import (
ScheduleFactory,
ScheduleTemplateFactory,
Expand Down Expand Up @@ -163,3 +165,38 @@ def test__hello_world(self):
)
end = start + datetime.timedelta(days=3)
self.schedule.autofill_slots(start, end)

class TestShiftEmailCorrectFormat(TestCase):
def setUp(self):
start = make_aware(
datetime.datetime(2022, 5, 2, 15, 0), timezone=pytz.timezone("Europe/Oslo")
)
end = start + datetime.timedelta(hours=8)

self.schedule = ScheduleFactory.create(name="Edgar")
self.template = ScheduleTemplateFactory.create(
schedule=self.schedule, name="Standarduke"
)
self.shift = ShiftFactory(
name="Onsdag tidlig",
schedule=self.schedule,
datetime_start=start,
datetime_end=end,
)

user = UserFactory.create()

self.shift_slot = ShiftSlotFactory.create(
shift=self.shift, user=user, role=RoleOption.BARISTA
)

def test__shift_email__is_correctly_formatted(self):
send_given_shift_email(self.shift_slot)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [self.shift_slot.user.email])
self.assertIn("Hei!", mail.outbox[0].body)
self.assertIn("Du har blitt satt opp på vakt!", mail.outbox[0].body)
self.assertIn("Vakt: Onsdag tidlig", mail.outbox[0].body)
self.assertIn("Hvor: Edgar", mail.outbox[0].body)
self.assertIn("Når: 02.05 kl 15:00 - 23:00", mail.outbox[0].body)

17 changes: 16 additions & 1 deletion schedules/utils/schedules.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import secrets

from django.utils import timezone
from django.conf import settings
import pytz

from common.util import send_email

Expand Down Expand Up @@ -149,13 +151,24 @@ def normalize_shifts(shifts, display_mode):

def send_given_shift_email(shift_slot):
user = shift_slot.user
local_time_datetime_start = timezone.localtime(
shift_slot.shift.datetime_start, pytz.timezone(settings.TIME_ZONE)
)
local_time_datetime_end = timezone.localtime(
shift_slot.shift.datetime_end, pytz.timezone(settings.TIME_ZONE)
)

formatted_datetime_start = local_time_datetime_start.strftime("%d.%m kl %H:%M")
formatted_datetime_end = local_time_datetime_end.strftime("%H:%M")

content = f"""
Hei!

Du har blitt satt opp på vakt!

Vakt: {shift_slot.shift.name}
Hvor: {shift_slot.shift.location}
Når: {formatted_datetime_start} - {formatted_datetime_end}

"""

Expand All @@ -164,8 +177,10 @@ def send_given_shift_email(shift_slot):
<p>Du har blitt satt opp på vakt!</p>
<p>Vakt: {shift_slot.shift.name}</p>
<p>Hvor: {shift_slot.shift.location}</p>
<p>Når: {formatted_datetime_start} - {formatted_datetime_end}</p>


"""
"""

send_email(
recipients=[user.email],
Expand Down
Loading