Skip to content

Commit

Permalink
Merge branch 'development' into permissions_cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
DeLany123 committed Mar 27, 2024
2 parents 8cb3bcc + a7eccbc commit c2a741a
Show file tree
Hide file tree
Showing 207 changed files with 19,399 additions and 1,293 deletions.
2 changes: 1 addition & 1 deletion .dev.env
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ DJANGO_CAS_URL_PREFIX="" # URL prefix for the CAS server. Should be empty for de
DJANGO_CAS_PORT=8080 # Port for the CAS server. Should be 8080 if DJANGO_DOMAIN_NAME is localhost
DJANGO_DB_ENGINE=django.db.backends.sqlite3 # Database engine
DJANGO_REDIS_HOST=${REDIS_IP} # Redis configuration
DJANGO_REDIS_PORT=${REDIS_PORT}
DJANGO_REDIS_PORT=${REDIS_PORT}
2 changes: 1 addition & 1 deletion .github/workflows/deployement.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ jobs:
script: |
cd UGent-7
docker-compose -f production.yml down
${{ secrets.PULL_SCRIPT }}
git pull
docker-compose -f production.yml build --no-cache
docker-compose -f production.yml up -d
2 changes: 1 addition & 1 deletion .prod.env
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ DJANGO_DB_PASSWORD=${POSTGRES_PASSWORD}
DJANGO_DB_HOST=${POSTGRES_IP}
DJANGO_DB_PORT=${POSTGRES_PORT}
DJANGO_REDIS_HOST=${REDIS_IP} # Redis configuration
DJANGO_REDIS_PORT=${REDIS_PORT}
DJANGO_REDIS_PORT=${REDIS_PORT}
6 changes: 4 additions & 2 deletions backend/api/models/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@ def is_past(self) -> bool:

def clone(self, clone_assistants=True) -> Self:
"""Clone the course to the next academic start year"""
course = Course(
course = Course.objects.create(
name=self.name,
description=self.description,
academic_startyear=self.academic_startyear + 1,
parent_course=self
)

if clone_assistants:
course.assistants.add(self.assistants)
# Add all the assistants of the current course to the follow up course
for assistant in self.assistants.all():
course.assistants.add(assistant)

return course

Expand Down
11 changes: 1 addition & 10 deletions backend/api/serializers/assistant_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,7 @@ class AssistantSerializer(serializers.ModelSerializer):

class Meta:
model = Assistant
fields = [
"id",
"first_name",
"last_name",
"email",
"faculties",
"last_enrolled",
"create_time",
"courses",
]
fields = "__all__"


class AssistantIDSerializer(serializers.Serializer):
Expand Down
12 changes: 3 additions & 9 deletions backend/api/serializers/checks_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,13 @@ class StructureCheckSerializer(serializers.ModelSerializer):
read_only=True
)

obligated_extensions = FileExtensionSerializer(many=True, required=False, default=[], read_only=True)
obligated_extensions = FileExtensionSerializer(many=True, required=False, default=[])

blocked_extensions = FileExtensionSerializer(many=True, required=False, default=[], read_only=True)
blocked_extensions = FileExtensionSerializer(many=True, required=False, default=[])

class Meta:
model = StructureCheck
fields = [
"id",
"name",
"project",
"obligated_extensions",
"blocked_extensions"
]
fields = "__all__"


class ExtraCheckSerializer(serializers.ModelSerializer):
Expand Down
16 changes: 5 additions & 11 deletions backend/api/serializers/course_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,7 @@ class CourseSerializer(serializers.ModelSerializer):

class Meta:
model = Course
fields = [
"id",
"name",
"academic_startyear",
"description",
"parent_course",
"teachers",
"assistants",
"students",
"projects",
]
fields = "__all__"


class CourseIDSerializer(serializers.Serializer):
Expand All @@ -51,6 +41,10 @@ class CourseIDSerializer(serializers.Serializer):
)


class CourseCloneSerializer(serializers.Serializer):
clone_assistants = serializers.BooleanField()


class StudentJoinSerializer(StudentIDSerializer):
def validate(self, data):
# The validator needs the course context.
Expand Down
2 changes: 1 addition & 1 deletion backend/api/serializers/faculty_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
class facultySerializer(serializers.ModelSerializer):
class Meta:
model = Faculty
fields = ["name"]
fields = "__all__"
2 changes: 1 addition & 1 deletion backend/api/serializers/group_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class GroupSerializer(serializers.ModelSerializer):

class Meta:
model = Group
fields = ["id", "project", "students", "score", "submissions"]
fields = "__all__"

def to_representation(self, instance):
data = super().to_representation(instance)
Expand Down
48 changes: 28 additions & 20 deletions backend/api/serializers/project_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,7 @@ class ProjectSerializer(serializers.ModelSerializer):

class Meta:
model = Project
fields = [
"id",
"name",
"description",
"visible",
"archived",
"start_date",
"deadline",
"max_score",
"score_visible",
"group_size",
"structure_checks",
"extra_checks",
"course",
"groups",
"submissions"
]
fields = "__all__"

def validate(self, data):
if "course" in self.context:
Expand All @@ -73,12 +57,36 @@ def validate(self, data):
return data


class CreateProjectSerializer(ProjectSerializer):
number_groups = serializers.IntegerField(min_value=1, required=False)

def create(self, validated_data):
# Pop the 'number_groups' field from validated_data
number_groups = validated_data.pop('number_groups', None)

# Create the project object without passing 'number_groups' field
project = super().create(validated_data)

# Create groups for the project, if specified
if number_groups is not None:

for _ in range(number_groups):
Group.objects.create(project=project)

elif project.group_size == 1:
# If the group_size is set to one, create a group for each student
students = project.course.students.all()

for student in students:
group = Group.objects.create(project=project)
group.students.add(student)

return project


class TeacherCreateGroupSerializer(serializers.Serializer):
number_groups = serializers.IntegerField(min_value=1)

def validate(self, data):
return data


class SubmissionStatusSerializer(serializers.Serializer):
non_empty_groups = serializers.IntegerField(read_only=True)
Expand Down
10 changes: 1 addition & 9 deletions backend/api/serializers/submission_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,7 @@ class SubmissionSerializer(serializers.ModelSerializer):

class Meta:
model = Submission
fields = [
"id",
"group",
"submission_number",
"submission_time",
"files",
"structure_checks_passed",
"extra_checks_results"
]
fields = "__all__"
extra_kwargs = {
"submission_number": {
"required": False,
Expand Down
11 changes: 1 addition & 10 deletions backend/api/serializers/teacher_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,4 @@ class TeacherSerializer(serializers.ModelSerializer):

class Meta:
model = Teacher
fields = [
"id",
"first_name",
"last_name",
"email",
"faculties",
"last_enrolled",
"create_time",
"courses",
]
fields = "__all__"
113 changes: 112 additions & 1 deletion backend/api/tests/test_course.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,26 +811,137 @@ def test_create_project(self):
"archived": False,
"days": 50,
"deadline": timezone.now() + timezone.timedelta(days=50),
"start_date": timezone.now()
"start_date": timezone.now(),
"group_size": 2
},
follow=True,
)

self.assertEqual(response.status_code, 200)
self.assertTrue(course.projects.filter(name="become champions").exists())

# Make sure there are no groups automatically made
project = course.projects.get(name="become champions")
self.assertEqual(project.groups.count(), 0)

def test_create_project_with_number_groups(self):
"""
Able to create a project for a course with a number of groups.
"""
course = get_course()
course.teachers.add(self.user)

response = self.client.post(
reverse("course-projects", args=[str(course.id)]),
data={
"name": "become champions",
"description": "win the jpl",
"visible": True,
"archived": False,
"days": 50,
"deadline": timezone.now() + timezone.timedelta(days=50),
"start_date": timezone.now(),
"number_groups": 5
},
follow=True,
)

self.assertEqual(response.status_code, 200)
self.assertTrue(course.projects.filter(name="become champions").exists())

# Make sure the groups are created
project = course.projects.get(name="become champions")
self.assertEqual(project.groups.count(), 5)

def test_create_individual_project(self):
"""
Able to create an individual project for a course.
"""
course = get_course()
course.teachers.add(self.user)

# Create some students
student1 = create_student(id=5, first_name="Simon", last_name="Mignolet", email="[email protected]")
student2 = create_student(id=6, first_name="Ronny", last_name="Deila", email="[email protected]")
student3 = create_student(id=7, first_name="Karel", last_name="Geraerts", email="[email protected]")

# Add the students to the course
course.students.add(student1)
course.students.add(student2)
course.students.add(student3)

response = self.client.post(
reverse("course-projects", args=[str(course.id)]),
data={
"name": "become champions",
"description": "win the jpl",
"visible": True,
"archived": False,
"days": 50,
"deadline": timezone.now() + timezone.timedelta(days=50),
"start_date": timezone.now(),
"group_size": 1
},
follow=True,
)

self.assertEqual(response.status_code, 200)
self.assertTrue(course.projects.filter(name="become champions").exists())

# Make sure the groups are created
project = course.projects.get(name="become champions")
self.assertEqual(project.groups.count(), 3)

for group in project.groups.all():
self.assertEqual(group.students.count(), 1)

def test_clone_course(self):
"""
Able to clone a course.
"""
course = get_course()
course.teachers.add(self.user)

# Create an assistant and add it to the course
assistant = get_assistant()
course.assistants.add(assistant)

response = self.client.post(
reverse("course-clone", args=[str(course.id)]),
data={"clone_assistants": False},
follow=True,
)

self.assertEqual(response.status_code, 200)
self.assertTrue(Course.objects.filter(name=course.name,
academic_startyear=course.academic_startyear + 1).exists())

# Make sure there are no assistants in the cloned course
cloned_course = Course.objects.get(name=course.name, academic_startyear=course.academic_startyear + 1)
self.assertFalse(cloned_course.assistants.exists())

def test_clone_with_assistants(self):
"""
Able to clone a course with assistants.
"""
course = get_course()
course.teachers.add(self.user)

# Create an assistant and add it to the course
assistant = get_assistant()
course.assistants.add(assistant)

# Clone the course with the assistants
response = self.client.post(
reverse("course-clone", args=[str(course.id)]),
data={"clone_assistants": True},
follow=True,
)

self.assertEqual(response.status_code, 200)
self.assertTrue(Course.objects.filter(name=course.name,
academic_startyear=course.academic_startyear + 1).exists())

# Make sure the assistant is also cloned
cloned_course = Course.objects.get(name=course.name, academic_startyear=course.academic_startyear + 1)
self.assertTrue(cloned_course.assistants.filter(id=assistant.id).exists())
2 changes: 2 additions & 0 deletions backend/api/views/admin_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.permissions import IsAdminUser
from drf_yasg.utils import swagger_auto_schema
from authentication.serializers import UserSerializer, UserIDSerializer
from authentication.models import User

Expand All @@ -12,6 +13,7 @@ class AdminViewSet(ReadOnlyModelViewSet):
serializer_class = UserSerializer
permission_classes = [IsAdminUser]

@swagger_auto_schema(request_body=UserIDSerializer)
def create(self, request: Request) -> Response:
"""
Make the provided user admin by setting `is_staff` = true.
Expand Down
Loading

0 comments on commit c2a741a

Please sign in to comment.