Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 56 additions & 30 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,59 @@
name: Lint
on: pull_request
jobs:
run-linters:
name: Run linters
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend

steps:
- name: Check out Git repository
uses: actions/checkout@v5

- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: 22

- name: Enable Corepack
run: corepack enable

# ESLint and Prettier must be in `package.json`
- name: Install Node.js dependencies
run: yarn install --immutable

- name: Run linters
uses: wearerequired/lint-action@v2.3.0
with:
eslint: true
eslint_dir: ./frontend
prettier: true
prettier_dir: ./frontend
run-linters:
name: Run linters
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend

steps:
- name: Check out Git repository
uses: actions/checkout@v5

- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: 22

- name: Enable Corepack
run: corepack enable

# ESLint and Prettier must be in `package.json`
- name: Install Node.js dependencies
run: yarn install --immutable

- name: Run linters
uses: wearerequired/lint-action@v2.3.0
with:
eslint: true
eslint_dir: ./frontend
prettier: true
prettier_dir: ./frontend

ruff:
name: Ruff (backend)
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./backend

steps:
- name: Check out Git repository
uses: actions/checkout@v5

- name: Install uv
uses: astral-sh/setup-uv@v4

- name: Set up Python
run: uv python install

- name: Install backend dependencies
run: uv sync --group dev

- name: Run Ruff lint check
run: uv run ruff check

- name: Run Ruff format check
run: uv run ruff format --check
2 changes: 2 additions & 0 deletions backend/config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
from django.urls import path

from hoagiecalendar.api.event_views import EventDetailView, EventView
from hoagiecalendar.api.user_events_view import UserEventsView

urlpatterns = [
path("admin/", admin.site.urls),
path("event/", EventView.as_view(), name="event"),
path("event/<int:event_id>/", EventDetailView.as_view(), name="event-detail"),
path("user/events/", UserEventsView.as_view(), name="user-events"),
]
2 changes: 0 additions & 2 deletions backend/hoagiecalendar/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
from django.contrib import admin

# Register your models here.
115 changes: 100 additions & 15 deletions backend/hoagiecalendar/api/event_views.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,111 @@
from django.shortcuts import get_object_or_404
from rest_framework import serializers, status
from rest_framework.response import Response
from rest_framework.views import APIView

from ..models.event import Event


class EventSerializer(serializers.ModelSerializer):
name = serializers.CharField(
max_length=100,
min_length=3,
error_messages={
"blank": "Name must be at least 3 characters.",
"min_length": "Name must be at least 3 characters.",
"max_length": "Name must be at most 100 characters.",
},
)

location = serializers.CharField(
max_length=100,
min_length=3,
error_messages={
"blank": "Location must be at least 3 characters.",
"min_length": "Location must be at least 3 characters.",
"max_length": "Location must be at most 100 characters.",
},
)

host = serializers.CharField(
max_length=100,
min_length=3,
error_messages={
"blank": "Host must be at least 3 characters.",
"min_length": "Host must be at least 3 characters.",
"max_length": "Host must be at most 100 characters.",
},
)

class Meta:
model = Event
fields = [
"id",
"start",
"end",
"name",
"location",
"description",
"host",
"owner",
"category",
"from_mail",
"ordering",
]
read_only_fields = ["id", "owner", "created_at", "updated_at"]


class EventView(APIView):
def get(self, request) -> Response:
# Logic to get events
pass
def get(self, request) -> Response:
start_time = request.query_params.get("start_time")
end_time = request.query_params.get("end_time")

# return an error if start_time or end_time are not in the request
if not start_time or not end_time:
return Response(
{"detail": "Both start_time and end_time query parameters are required."},
status=status.HTTP_400_BAD_REQUEST,
)

# get all events that overlap with the given time interval
# (event end is after the start of the range, and event start is before the end of the range)
queryset = Event.objects.filter(end__gte=start_time, start__lte=end_time)

# filter by matching category IDs (allow multiple categories)
category_ids = request.query_params.getlist("category_id")
if category_ids:
queryset = queryset.filter(category__id__in=category_ids)

# make sure events returned are unique (in case of multiple category matches)
queryset = queryset.distinct()

serializer = EventSerializer(queryset, many=True)

return Response(serializer.data, status=status.HTTP_200_OK)

def post(self, request) -> Response:
# Logic to create an event
pass
def post(self, request) -> Response:
serializer = EventSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
# saving the event with the user as the owner
serializer.save(owner=request.user)
return Response(serializer.data, status=status.HTTP_201_CREATED)


class EventDetailView(APIView):
def get(self, request, event_id) -> Response:
# Logic to get details of an event
pass
def get(self, request, event_id) -> Response:
# Logic to get details of an event
event = get_object_or_404(Event, id=event_id)
serializer = EventSerializer(event)
return Response(serializer.data, status=status.HTTP_200_OK)

def put(self, request, event_id) -> Response:
# Logic to update details of an event
pass
def put(self, request, event_id) -> Response:
# Logic to update details of an event
event = get_object_or_404(Event, id=event_id)
serializer = EventSerializer(event, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)

def delete(self, request, event_id) -> Response:
# Logic to delete an event
pass
def delete(self, request, event_id) -> Response:
# Logic to delete an event
pass
14 changes: 14 additions & 0 deletions backend/hoagiecalendar/api/user_events_view.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

from ..models.event import Event
from .event_views import EventSerializer


class UserEventsView(APIView):
# Logic to get events user created
def get(self, request) -> Response:
events = Event.objects.filter(owner=request.user)
serializer = EventSerializer(events, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
3 changes: 3 additions & 0 deletions backend/hoagiecalendar/models/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ class Event(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ManyToManyField(Category, related_name="events", blank=True)
from_mail = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def __str__(self) -> str:
return self.name

class Meta:
db_table = "Event"
ordering = ["start"]
2 changes: 0 additions & 2 deletions backend/hoagiecalendar/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
from django.test import TestCase

# Create your tests here.
5 changes: 5 additions & 0 deletions backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ line-ending = "auto" # Automatically detect line endings
requires = ["hatchling"]
build-backend = "hatchling.build"

[dependency-groups]
dev = [
"ruff>=0.15.4",
]

[tool.hatch.build.targets.wheel]
packages = ["hoagiecalendar"]

57 changes: 45 additions & 12 deletions backend/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading