Skip to content

Commit

Permalink
Merge branch 'dev' into dependabot/pip/djangorestframework-3.15.2
Browse files Browse the repository at this point in the history
  • Loading branch information
MadsNyl authored Sep 27, 2024
2 parents ba2a844 + d0a0c07 commit 50e853d
Show file tree
Hide file tree
Showing 55 changed files with 1,596 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

## Neste versjon

## Versjon 2024.09.25

-**Codex arrangementer**. Det kan nå opprettes arrangementer på Codex, som medlemmer av Codex kan melde seg på.
-**Betalingsordre**. Man kan nå se historikk over betalingsordre for en påmelding til et arrangement.
-**Gruppe**. HS kan nå opprette en ny gruppe.
-**Swagger**. La til en GitHub Action for å verifisere at Swagger er oppe og går.
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ createsuperuser: ## Create a new django superuser

.PHONY: makemigrations
makemigrations: ## Create migration files
docker compose run --rm web python manage.py makemigrations
docker compose run --rm web python manage.py makemigrations ${args}

.PHONY: migrate
migrate: ## Run django migrations
Expand Down
Empty file added app/codex/__init__.py
Empty file.
1 change: 1 addition & 0 deletions app/codex/admin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from app.codex.admin import admin
7 changes: 7 additions & 0 deletions app/codex/admin/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin

from app.codex.models.event import CodexEvent
from app.codex.models.registration import CodexEventRegistration

admin.site.register(CodexEvent)
admin.site.register(CodexEventRegistration)
Empty file added app/codex/apps.py
Empty file.
23 changes: 23 additions & 0 deletions app/codex/enums.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from django.db import models


class CodexGroups(models.TextChoices):
DRIFT = "Drift"
INDEX = "Index"

@classmethod
def all(cls) -> list:
return [cls.DRIFT, cls.INDEX]

@classmethod
def reverse(cls) -> list:
return [cls.INDEX, cls.DRIFT]


class CodexEventTags(models.TextChoices):
WORKSHOP = "Workshop"
LECTURE = "Lecture"

@classmethod
def all(cls) -> list:
return [cls.WORKSHOP, cls.LECTURE]
24 changes: 24 additions & 0 deletions app/codex/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from rest_framework import status
from rest_framework.exceptions import APIException


class APICodexEventEndRegistrationDateAfterStartDate(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = (
"Sluttdatoen for påmelding kan ikke være etter startdatoen for kurset"
)


class APICodexEventEndRegistrationDateBeforeStartRegistrationDate(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = (
"Sluttdatoen for påmelding kan ikke være før startdatoen for påmelding"
)


class CodexEventEndRegistrationDateAfterStartDate(ValueError):
pass


class CodexEventEndRegistrationDateBeforeStartRegistrationDate(ValueError):
pass
2 changes: 2 additions & 0 deletions app/codex/factories/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from app.codex.factories.event import CodexEventFactory
from app.codex.factories.registration import CodexEventRegistrationFactory
20 changes: 20 additions & 0 deletions app/codex/factories/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from datetime import timedelta

from django.utils import timezone

import factory
from factory.django import DjangoModelFactory

from app.codex.models.event import CodexEvent


class CodexEventFactory(DjangoModelFactory):
class Meta:
model = CodexEvent

title = factory.Sequence(lambda n: f"Event {n}")
description = factory.Faker("text")
start_date = timezone.now() + timedelta(days=10)

start_registration_at = timezone.now() - timedelta(days=1)
end_registration_at = timezone.now() + timedelta(days=9)
15 changes: 15 additions & 0 deletions app/codex/factories/registration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import factory
from factory.django import DjangoModelFactory

from app.codex.factories.event import CodexEventFactory
from app.codex.models.registration import CodexEventRegistration
from app.content.factories.user_factory import UserFactory


class CodexEventRegistrationFactory(DjangoModelFactory):
class Meta:
model = CodexEventRegistration

user = factory.SubFactory(UserFactory)
event = factory.SubFactory(CodexEventFactory)
order = 0
1 change: 1 addition & 0 deletions app/codex/filters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from app.codex.filters.event import CodexEventFilter
20 changes: 20 additions & 0 deletions app/codex/filters/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django_filters.rest_framework import (
DateTimeFilter,
FilterSet,
OrderingFilter,
)

from app.codex.models.event import CodexEvent


class CodexEventFilter(FilterSet):
"""Filters events by tag and expired. Works with search query"""

end_range = DateTimeFilter(field_name="start_date", lookup_expr="lte")
start_range = DateTimeFilter(field_name="end_date", lookup_expr="gte")

ordering = OrderingFilter("start_date", "tag")

class Meta:
model = CodexEvent
fields = ["tag", "end_range", "start_range", "organizer"]
123 changes: 123 additions & 0 deletions app/codex/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Generated by Django 4.2.16 on 2024-09-24 16:44

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("group", "0020_alter_membership_membership_type_and_more"),
]

operations = [
migrations.CreateModel(
name="CodexEvent",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("title", models.CharField(max_length=255)),
("description", models.TextField(blank=True, default="")),
("start_date", models.DateTimeField()),
(
"start_registration_at",
models.DateTimeField(blank=True, default=None, null=True),
),
(
"end_registration_at",
models.DateTimeField(blank=True, default=None, null=True),
),
(
"tag",
models.CharField(
choices=[("Workshop", "Workshop"), ("Lecture", "Lecture")],
default="Lecture",
max_length=50,
),
),
("location", models.CharField(max_length=200, null=True)),
("mazemap_link", models.URLField(max_length=2000, null=True)),
(
"lecturer",
models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="codex_events",
to=settings.AUTH_USER_MODEL,
),
),
(
"organizer",
models.ForeignKey(
blank=True,
default=None,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="codex_events",
to="group.group",
),
),
],
options={
"verbose_name_plural": "Events",
"ordering": ("start_date",),
},
),
migrations.CreateModel(
name="CodexEventRegistration",
fields=[
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
(
"registration_id",
models.AutoField(primary_key=True, serialize=False),
),
("order", models.IntegerField(default=0)),
(
"event",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="codex_event_registrations",
to="codex.codexevent",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="codex_event_registrations",
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"ordering": ("order", "created_at"),
"unique_together": {("user", "event")},
},
),
migrations.AddField(
model_name="codexevent",
name="registrations",
field=models.ManyToManyField(
blank=True,
default=None,
through="codex.CodexEventRegistration",
to=settings.AUTH_USER_MODEL,
),
),
]
Empty file.
17 changes: 17 additions & 0 deletions app/codex/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from app.codex.exceptions import (
APICodexEventEndRegistrationDateAfterStartDate,
APICodexEventEndRegistrationDateBeforeStartRegistrationDate,
CodexEventEndRegistrationDateAfterStartDate,
CodexEventEndRegistrationDateBeforeStartRegistrationDate,
)
from app.util.mixins import APIErrorsMixin


class APICodexEventErrorsMixin(APIErrorsMixin):
@property
def expected_exceptions(self):
return {
**super().expected_exceptions,
CodexEventEndRegistrationDateAfterStartDate: APICodexEventEndRegistrationDateAfterStartDate,
CodexEventEndRegistrationDateBeforeStartRegistrationDate: APICodexEventEndRegistrationDateBeforeStartRegistrationDate,
}
Empty file added app/codex/models/__init__.py
Empty file.
93 changes: 93 additions & 0 deletions app/codex/models/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
from django.db import models

from app.codex.enums import CodexEventTags, CodexGroups
from app.codex.util import user_is_leader_of_codex_group
from app.common.permissions import BasePermissionModel
from app.content.models import User
from app.group.models import Group
from app.util.models import BaseModel


class CodexEvent(BaseModel, BasePermissionModel):
read_access = CodexGroups.all()
write_access = CodexGroups.all()

title = models.CharField(max_length=255)
description = models.TextField(blank=True, default="")

start_date = models.DateTimeField()

start_registration_at = models.DateTimeField(blank=True, null=True, default=None)
end_registration_at = models.DateTimeField(blank=True, null=True, default=None)

tag = models.CharField(
max_length=50, choices=CodexEventTags.choices, default=CodexEventTags.LECTURE
)

location = models.CharField(max_length=200, null=True)
mazemap_link = models.URLField(max_length=2000, null=True)

organizer = models.ForeignKey(
Group,
blank=True,
null=True,
default=None,
on_delete=models.SET_NULL,
related_name="codex_events",
)
lecturer = models.ForeignKey(
User,
blank=True,
null=True,
default=None,
on_delete=models.SET_NULL,
related_name="codex_events",
)

registrations = models.ManyToManyField(
User,
through="CodexEventRegistration",
through_fields=("event", "user"),
blank=True,
default=None,
)

class Meta:
verbose_name_plural = "Events"
ordering = ("start_date",)

def __str__(self):
return f"{self.title} - starting {self.start_date} at {self.location}"

@property
def list_count(self):
return self.registrations.count()

@classmethod
def has_write_permission(cls, request):
user = request.user
return user_is_leader_of_codex_group(user)

@classmethod
def has_update_permission(cls, request):
return cls.has_write_permission(request)

@classmethod
def has_destroy_permission(cls, request):
return cls.has_write_permission(request)

@classmethod
def has_retrieve_permission(cls, request):
return cls.has_read_permission(request)

def has_object_write_permission(self, request):
return self.has_write_permission(request)

def has_object_update_permission(self, request):
return self.has_write_permission(request)

def has_object_destroy_permission(self, request):
return self.has_write_permission(request)

def has_object_retrieve_permission(self, request):
return self.has_read_permission(request)
Loading

0 comments on commit 50e853d

Please sign in to comment.