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

Dashboard based on role + course creation #216

Merged
merged 18 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from 17 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
4 changes: 4 additions & 0 deletions backend/api/tests/test_course.py
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,10 @@ def test_create_course(self):
self.assertEqual(response.status_code, 201)
self.assertTrue(Course.objects.filter(name="Introduction to Computer Science").exists())

# Make sure the teacher is added to the course
course = Course.objects.get(name="Introduction to Computer Science")
self.assertTrue(course.teachers.filter(id=self.user.id).exists())

def test_create_project(self):
"""
Able to create a project for a course.
Expand Down
19 changes: 18 additions & 1 deletion backend/api/views/course_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
from rest_framework.response import Response
from rest_framework.request import Request
from drf_yasg.utils import swagger_auto_schema
from rest_framework import status
from api.models.course import Course
from api.permissions.course_permissions import (
CoursePermission,
CourseAssistantPermission,
CourseStudentPermission,
CourseTeacherPermission
)
from api.permissions.role_permissions import IsTeacher
from api.permissions.role_permissions import IsTeacher, is_teacher
from api.serializers.course_serializer import (
CourseSerializer, StudentJoinSerializer, StudentLeaveSerializer, CourseCloneSerializer,
TeacherJoinSerializer, TeacherLeaveSerializer
Expand All @@ -29,6 +30,22 @@ class CourseViewSet(viewsets.ModelViewSet):
serializer_class = CourseSerializer
permission_classes = [IsAdminUser | CoursePermission]

def create(self, request: Request, *_):
"""Override the create method to add the teacher to the course"""
serializer = CourseSerializer(data=request.data, context={"request": request})

if serializer.is_valid(raise_exception=True):
course = serializer.save()

# If it was a teacher who created the course, add them as a teacher
if is_teacher(request.user):
course.teachers.add(request.user.id)

return Response(
{"message": gettext("courses.success.create")},
status=status.HTTP_201_CREATED
)

@action(detail=True, permission_classes=[IsAdminUser | CourseAssistantPermission])
def assistants(self, request: Request, **_):
"""Returns a list of assistants for the given course"""
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/assets/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"header": {
"logo": "Ghent University logo",
"login": "login",
"view": "View as {0}",
"navigation": {
"dashboard": "Dashboard",
"calendar": "Calendar",
Expand All @@ -19,7 +20,9 @@
"views": {
"dashboard": {
"courses": "My courses",
"projects": "Current projects"
"projects": "Current projects",
"no_projects": "No projects available for this academic year.",
"no_courses": "No courses available for this academic year."
},
"login": {
"title": "Login",
Expand All @@ -38,6 +41,12 @@
"deadline": "Deadline",
"submissionStatus": "Indienstatus",
"groupMembers": "Group members"
},
"courses": {
"create": "Create course",
"name": "Course name",
"description": "Description",
"year": "Academic year"
}
},
"composables": {
Expand All @@ -64,6 +73,13 @@
"open": "details"
}
},
"types": {
"roles": {
"student": "Student",
"assistant": "Assistant",
"teacher": "Teacher"
}
},
"toasts": {
"messages": {
"unknown": "An unknown error has occurred."
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/assets/lang/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"views": {
"dashboard": {
"courses": "Mijn vakken",
"projects": "Lopende projecten"
"projects": "Lopende projecten",
"no_projects": "Geen projecten beschikbaar voor dit academiejaar.",
"no_courses": "Geen vakken beschikbaar voor dit academiejaar."
},
"login": {
"title": "Inloggen",
Expand All @@ -39,7 +41,13 @@
"deadline": "Deadline",
"submissionStatus": "Indienstatus",
"groupMembers": "Groepsleden"
}
},
"courses": {
"create": "Creëer vak",
"name": "Vaknaam",
"description": "Beschrijving",
"year": "Academiejaar"
}
},
"composables": {
"helpers": {
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/composables/services/courses.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ export function useCourses() {
await getList<Course>(endpoint, courses, Course.fromJSON);
}

async function getCoursesByTeacher(teacher_id: string) {
const endpoint = endpoints.courses.byTeacher.replace('{teacher_id}', teacher_id);
await getList<Course>(endpoint, courses, Course.fromJSON);
}

async function getCourseByAssistant(assistant_id: string) {
const endpoint = endpoints.courses.byAssistant.replace('{assistant_id}', assistant_id);
await getList<Course>(endpoint, courses, Course.fromJSON);
}

async function createCourse(course_data: Course) {
const endpoint = endpoints.courses.index;
await create<Course>(endpoint,
Expand Down Expand Up @@ -50,6 +60,8 @@ export function useCourses() {
getCourseByID,
getCourses,
getCoursesByStudent,
getCoursesByTeacher,
getCourseByAssistant,

createCourse,
cloneCourse,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/config/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const endpoints = {
index: '/api/courses/',
retrieve: '/api/courses/{id}/',
byStudent: '/api/students/{student_id}/courses/',
byTeacher: '/api/teachers/{teacher_id}/courses/',
byAssistant: '/api/assistants/{assistant_id}/courses/',
clone: '/api/courses/{course_id}/clone/'
},
students: {
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import DashboardView from '@/views/dashboard/DashboardView.vue';
import CourseView from '@/views/courses/CourseView.vue';
import CreateCourseView from '@/views/courses/CreateCourseView.vue';
import Dummy from '@/components/Dummy.vue';
import LoginView from '@/views/authentication/LoginView.vue';
import CalendarView from '@/views/calendar/CalendarView.vue';
Expand All @@ -27,7 +28,7 @@ const routes: RouteRecordRaw[] = [
// Courses
{ path: '/courses', children: [
{ path: '', component: Dummy, name: 'courses' },
{ path: 'create', component: Dummy, name: 'course-create' },
{ path: 'create', component: CreateCourseView, name: 'course-create' },
// Single course
{ path: ':courseId', children: [
{ path: '', component: CourseView, name: 'course' },
Expand Down
77 changes: 71 additions & 6 deletions frontend/src/store/authentication.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,81 @@ import {Teacher} from '@/types/Teacher.ts';
import {Student} from '@/types/Student.ts';
import {Assistant} from '@/types/Assistant.ts';
import {useLocalStorage} from '@vueuse/core';
import {computed, ref} from 'vue';
import { useCourses } from '@/composables/services/courses.service';
import {computed, ref, watch} from 'vue';

export const useAuthStore = defineStore('auth', () => {
/* Stores */
const user = ref<User|null>(null);
const teacher = ref<Teacher|null>(null);
const student = ref<Student|null>(null);
const assistant = ref<Assistant|null>(null);
const view = useLocalStorage<Role|null>('view', null);
const intent = useLocalStorage<string>('intent', '/');

/* Services */
const { courses, getCoursesByTeacher, getCoursesByStudent, getCourseByAssistant } = useCourses();

/* Update the user object when the view changes. */
watch(view, async () => {
initUser();
BramMeir marked this conversation as resolved.
Show resolved Hide resolved
});

const initUser = async () => {
BramMeir marked this conversation as resolved.
Show resolved Hide resolved
if (user.value !== null) {
if (view.value === 'teacher') {
await getCoursesByTeacher(user.value.id);

user.value = new Teacher(
user.value.id,
user.value.username,
user.value.email,
user.value.first_name,
user.value.last_name,
user.value.last_enrolled,
user.value.is_staff,
user.value.roles,
[],
courses.value ?? [],
user.value.create_time,
user.value.last_login
);
}else if (view.value === 'student') {
await getCoursesByStudent(user.value.id);

user.value = new Student(
user.value.id,
user.value.username,
user.value.email,
user.value.first_name,
user.value.last_name,
user.value.is_staff,
user.value.last_enrolled,
user.value.create_time,
user.value.last_login,
user.value.id,
user.value.roles,
courses.value ?? []
);
}else {
await getCourseByAssistant(user.value.id);

user.value = new Assistant(
user.value.id,
user.value.username,
user.value.email,
user.value.first_name,
user.value.last_name,
user.value.last_enrolled,
user.value.is_staff,
user.value.roles,
[],
courses.value ?? [],
user.value.create_time,
user.value.last_login
);
}
}
};


/**
* Attempt to log in the user using a CAS ticket.
*
Expand Down Expand Up @@ -61,7 +125,8 @@ export const useAuthStore = defineStore('auth', () => {
view.value = user.value.roles[0];
}

// TODO: Get the teacher, student, and assistant information.
// Init the user depending on the role selected.
initUser();

}).catch((error) => {
add({
Expand All @@ -86,7 +151,7 @@ export const useAuthStore = defineStore('auth', () => {
});

return {
user, teacher, student, assistant, view, intent,
user, view, intent,
login, refresh, logout,
isAuthenticated
}
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/types/Assistant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export class Assistant extends User {
public faculties: Faculty[] = [],
public courses: Course[] = [],
public create_time: Date,
public last_login: Date |null,
public last_login: Date |null
) {
super(id, username, email, first_name, last_name, last_enrolled, is_staff, roles, faculties, create_time, last_login);
super(id, username, email, first_name, last_name, last_enrolled, is_staff, roles, faculties, create_time, last_login, courses);
}

/**
Expand All @@ -41,4 +41,13 @@ export class Assistant extends User {
assistant.last_login ? new Date(assistant.last_login) : null
);
}

/**
* Check if the user is a assistant.
*
* @returns boolean
*/
public isAssistant(): boolean {
return true;
}
}
11 changes: 10 additions & 1 deletion frontend/src/types/Student.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class Student extends User {
public groups: Group[] = [],
public faculties: Faculty[] = [],
) {
super(id, username, email, first_name, last_name, last_enrolled, is_staff, roles, faculties, create_time, last_login);
super(id, username, email, first_name, last_name, last_enrolled, is_staff, roles, faculties, create_time, last_login, courses);
}

/**
Expand All @@ -42,4 +42,13 @@ export class Student extends User {
student.student_id
);
}

/**
* Check if the user is a student.
*
* @returns boolean
*/
public isStudent(): boolean {
return true;
}
}
11 changes: 10 additions & 1 deletion frontend/src/types/Teacher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class Teacher extends User {
public create_time: Date,
public last_login: Date |null,
) {
super(id, username, email, first_name, last_name, last_enrolled, is_staff, roles, faculties, create_time, last_login);
super(id, username, email, first_name, last_name, last_enrolled, is_staff, roles, faculties, create_time, last_login, courses);
}

/**
Expand All @@ -42,4 +42,13 @@ export class Teacher extends User {
teacher.last_login ? new Date(teacher.last_login) : null
);
}

/**
* Check if the user is a teacher.
*
* @returns boolean
*/
public isTeacher(): boolean {
return true;
}
}
8 changes: 5 additions & 3 deletions frontend/src/types/User.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Course } from "./Course";
import { Faculty } from "./Faculty";

export type Role = 'user' | 'student' | 'assistant' | 'teacher';
Expand All @@ -15,6 +16,7 @@ export class User {
public faculties: Faculty[] = [],
public create_time: Date,
public last_login: Date |null,
public courses: Course[] = []
) {
}

Expand All @@ -33,7 +35,7 @@ export class User {
* @returns boolean
*/
public isStudent(): boolean {
return this.roles.includes('student');
return false;
}

/**
Expand All @@ -42,7 +44,7 @@ export class User {
* @returns boolean
*/
public isAssistant(): boolean {
return this.roles.includes('assistant');
return false;
}

/**
Expand All @@ -51,7 +53,7 @@ export class User {
* @returns boolean
*/
public isTeacher(): boolean {
return this.roles.includes('teacher');
return false;
}

/**
Expand Down
Loading
Loading