diff --git a/conf/permissions.dist.yml b/conf/permissions.dist.yml index cdd85ff6..cd310b4a 100644 --- a/conf/permissions.dist.yml +++ b/conf/permissions.dist.yml @@ -35,9 +35,9 @@ db_permissions: Course: getCourses: - allowed_roles: ['*'] + authenticated: true getCourse: - allowed_roles: ['*'] + authenticated: true updateCourse: admin_required: true addCourse: @@ -48,7 +48,7 @@ db_permissions: getGlobalUsers: admin_required: true getGlobalUser: - admin_required: true + allow_self_access: true checkGlobalUser: allowed_roles: ['course_admin', 'instructor'] updateGlobalUser: @@ -78,6 +78,7 @@ db_permissions: getGlobalCourseUsers: allowed_roles: ['course_admin', 'instructor'] getCourseUser: + allow_self_access: true allowed_roles: ['course_admin', 'instructor'] addCourseUser: allowed_roles: ['course_admin', 'instructor'] @@ -99,6 +100,7 @@ db_permissions: getAllUserSets: allowed_roles: ['course_admin', 'instructor'] getUserSets: + allow_self_access: true allowed_roles: ['course_admin', 'instructor'] addUserSet: allowed_roles: ['course_admin', 'instructor'] diff --git a/lib/WeBWorK3/Controller/Permission.pm b/lib/WeBWorK3/Controller/Permission.pm index 9a7c5606..737ef18a 100644 --- a/lib/WeBWorK3/Controller/Permission.pm +++ b/lib/WeBWorK3/Controller/Permission.pm @@ -62,9 +62,9 @@ sub checkPermission ($c) { } elsif ($perm_db->admin_required && !$user->{is_admin}) { $permitted = undef; $msg = 'This route requires admin privileges.'; - } elsif (!$course_id && $perm_db->allow_self_access && defined($c->param('user_id'))) { + } elsif (!$course_id && $perm_db->allow_self_access && defined($user_id)) { # Some routes allow self access, but the course_id is not defined. - $permitted = $user->{user_id} == $c->param('user_id'); + $permitted = $user->{user_id} == $user_id; } elsif ($course_id) { my $course_user = $c->schema->resultset('User')->getCourseUser( info => { diff --git a/src/common/models/courses.ts b/src/common/models/courses.ts index 28bc28db..f269fe20 100644 --- a/src/common/models/courses.ts +++ b/src/common/models/courses.ts @@ -106,12 +106,12 @@ export class Course extends Model { */ export interface ParseableUserCourse { - course_id?: number; - user_id?: number; - course_name?: string; + course_id: number; + user_id: number; + course_name: string; username?: string; visible?: boolean; - role?: string; + role: string; course_dates?: ParseableCourseDates; } export class UserCourse extends Model { @@ -126,6 +126,13 @@ export class UserCourse extends Model { static ALL_FIELDS = ['course_id', 'course_name', 'visible', 'course_dates', 'user_id', 'username', 'role']; + static DEFAULT_VALUES = { + course_id: 0, + user_id: 0, + course_name: 'DEFAULT_USER_COURSE', + role: 'unknown', + }; + get all_field_names(): string[] { return UserCourse.ALL_FIELDS; } @@ -134,7 +141,7 @@ export class UserCourse extends Model { return ['course_dates']; } - constructor(params: ParseableUserCourse = {}) { + constructor(params: ParseableUserCourse = UserCourse.DEFAULT_VALUES) { super(); this.set(params); } @@ -171,7 +178,8 @@ export class UserCourse extends Model { set role(value: string) { this._role = value; } clone(): UserCourse { - return new UserCourse(this.toObject()); + // typescript does not recognize the getters as keys when converting with .toObject() + return new UserCourse(this.toObject() as unknown as ParseableUserCourse); } isValid(): boolean { diff --git a/src/common/models/session.ts b/src/common/models/session.ts index 6e9c3e8b..e4503496 100644 --- a/src/common/models/session.ts +++ b/src/common/models/session.ts @@ -1,8 +1,8 @@ -import type { User } from 'src/common/models/users'; +import type { ParseableUser, User } from 'src/common/models/users'; import { parseBoolean } from './parsers'; export interface SessionInfo { - user: User; + user: ParseableUser; logged_in: boolean; message: string; } diff --git a/src/common/views.ts b/src/common/views.ts index 8eb59648..9f43dec7 100644 --- a/src/common/views.ts +++ b/src/common/views.ts @@ -49,6 +49,13 @@ export const student_views: Array = [ ]; export const instructor_views: Array = [ + { + name: 'Dashboard', + component_name: 'InstructorDashboard', + icon: 'speed', + route: 'dashboard', + sidebars: [] + }, { name: 'Calendar', component_name: 'Calendar', diff --git a/src/components/common/Login.vue b/src/components/common/Login.vue index 4c10b22f..1c707276 100644 --- a/src/components/common/Login.vue +++ b/src/components/common/Login.vue @@ -56,21 +56,21 @@ const login = async () => { }; const session_info = await checkPassword(username_info); - if (!session_info.logged_in) { + if (!session_info.logged_in || !session_info.user.user_id) { message.value = i18n.t('authentication.failure'); } else { // success session.updateSessionInfo(session_info); // permissions require access to user courses and respective roles - await session.fetchUserCourses(session_info.user.user_id); + await session.fetchUserCourses(); await permission_store.fetchRoles(); await permission_store.fetchRoutePermissions(); let forward = localStorage.getItem('afterLogin'); forward ||= (session_info.user.is_admin) ? '/admin' : - `/users/${session.user.user_id}/courses`; + `/users/${session_info.user.user_id}/courses`; localStorage.removeItem('afterLogin'); void router.push(forward); } diff --git a/src/components/common/UserCourses.vue b/src/components/common/UserCourses.vue index 1f87a377..54ffbc2a 100644 --- a/src/components/common/UserCourses.vue +++ b/src/components/common/UserCourses.vue @@ -36,48 +36,35 @@ import { computed } from 'vue'; import { useRouter } from 'vue-router'; import { useSessionStore } from 'src/stores/session'; +import { logger } from 'src/boot/logger'; -const session = useSessionStore(); +const session_store = useSessionStore(); const router = useRouter(); +const user = computed(() => session_store.user); + // This is used to simplify the UI. const course_types = computed(() => [ - { name: 'Student', courses: student_courses.value }, - { name: 'Instrutor', courses: instructor_courses.value } + { name: 'Student', courses: session_store.user_courses.filter(c => c.role === 'student') }, + { name: 'Instructor', courses: session_store.user_courses.filter(c => c.role === 'instructor') } ]); -const student_courses = computed(() => - // for some reason on load the user_course.role is undefined. - session.user_courses.filter(user_course => user_course.role === 'student')); - -const instructor_courses = computed(() => - // For some reason on load the user_course.role is undefined. - session.user_courses.filter(user_course => user_course.role === 'instructor') -); -const user = computed(() => session.user); +const switchCourse = (course_id?: number) => { + if (!course_id) { + logger.error('[UserCourses/switchCourse]: the course_id is 0 or undefined.'); + return; + } + session_store.setCourse(course_id); -const switchCourse = async (course_id: number) => { - const student_course = student_courses.value.find(c => c.course_id === course_id); - const instructor_course = instructor_courses.value.find(c => c.course_id === course_id); - if (student_course) { - session.setCourse({ - course_name: student_course.course_name, - course_id: student_course.course_id, - role: 'student' - }); - await router.push({ + if (session_store.course.role === 'student') { + void router.push({ name: 'StudentDashboard', - params: { course_id: student_course.course_id } - }); - } else if (instructor_course) { - session.setCourse({ - course_name: instructor_course.course_name, - course_id: instructor_course.course_id, - role: 'instructor' + params: { course_id } }); - await router.push({ - name: 'instructor', - params: { course_id: instructor_course.course_id } + } else if (session_store.course.role === 'instructor') { + void router.push({ + name: 'InstructorDashboard', + params: { course_id } }); } }; diff --git a/src/components/student/Student.vue b/src/components/student/Student.vue index c880750f..a6a079f4 100644 --- a/src/components/student/Student.vue +++ b/src/components/student/Student.vue @@ -21,31 +21,22 @@ const loadStudentSets = async () => { // Fetch only the current user info. await user_store.setSessionUser(); - logger.debug(`[Student/loadStudenSet]: loading data for course ${session_store.course.course_id}`); + logger.debug(`[Student/loadStudentSets]: loading data for course ${session_store.course.course_id}`); if (session_store.course.course_id > 0) { // Fetch all problem sets and user sets await problem_set_store.fetchProblemSets(session_store.course.course_id); - await problem_set_store.fetchUserSetsForUser({ user_id: session_store.user.user_id }); - + if (session_store.user.user_id) { + await problem_set_store.fetchUserSetsForUser({ user_id: session_store.user.user_id }); + } } }; const course_id = parseRouteCourseID(route); -const course = session_store.user_courses.find(c => c.course_id === course_id); -if (course) { - session_store.setCourse({ - course_id: course_id, - course_name: course.course_name - }); -} else { - logger.warn(`Can't find ${course_id} in ${session_store.user_courses - .map((c) => c.course_id).join(', ')}`); -} +session_store.setCourse(course_id); await loadStudentSets(); watch(() => session_store.course.course_id, async () => { - await loadStudentSets(); }); diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 5f462e55..7bf0ae33 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -10,9 +10,9 @@ - + - + + + diff --git a/src/router/routes.ts b/src/router/routes.ts index a5ba232c..d50e0153 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -37,7 +37,7 @@ const routes: RouteRecordRaw[] = [ ) }, { - path: 'courses/:course_id', + path: 'courses/:course_id/student', component: () => import( /* webpackChunkName: "Student" */ @@ -115,6 +115,15 @@ const routes: RouteRecordRaw[] = [ name: 'instructor', meta: { requiresAuth: true }, children: [ + { + path: '', + name: 'InstructorDashboard', + component: () => + import( + /* webpackChunkName: "Dashboard" */ + 'pages/instructor/Dashboard.vue' + ) + }, { path: 'settings', name: 'Settings', diff --git a/src/stores/permissions.ts b/src/stores/permissions.ts index 9c157eb9..ef31368e 100644 --- a/src/stores/permissions.ts +++ b/src/stores/permissions.ts @@ -54,7 +54,7 @@ export const usePermissionStore = defineStore('permission', { // admin-only routes const session_store = useSessionStore(); const user = session_store.user; - if (permission.admin_required) return user.is_admin; + if (permission.admin_required) return user.is_admin ?? false; // routes that 'belong' to a user const route_user_id = parseRouteUserID(route); diff --git a/src/stores/session.ts b/src/stores/session.ts index 671232df..12341d37 100644 --- a/src/stores/session.ts +++ b/src/stores/session.ts @@ -2,9 +2,9 @@ import { defineStore } from 'pinia'; import { api } from 'boot/axios'; -import { User } from 'src/common/models/users'; +import { ParseableUser, User } from 'src/common/models/users'; import type { SessionInfo } from 'src/common/models/session'; -import { ParseableUserCourse, UserCourse } from 'src/common/models/courses'; +import { ParseableUserCourse } from 'src/common/models/courses'; import { logger } from 'boot/logger'; import { ResponseError } from 'src/common/api-requests/errors'; @@ -19,13 +19,15 @@ interface CourseInfo { course_id: number; } -// SessionState should contain a de facto User, already parsed +// SessionState should contain a de facto User, already parsed. +// In order for the session to be persistent, we need to store the fields username, +// user_id, etc. instead of _username, _user_id from a Model. export interface SessionState { logged_in: boolean; expiry: number; - user: User; + user: ParseableUser; course: CourseInfo; - user_courses: UserCourse[]; + user_courses: ParseableUserCourse[]; } export const useSessionStore = defineStore('session', { @@ -34,7 +36,7 @@ export const useSessionStore = defineStore('session', { state: (): SessionState => ({ logged_in: false, expiry: 0, - user: new User({ username: 'logged_out' }), + user: { username: 'logged_out' }, course: { course_id: 0, role: '', @@ -61,28 +63,40 @@ export const useSessionStore = defineStore('session', { if (this.logged_in) { this.user = session_info.user; } else { - this.user = new User({ username: 'logged_out' }); + this.user = new User({ username: 'logged_out' }).toObject(); } }, - setCourse(course: CourseInfo): void { - this.course = course; - this.course.role = this.user_courses.find((c) => c.course_id === course.course_id)?.role || ''; + setCourse(course_id: number): void { + if (course_id === this.course.course_id) return; + const new_course = this.user_courses.find((c) => c.course_id === course_id); + if (!new_course) { + logger.error(`[session_store] Attempted to select course #${course_id} -- not found!`); + this.course = { + course_id: 0, + course_name: '', + role: 'unknown' + }; + return; + } + // in order to be reactive, replace the entire `this.course` object + this.course = { + course_id, + course_name: new_course.course_name, + role: new_course.role + }; }, /** * fetch all User Courses for a given user. * @param {number} user_id */ - async fetchUserCourses(user_id: number): Promise { - const response = await api.get(`users/${user_id}/courses`); + async fetchUserCourses(): Promise { + if (!this.user.user_id) throw { + message: 'No user has been authenticated', + } as ResponseError; + + const response = await api.get(`users/${this.user.user_id}/courses`); if (response.status === 200) { - this.user_courses = (response.data as ParseableUserCourse[]) - .map(user_course => new UserCourse({ - course_id: user_course.course_id, - user_id: user_course.user_id, - visible: user_course.visible, - role: user_course.role, - course_name: user_course.course_name, - })); + this.user_courses = response.data as ParseableUserCourse[]; } else { logger.error(response.data); throw response.data as ResponseError; @@ -90,7 +104,7 @@ export const useSessionStore = defineStore('session', { }, logout() { this.logged_in = false; - this.user = new User({ username: 'logged_out' }); + this.user = new User({ username: 'logged_out' }).toObject(); this.course = { course_id: 0, role: '', course_name: '' }; useProblemSetStore().clearAll(); useSettingsStore().clearAll(); diff --git a/src/stores/set_problems.ts b/src/stores/set_problems.ts index 6413fc8c..b4ef07ec 100644 --- a/src/stores/set_problems.ts +++ b/src/stores/set_problems.ts @@ -106,9 +106,13 @@ export const useSetProblemStore = defineStore('set_problems', { * Fetch all set problems with given course_id. */ async fetchSetProblems(course_id: number): Promise { - const response = await api.get(`courses/${course_id}/problems`); - const all_problems = response.data as Array; - this.set_problems = all_problems.map((prob) => parseProblem(prob, 'Set') as SetProblem); + const response = await api.get(`courses/${course_id}/problems`) + .then((response) => { + // TODO: throw exceptions via axios hook instead + if (response.status !== 200) throw (response.data as Error); + return response.data as Array; + }); + if (response) this.set_problems = response.map((prob) => parseProblem(prob, 'Set') as SetProblem); }, /** @@ -118,7 +122,11 @@ export const useSetProblemStore = defineStore('set_problems', { async addSetProblem(problem: LibraryProblem, set_id: number): Promise { if (!problem.isValid()) await invalidError(problem, 'The added problem is invalid'); - const course_id = useSessionStore().course.course_id; + const session_store = useSessionStore(); + + const course_id = session_store.course.course_id; + if (!course_id) logger.error('[addSetProblem] cannot add problem when session course is not set'); + const prob = new SetProblem({ problem_params: problem.location_params, set_id: set_id @@ -127,7 +135,8 @@ export const useSetProblemStore = defineStore('set_problems', { // delete the render params. Not in the database. delete prob.render_params; const response = await api.post(`/courses/${course_id}/sets/${set_id}/problems`, prob). - catch((e: Error) => logger.error(`[addSetProblem] ${JSON.stringify(prob)} failed with ${e.message}`)); + catch((e: Error) => + logger.error(`[addSetProblem] ${JSON.stringify(prob)} failed with ${e.message}`)); const new_problem = new SetProblem(response.data as ParseableSetProblem); this.set_problems.push(new_problem); diff --git a/src/stores/users.ts b/src/stores/users.ts index fede6a6a..c84f2a3d 100644 --- a/src/stores/users.ts +++ b/src/stores/users.ts @@ -191,14 +191,14 @@ export const useUserStore = defineStore('user', { */ async setSessionUser() { const session_store = useSessionStore(); + const user_id = session_store.user.user_id ?? 0; // if there is no user in the session don't fetch the user. - if (session_store.user.user_id === 0) return; + if (user_id === 0) return; // Get the global user. - const user_response = await api.get(`users/${session_store.user.user_id}`); + const user_response = await api.get(`users/${user_id}`); this.users = [ new User(user_response.data as ParseableUser)]; // fetch the course user information for this use - const response = await api.get(`courses/${session_store.course.course_id}/users/${ - session_store.user.user_id}`); + const response = await api.get(`courses/${session_store.course.course_id}/users/${user_id}`); this.db_course_users = [ new DBCourseUser(response.data as ParseableDBCourseUser)]; }, // CourseUser actions diff --git a/tests/stores/problem_sets.spec.ts b/tests/stores/problem_sets.spec.ts index 6ac06c74..41d1aa27 100644 --- a/tests/stores/problem_sets.spec.ts +++ b/tests/stores/problem_sets.spec.ts @@ -15,12 +15,12 @@ import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; import { useProblemSetStore } from 'src/stores/problem_sets'; import { useCourseStore } from 'src/stores/courses'; import { useSessionStore } from 'src/stores/session'; -import { api } from 'src/boot/axios'; import { HomeworkSet, ProblemSet, Quiz, ReviewSet } from 'src/common/models/problem_sets'; import { Course } from 'src/common/models/courses'; import { cleanIDs, loadCSV } from '../utils'; +import { checkPassword } from 'src/common/api-requests/session'; const app = createApp({}); @@ -34,7 +34,10 @@ describe('Problem Set store tests', () => { setActivePinia(pinia); // Login to the course as the admin in order to be authenticated for the rest of the test. - await api.post('login', { username: 'admin', password: 'admin' }); + const session_info = await checkPassword({ username: 'admin', password: 'admin' }); + const session_store = useSessionStore(); + session_store.updateSessionInfo(session_info); + await session_store.fetchUserCourses(); const problem_set_config = { params: ['set_params', 'set_dates' ], @@ -64,11 +67,7 @@ describe('Problem Set store tests', () => { precalc_course = courses_store.courses.find(course => course.course_name === 'Precalculus') as Course; // Add the precalc course to the session; - const session_store = useSessionStore(); - session_store.setCourse({ - course_id: precalc_course.course_id, - course_name: precalc_course.course_name - }); + session_store.setCourse(precalc_course.course_id); }); // sort by set name and clean up the _id tags. diff --git a/tests/stores/session.spec.ts b/tests/stores/session.spec.ts index a30d72da..f26b224f 100644 --- a/tests/stores/session.spec.ts +++ b/tests/stores/session.spec.ts @@ -19,7 +19,7 @@ import { checkPassword } from 'src/common/api-requests/session'; import { Course, UserCourse } from 'src/common/models/courses'; import { SessionInfo } from 'src/common/models/session'; -import { User } from 'src/common/models/users'; +import { ParseableUser, User } from 'src/common/models/users'; import { cleanIDs, loadCSV } from '../utils'; @@ -29,18 +29,25 @@ describe('Session Store', () => { let lisa_courses: UserCourse[]; let lisa: User; - const user: User = new User({ + // session now just stores objects not models: + const user: ParseableUser = { first_name: 'Homer', last_name: 'Simpson', user_id: 1234, email: 'homer@msn.com', username: 'homer', is_admin: false, - }); + }; - const logged_out: User = new User({ - username: 'logged_out' - }); + const logged_out: ParseableUser = { + username: 'logged_out', + email: '', + last_name: '', + first_name: '', + user_id: 0, + is_admin: false, + student_id: '' + }; const session_info: SessionInfo = { logged_in: true, @@ -82,6 +89,7 @@ describe('Session Store', () => { const course = courses_from_csv.find(c => c.course_name == user_course.course_name) ?? new Course(); return new UserCourse({ + course_id: 0, // will this be stripped before comparison later? course_name: course.course_name, user_id: lisa.user_id, visible: course.visible, @@ -97,7 +105,7 @@ describe('Session Store', () => { const session = useSessionStore(); expect(session.logged_in).toBe(false); - expect(session.user).toStrictEqual(logged_out); + expect(session.user.username).toBe('logged_out'); expect(session.course).toStrictEqual({ course_id: 0, course_name: '', @@ -113,6 +121,12 @@ describe('Session Store', () => { expect(session_info.logged_in).toBe(true); expect(session_info.user).toStrictEqual(lisa.toObject()); + const session = useSessionStore(); + session.updateSessionInfo(session_info); + + expect(session.logged_in).toBe(true); + expect(session.user).toStrictEqual(lisa.toObject()); + }); // sort by course name and clean up the _id tags. @@ -123,24 +137,22 @@ describe('Session Store', () => { test('check user courses', async () => { const session_store = useSessionStore(); - await session_store.fetchUserCourses(lisa.user_id); - expect(sortAndClean(session_store.user_courses as UserCourse[])) + await session_store.fetchUserCourses(); + expect(sortAndClean(session_store.user_courses.map(c => new UserCourse(c)))) .toStrictEqual(sortAndClean(lisa_courses)); }); test('update the session', () => { const session = useSessionStore(); - session.updateSessionInfo(session_info); - - expect(session.logged_in).toBe(true); - expect(session.user).toStrictEqual(user); - + const user_course = session.user_courses.find((c) => c.course_name === 'Arithmetic'); + expect(user_course?.course_id).toBeTruthy(); const course = { - course_name: 'Arithmetic', - course_id: 1 + course_name: user_course?.course_name, + course_id: user_course?.course_id, + role: user_course?.role }; - session.setCourse(course); + session.setCourse(user_course?.course_id ?? 0); expect(session.course).toStrictEqual(course); }); diff --git a/tests/stores/set_problems.spec.ts b/tests/stores/set_problems.spec.ts index 485e0dd3..0d4bfb2d 100644 --- a/tests/stores/set_problems.spec.ts +++ b/tests/stores/set_problems.spec.ts @@ -11,7 +11,6 @@ import { createApp } from 'vue'; import { createPinia, setActivePinia } from 'pinia'; import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'; -import { api } from 'boot/axios'; import { useCourseStore } from 'src/stores/courses'; import { useUserStore } from 'src/stores/users'; @@ -27,6 +26,8 @@ import { DBUserHomeworkSet, mergeUserSet, UserSet } from 'src/common/models/user import { Dictionary, generic } from 'src/common/models'; import { loadCSV, cleanIDs } from '../utils'; +import { checkPassword } from 'src/common/api-requests/session'; +import { logger } from 'src/boot/logger'; const app = createApp({}); @@ -43,8 +44,10 @@ describe('Problem Set store tests', () => { app.use(pinia); setActivePinia(pinia); - // Login to the course as the admin in order to be authenticated for the rest of the test. - await api.post('login', { username: 'admin', password: 'admin' }); + // Login to the course as Precalculus instructor in order to be authenticated for the rest of the test. + const session_info = await checkPassword({ username: 'frink', password: 'frink' }); + const session_store = useSessionStore(); + session_store.updateSessionInfo(session_info); const problem_set_config = { params: ['set_params', 'set_dates' ], @@ -117,11 +120,8 @@ describe('Problem Set store tests', () => { await problem_set_store.fetchAllUserSets(precalc_course.course_id); // Add the precalc course to the session; - const session_store = useSessionStore(); - session_store.setCourse({ - course_id: precalc_course.course_id, - course_name: precalc_course.course_name - }); + await session_store.fetchUserCourses(); + session_store.setCourse(precalc_course.course_id); }); describe('fetching set problems for a course', () => { @@ -145,9 +145,11 @@ describe('Problem Set store tests', () => { const problem_set_store = useProblemSetStore(); const set_problem_store = useSetProblemStore(); const hw1 = problem_set_store.findProblemSet({ set_name: 'HW #1' }); + expect(hw1?.set_name).toStrictEqual('HW #1'); // grab the set problems for HW #1 so we know which is the next problem number. const probs = set_problem_store.findSetProblems({ set_name: 'HW #1' }); + expect(probs.length).toBeGreaterThan(0); const problem_number = probs[probs.length - 1].problem_number + 1; diff --git a/tests/stores/user_sets.spec.ts b/tests/stores/user_sets.spec.ts index e2578111..d5c40249 100644 --- a/tests/stores/user_sets.spec.ts +++ b/tests/stores/user_sets.spec.ts @@ -28,6 +28,7 @@ import { } from 'src/common/models/user_sets'; import { loadCSV, cleanIDs } from '../utils'; +import { checkPassword } from 'src/common/api-requests/session'; const app = createApp({}); @@ -42,8 +43,11 @@ describe('Tests user sets and merged user sets in the problem set store', () => app.use(pinia); setActivePinia(pinia); - // Login to the course as the admin in order to be authenticated for the rest of the test. - await api.post('login', { username: 'admin', password: 'admin' }); + // Login to the course as Precalculus instructor in order to be authenticated for the rest of the test. + const session_info = await checkPassword({ username: 'frink', password: 'frink' }); + const session_store = useSessionStore(); + session_store.updateSessionInfo(session_info); + await session_store.fetchUserCourses(); const problem_set_config = { params: ['set_params', 'set_dates' ], @@ -73,11 +77,7 @@ describe('Tests user sets and merged user sets in the problem set store', () => precalc_course = courses_store.courses.find(course => course.course_name === 'Precalculus') as Course; // Add the precalc course to the session; - const session_store = useSessionStore(); - session_store.setCourse({ - course_id: precalc_course.course_id, - course_name: precalc_course.course_name - }); + session_store.setCourse(precalc_course.course_id); // Fetch course users and they are needed below. const user_store = useUserStore(); diff --git a/tests/unit-tests/courses.spec.ts b/tests/unit-tests/courses.spec.ts index df108728..974376ab 100644 --- a/tests/unit-tests/courses.spec.ts +++ b/tests/unit-tests/courses.spec.ts @@ -108,7 +108,7 @@ describe('Test Course Models', () => { const default_user_course = { course_id: 0, user_id: 0, - course_name: '', + course_name: 'DEFAULT_USER_COURSE', username: '', visible: true, role: 'unknown', @@ -145,7 +145,8 @@ describe('Test Course Models', () => { describe('Updating a UserCourse', () => { test('set fields of a user course', () => { - const user_course = new UserCourse({ course_name: 'Arithmetic' }); + const user_course = new UserCourse(); + user_course.course_id = 5; expect(user_course.course_id).toBe(5); @@ -166,32 +167,25 @@ describe('Test Course Models', () => { }); describe('Checking valid and invalid creation parameters.', () => { - test('Parsing of undefined and null values', () => { - const course1 = new UserCourse({ course_name: 'Arithmetic' }); - const course2 = new UserCourse({ + test('Create a course with invalid fields', () => { + const c1 = new UserCourse({ + course_id: 1, + user_id: 1, course_name: 'Arithmetic', - user_id: undefined, - course_id: undefined + username: 'homer', + role: 'student' }); - expect(course1).toStrictEqual(course2); - - // the following allow to pass in non-valid parameters for testing - const params = { course_name: 'Arithmetic', course_id: null }; - const course3 = new UserCourse(params as unknown as ParseableCourse); - expect(course1).toStrictEqual(course3); - }); - - test('Create a course with invalid fields', () => { - const c1 = new UserCourse({ course_name: 'Arithmetic', username: 'homer', role: 'student' }); expect(c1.isValid()).toBe(true); c1.course_name = ''; expect(c1.isValid()).toBe(false); - c1.set({ course_name: 'Arithmetic', user_id: -1 }); + c1.course_name = 'Arithmetic'; + c1.user_id = -1; expect(c1.isValid()).toBe(false); - c1.set({ user_id: 10, course_id: -1 }); + c1.user_id = 10; + c1.course_id = -1; expect(c1.isValid()).toBe(false); c1.course_id = 10; @@ -210,6 +204,8 @@ describe('Test Course Models', () => { test('Create a user course with invalid dates', () => { const c1 = new UserCourse({ + course_id: 1, + user_id: 1, course_name: 'Arithmetic', username: 'homer', role: 'student',