Skip to content

Commit

Permalink
Merge pull request #198 from SELab-2/develop
Browse files Browse the repository at this point in the history
Milestone 3
  • Loading branch information
robinpdev authored May 23, 2024
2 parents c4497f8 + 34668da commit c54a8c5
Show file tree
Hide file tree
Showing 244 changed files with 10,425 additions and 3,112 deletions.
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
pip install -r ./backend/requirements.txt
- name: Running Django tests
run: |
source /home/selab2/hosting/.env.test
sh ./backend/runtests.sh
frontend-test:
Expand Down
23 changes: 23 additions & 0 deletions .template.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
DATABASE=postgres
DEBUG=1
DJANGO_ALLOWED_HOSTS='localhost example.com 127.0.0.1 [::1] django'
DJANGO_SUPERUSER_EMAIL=[email protected]
DJANGO_SUPERUSER_PASSWORD=abc
FRONTEND_URL=http://localhost:3000
NEXT_PUBLIC_BACKEND_URL=http://localhost:8000
NEXT_PUBLIC_REDIRECT_URL=/redirect
OAUTH_CLIENT_ID=1234
OAUTH_CLIENT_SECRET=1234
OAUTH_TENANT_ID=1234
REGISTRY_NAME=sel2-1.ugent.be:2002
REGISTRY_PASSWORD=testding
REGISTRY_URL=https://sel2-1.ugent.be:2002
REGISTRY_USER=test
SECRET_KEY=development_key
SQL_DATABASE=pigeonhole_dev
SQL_ENGINE=django.db.backends.postgresql
SQL_HOST=pigeonhole-database
SQL_PASSWORD=password
SQL_PORT=5432
SQL_USER=pigeonhole
SUBMISSIONS_PATH=./backend/uploads/submissions/
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ENV PYTHONUNBUFFERED 1

# install psycopg2 dependencies
RUN apk update \
&& apk add postgresql-dev gcc python3-dev musl-dev
&& apk add postgresql-dev gcc python3-dev musl-dev docker-cli

# install dependencies
RUN pip install --upgrade pip
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.prod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ RUN mkdir $APP_HOME/uploads
WORKDIR $APP_HOME

# install dependencies
RUN apk update && apk add libpq
RUN apk update && apk add libpq docker-cli
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --no-cache /wheels/*
Expand Down
37 changes: 36 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ superuser:
mockdata:
docker exec -it pigeonhole-backend python manage.py runscript mockdata

registry:
docker build examples/advanced-evaluation/always-succeed -t test-always-succeed
docker tag test-always-succeed localhost:5000/test-always-succeed
docker push localhost:5000/test-always-succeed
docker build examples/advanced-evaluation/helloworld -t test-helloworld
docker tag test-helloworld localhost:5000/test-helloworld
docker push localhost:5000/test-helloworld
docker build examples/advanced-evaluation/fibonacci-python -t fibonacci-python
docker tag fibonacci-python localhost:5000/fibonacci-python
docker push localhost:5000/fibonacci-python

evaltest:
docker exec -it pigeonhole-backend python manage.py runscript eval_test

submit:
docker exec -it pigeonhole-backend python manage.py runscript submit

reset:
docker image prune -af
docker system prune
Expand All @@ -30,5 +47,23 @@ frontshell:
componenttest:
docker exec -it pigeonhole-frontend npx jest

coveragecomponenttest:
docker exec -it pigeonhole-frontend npx jest --coverage --silent

silentcomponenttest:
docker exec -it pigeonhole-frontend npx jest --silent
docker exec -it pigeonhole-frontend npx jest --silent

resetdb:
docker exec pigeonhole-backend python manage.py flush --noinput
docker exec -it pigeonhole-backend python manage.py runscript mockdata

prodregistry:
docker build examples/advanced-evaluation/always-succeed -t test-always-succeed
docker tag test-always-succeed sel2-1.ugent.be:2002/test-always-succeed
docker push sel2-1.ugent.be:2002/test-always-succeed
docker build examples/advanced-evaluation/helloworld -t test-helloworld
docker tag test-helloworld sel2-1.ugent.be:2002/test-helloworld
docker push sel2-1.ugent.be:2002/test-helloworld
docker build examples/advanced-evaluation/fibonacci-python -t fibonacci-python
docker tag fibonacci-python sel2-1.ugent.be:2002/fibonacci-python
docker push sel2-1.ugent.be:2002/fibonacci-python
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
- Rune Dyselinck: Secretary

## Bekijk de [wiki](https://github.com/SELab-2/UGent-1/wiki) om alles over de applicatie te weten te komen.

## Bekijk de [user manual](https://github.com/SELab-2/UGent-1/blob/user-manual/user_manual/manual.pdf) voor de gebruikershandleiding.
1 change: 1 addition & 0 deletions backend/entrypoint.prod.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ python manage.py runscript push_site

python manage.py collectstatic --noinput

docker login $REGISTRY_URL -u $REGISTRY_USER -p $REGISTRY_PASSWORD

exec "$@"
2 changes: 2 additions & 0 deletions backend/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ python manage.py runscript push_site

python manage.py createsuperuser --noinput --email $DJANGO_SUPERUSER_EMAIL

docker login $REGISTRY_URL -u $REGISTRY_USER -p $REGISTRY_PASSWORD

exec "$@"
8 changes: 8 additions & 0 deletions backend/pigeonhole/apps/courses/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ class CourseAdmin(admin.ModelAdmin):
'open_course',
)
}
),
(
'banner',
{
'fields': (
'banner',
)
}
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 5.0.2 on 2024-04-27 11:32

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('courses', '0005_alter_course_banner'),
]

operations = [
migrations.AddField(
model_name='course',
name='archived',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='course',
name='year',
field=models.IntegerField(blank=True, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-04-30 21:06

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('courses', '0006_course_archived_course_year'),
]

operations = [
migrations.AlterField(
model_name='course',
name='year',
field=models.IntegerField(default=2024),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.11 on 2024-05-23 12:40

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('courses', '0007_alter_course_year'),
]

operations = [
migrations.AlterField(
model_name='course',
name='banner',
field=models.FileField(blank=True, null=True, upload_to='course_banners/'),
),
]
8 changes: 4 additions & 4 deletions backend/pigeonhole/apps/courses/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
from rest_framework import serializers


# Create your models here.
class Course(models.Model):
course_id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=256)
description = models.TextField()
open_course = models.BooleanField(default=False)
invite_token = models.CharField(max_length=20, blank=True, null=True)
banner = models.FileField(upload_to='course_banners/', blank=True, null=False,
default='course_banners/ugent_banner.png')
banner = models.FileField(upload_to='course_banners/', blank=True, null=True)
archived = models.BooleanField(default=False)
year = models.IntegerField(default=2024)

objects = models.Manager()

Expand All @@ -34,7 +34,7 @@ class CourseSerializer(serializers.ModelSerializer):

class Meta:
model = Course
fields = ['course_id', 'name', 'open_course', 'description', 'invite_token', 'banner']
fields = ['course_id', 'name', 'open_course', 'description', 'invite_token', 'banner', 'archived', 'year']

def to_representation(self, instance):
data = super().to_representation(instance)
Expand Down
5 changes: 3 additions & 2 deletions backend/pigeonhole/apps/courses/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ def has_permission(self, request, view):
"leave_course",
"get_teachers",
"get_students",
"get_archived_courses",
"get_open_courses"
]:
return True

if request.user.is_teacher:
if view.action in ["create", "list", "retrieve"]:
return True
elif (
view.action in ["update", "partial_update", "destroy",
"get_projects"]
view.action in ["update", "partial_update", "destroy", "get_projects"]
and User.objects.filter(
id=request.user.id, course=view.kwargs["pk"]
).exists()
Expand Down
53 changes: 51 additions & 2 deletions backend/pigeonhole/apps/courses/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django_filters.rest_framework import DjangoFilterBackend

from backend.pigeonhole.apps.courses.models import CourseSerializer
from backend.pigeonhole.apps.groups.models import Group
from backend.pigeonhole.apps.groups.models import Group, GroupSerializer
from backend.pigeonhole.apps.projects.models import Project
from backend.pigeonhole.apps.projects.models import ProjectSerializer
from backend.pigeonhole.apps.users.models import User, UserSerializer
Expand Down Expand Up @@ -59,6 +59,21 @@ def join_course(self, request, *args, **kwargs):
if request.user.is_student:
if course.open_course:
user.course.add(course)

# Join all individual projects of the course
projects = Project.objects.filter(course_id=course, group_size=1)
for project in projects:
group_data = {
"project_id": project.project_id,
"user": [user.id],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
group_serializer.save()

return Response(status=status.HTTP_200_OK)
else:
return Response(
Expand All @@ -81,6 +96,22 @@ def join_course_with_token(self, request, *args, **kwargs):

if invite_token == course.invite_token:
user.course.add(course)

# Join all individual projects of the course
if request.user.is_student:
projects = Project.objects.filter(course_id=course, group_size=1)
for project in projects:
group_data = {
"project_id": project.project_id,
"user": [user.id],
"feedback": None,
"final_score": None,
"visible": False,
}
group_serializer = GroupSerializer(data=group_data)
group_serializer.is_valid(raise_exception=True)
group_serializer.save()

return Response(
{"message": "Successfully joined the course with invite token."},
status=status.HTTP_200_OK,
Expand Down Expand Up @@ -112,7 +143,7 @@ def leave_course(self, request, *args, **kwargs):
@action(detail=False, methods=["GET"])
def get_selected_courses(self, request, *args, **kwargs):
user = request.user
courses = Course.objects.filter(user=user)
courses = Course.objects.filter(user=user, archived=False)
course_filter = CourseFilter(request.GET, queryset=courses)
paginated_queryset = self.paginate_queryset(course_filter.qs)
queryset = self.order_queryset(paginated_queryset)
Expand Down Expand Up @@ -162,3 +193,21 @@ def get_projects(self, request, *args, **kwargs):
paginated_queryset = self.paginate_queryset(queryset)
serializer = ProjectSerializer(paginated_queryset, many=True)
return self.get_paginated_response(serializer.data)

@action(detail=False, methods=["GET"])
def get_archived_courses(self, request, *args, **kwargs):
user = request.user
courses = Course.objects.filter(user=user, archived=True)
course_filter = CourseFilter(request.GET, queryset=courses)
paginated_queryset = self.paginate_queryset(course_filter.qs)
queryset = self.order_queryset(paginated_queryset)
serializer = CourseSerializer(queryset, many=True)
return self.get_paginated_response(serializer.data)

@action(detail=False, methods=["GET"])
def get_open_courses(self, request, *args, **kwargs):
courses = Course.objects.filter(open_course=True)
course_filter = CourseFilter(request.GET, queryset=courses)
queryset = self.order_queryset(course_filter.qs)
serializer = CourseSerializer(self.paginate_queryset(queryset), many=True)
return self.get_paginated_response(serializer.data)
8 changes: 8 additions & 0 deletions backend/pigeonhole/apps/projects/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ class ProjectAdmin(admin.ModelAdmin):
)
}
),
(
'test docker image',
{
'fields': (
'test_docker_image',
)
}
),
)

raw_id_fields = (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.13 on 2024-05-19 11:35

import backend.pigeonhole.apps.projects.models
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
('projects', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='project',
name='test_dockerfile',
field=models.FileField(blank=True, null=True,
upload_to=backend.pigeonhole.apps.projects.models.get_upload_to),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 4.2.13 on 2024-05-19 16:38

import backend.pigeonhole.apps.projects.models
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
('projects', '0002_project_test_dockerfile'),
]

operations = [
migrations.AlterField(
model_name='project',
name='test_dockerfile',
field=models.FileField(blank=True, null=True,
upload_to=backend.pigeonhole.apps.projects.models.dockerfile_path),
),
migrations.AlterField(
model_name='project',
name='test_files',
field=models.FileField(blank=True, null=True,
upload_to=backend.pigeonhole.apps.projects.models.testfile_path),
),
]
Loading

0 comments on commit c54a8c5

Please sign in to comment.