342 lines
8.0 KiB
JavaScript
342 lines
8.0 KiB
JavaScript
import { supabase } from '../../functions/supabase';
|
|
import { isUUID } from '../../functions/isUUID';
|
|
import { QUESTION_TYPE } from '../../../components/Question/constants';
|
|
|
|
export async function fetchCourse(courseId, session) {
|
|
console.log(`courseId`, courseId);
|
|
let jsonUser;
|
|
|
|
if (!process.browser) {
|
|
// try {
|
|
// jsonUser = JSON.parse(session.user);
|
|
// } catch (error) {
|
|
// console.log('Token is expired probably cause user not found');
|
|
// return {
|
|
// data: [],
|
|
// cantFetch: true,
|
|
// };
|
|
// // return this.redirect(301, '/login');
|
|
// }
|
|
}
|
|
|
|
const { data, error } = await supabase
|
|
.from('course')
|
|
.select(
|
|
`
|
|
id,
|
|
title,
|
|
description,
|
|
overview,
|
|
logo,
|
|
group(*,
|
|
members:groupmember(*,
|
|
profile(*)
|
|
)
|
|
),
|
|
lessons:lesson(
|
|
id, title,public, lesson_at, call_url, is_complete,created_at,
|
|
profile:teacher_id(id, avatar_url, fullname)
|
|
)
|
|
`
|
|
)
|
|
.match({ id: courseId })
|
|
.single();
|
|
console.log(`error`, error);
|
|
if (!data || error) {
|
|
console.log(`data`, data);
|
|
console.log(`fetchCourse => error`, error);
|
|
return this.redirect(301, '/courses');
|
|
}
|
|
|
|
return {
|
|
data,
|
|
error,
|
|
};
|
|
}
|
|
|
|
export async function fetchGroup(groupId) {
|
|
const { data, error } = await supabase
|
|
.from('group')
|
|
.select(`*,members:groupmember(*,profile(*))`)
|
|
.match({ id: groupId })
|
|
.single();
|
|
|
|
return {
|
|
data,
|
|
error,
|
|
};
|
|
}
|
|
|
|
export async function setProfileIdOfGroupMember(email, profileId) {
|
|
const { data, error } = await supabase
|
|
.from('groupmember')
|
|
.update({
|
|
email: null,
|
|
profile_id: profileId,
|
|
})
|
|
.match({ email: email });
|
|
|
|
return {
|
|
data,
|
|
error,
|
|
};
|
|
}
|
|
|
|
export async function updateCourse(courseId, course) {
|
|
if (course.avatar) {
|
|
const filename = `course/${courseId + Date.now()}.webp`;
|
|
|
|
const { data } = await supabase.storage
|
|
.from('avatars')
|
|
.upload(filename, course.avatar, {
|
|
cacheControl: '3600',
|
|
upsert: false,
|
|
});
|
|
|
|
if (data && data.Key) {
|
|
const { publicURL } = supabase.storage
|
|
.from('avatars')
|
|
.getPublicUrl(filename);
|
|
|
|
course.logo = publicURL;
|
|
}
|
|
}
|
|
|
|
delete course.avatar;
|
|
|
|
await supabase
|
|
.from('course')
|
|
.update(course, { returning: 'minimal' })
|
|
.match({ id: courseId });
|
|
|
|
return course.logo;
|
|
}
|
|
|
|
export async function deleteCourse(courseId, course) {
|
|
return await supabase.from('course').delete(course).match({ id: courseId });
|
|
}
|
|
|
|
export function addGroupMember(member) {
|
|
return supabase.from('groupmember').insert(member, {
|
|
returning: 'minimal',
|
|
});
|
|
}
|
|
|
|
export function fetchLesson(lessonId) {
|
|
return supabase
|
|
.from('lesson')
|
|
.select(`id, note, video_url, slide_url, call_url`)
|
|
.eq('id', lessonId)
|
|
.single();
|
|
}
|
|
|
|
export function createLesson(lesson) {
|
|
return supabase.from('lesson').insert(lesson);
|
|
}
|
|
|
|
export function updateLesson(lesson, lessonId) {
|
|
return supabase
|
|
.from('lesson')
|
|
.update(lesson, { returning: 'minimal' })
|
|
.match({ id: lessonId });
|
|
}
|
|
|
|
export function deleteLesson(lessonId) {
|
|
// Need to implement soft delete
|
|
return supabase.from('lesson').delete().match({ id: lessonId });
|
|
}
|
|
|
|
export function createExercise(exercise) {
|
|
return supabase.from('exercise').insert(exercise);
|
|
}
|
|
|
|
function isNew(item) {
|
|
return isNaN(item);
|
|
}
|
|
|
|
export async function upsertExercise(questionnaire, exerciseId) {
|
|
const {
|
|
questions,
|
|
title,
|
|
description,
|
|
is_title_dirty,
|
|
is_description_dirty,
|
|
} = questionnaire;
|
|
|
|
if (is_description_dirty || is_title_dirty) {
|
|
await supabase
|
|
.from('exercise')
|
|
.update({
|
|
title,
|
|
description,
|
|
})
|
|
.match({ id: exerciseId });
|
|
}
|
|
|
|
const updatedQuestions = [];
|
|
|
|
for (const question of questions) {
|
|
const {
|
|
title,
|
|
id,
|
|
name,
|
|
question_type,
|
|
options,
|
|
deleted_at,
|
|
points,
|
|
is_dirty,
|
|
} = question;
|
|
|
|
// DELETE /delete/:questionId - Don't delete if answer already given
|
|
if (deleted_at) {
|
|
// Delete from server only if this question exists in the database
|
|
if (!isNew(id)) {
|
|
const { error } = await supabase
|
|
.from('question')
|
|
.delete()
|
|
.match({ id });
|
|
|
|
if (error) {
|
|
console.error('Cannot delete this question', error);
|
|
continue;
|
|
}
|
|
|
|
await supabase.from('option').delete().match({ question_id: id });
|
|
}
|
|
|
|
// Skip the remaining operation so we filter out this question from the new questions array
|
|
continue;
|
|
}
|
|
|
|
// INSERT or UPDATE /update/:questionId or /insert/:questionId
|
|
const newQuestion = {
|
|
id: isNew(id) ? undefined : id,
|
|
name: isNew(id) ? undefined : name,
|
|
title,
|
|
points,
|
|
question_type_id: question_type.id,
|
|
exercise_id: exerciseId,
|
|
};
|
|
let questionSupabaseRes;
|
|
|
|
if (is_dirty || isNew(id)) {
|
|
const res = await supabase.from('question').upsert(newQuestion);
|
|
|
|
if (res.error) {
|
|
console.error(`Upsert question`, error);
|
|
}
|
|
questionSupabaseRes = Array.isArray(res.data) ? res.data[0] : null;
|
|
} else {
|
|
questionSupabaseRes = Object.assign(newQuestion);
|
|
}
|
|
|
|
if (questionSupabaseRes) {
|
|
const { question_type_id, id, name } = questionSupabaseRes;
|
|
|
|
// Delete cause this is not a field in the table
|
|
delete newQuestion.question_type_id;
|
|
|
|
newQuestion.question_type = { id: question_type_id };
|
|
newQuestion.id = id;
|
|
newQuestion.name = name;
|
|
newQuestion.options = [];
|
|
|
|
// Don't map options for 'Paragraph' questions
|
|
if (QUESTION_TYPE.TEXTAREA !== question_type_id) {
|
|
for (const option of options) {
|
|
const { deleted_at, is_dirty } = option;
|
|
|
|
// DELETE /delete/:optionId
|
|
if (deleted_at) {
|
|
// if this option exists in the database
|
|
if (!isNew(option.id)) {
|
|
supabase.from('option').delete().match({ id: option.id });
|
|
}
|
|
|
|
// Skip the remaining operation so we filter out this option from the new option array
|
|
continue;
|
|
}
|
|
|
|
// INSERT and UPDATE
|
|
const newOption = {
|
|
...option,
|
|
is_dirty: undefined,
|
|
id: isNew(option.id) ? undefined : option.id,
|
|
value: isUUID(option.value) ? option.value : undefined, // this value is of UUID type
|
|
question_id: newQuestion.id,
|
|
};
|
|
|
|
if (is_dirty || isNew(option.id)) {
|
|
const { data } = await supabase.from('option').upsert(newOption);
|
|
if (Array.isArray(data)) {
|
|
newQuestion.options.push(data[0]);
|
|
}
|
|
} else {
|
|
newQuestion.options.push(newOption);
|
|
}
|
|
}
|
|
}
|
|
|
|
updatedQuestions.push(newQuestion);
|
|
}
|
|
}
|
|
|
|
return updatedQuestions;
|
|
}
|
|
|
|
export async function submitExercise(
|
|
answers,
|
|
questions,
|
|
exerciseId,
|
|
courseId,
|
|
group,
|
|
profile
|
|
) {
|
|
let groupMember;
|
|
|
|
if (Array.isArray(group.tutors)) {
|
|
groupMember = group.tutors.find(
|
|
(student) => student.profile_id === profile.id
|
|
);
|
|
}
|
|
console.log(`groupMember`, groupMember);
|
|
if (!groupMember) {
|
|
return;
|
|
}
|
|
|
|
const questionsByName = questions.reduce(
|
|
(acc, q) => ({ ...acc, [q.name]: q.id }),
|
|
{}
|
|
);
|
|
const questionAnswers = [];
|
|
|
|
const { data: submission } = await supabase.from('submission').insert({
|
|
submitted_by: groupMember.id,
|
|
exercise_id: exerciseId,
|
|
course_id: courseId,
|
|
});
|
|
|
|
for (const questionName in answers) {
|
|
const value = answers[questionName];
|
|
|
|
const questionAnswer = {
|
|
group_member_id: groupMember.id,
|
|
question_id: questionsByName[questionName],
|
|
open_answer: '',
|
|
answers: [],
|
|
submission_id: submission[0].id,
|
|
};
|
|
|
|
if (typeof value === 'string') {
|
|
questionAnswer.open_answer = value;
|
|
} else {
|
|
questionAnswer.answers = value;
|
|
}
|
|
|
|
questionAnswers.push(questionAnswer);
|
|
}
|
|
|
|
const res = await supabase.from('question_answer').insert(questionAnswers);
|
|
console.log(`res`, res);
|
|
}
|