2021-12-30 22:30:30 +02:00
|
|
|
import { get } from 'svelte/store';
|
|
|
|
|
import type { PostgrestError } from '@supabase/supabase-js';
|
2023-08-02 19:35:27 +01:00
|
|
|
import { supabase } from '$lib/utils/functions/supabase';
|
2021-12-30 22:30:30 +02:00
|
|
|
// @ts-ignore
|
|
|
|
|
import { addGroupMember } from './index';
|
|
|
|
|
// @ts-ignore
|
2023-08-02 19:35:27 +01:00
|
|
|
import { profile } from '$lib/utils/store/user';
|
|
|
|
|
import type { Course, Exercise, Lesson, Profile } from '$lib/utils/types';
|
2021-12-30 22:30:30 +02:00
|
|
|
// @ts-ignore
|
2023-08-02 19:35:27 +01:00
|
|
|
import { ROLE } from '$lib/utils/constants/roles';
|
2021-12-30 22:30:30 +02:00
|
|
|
// @ts-ignore
|
2023-08-02 19:35:27 +01:00
|
|
|
import { QUESTION_TYPE } from '$lib/components/Question/constants';
|
2021-12-30 22:30:30 +02:00
|
|
|
|
|
|
|
|
type GetCourseResponse = {
|
|
|
|
|
data: Course;
|
|
|
|
|
error: PostgrestError | null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
async function fetchCourseData(courseId: string): Promise<GetCourseResponse> {
|
|
|
|
|
const { data, error } = await supabase
|
|
|
|
|
.from('course')
|
|
|
|
|
.select(
|
|
|
|
|
`
|
|
|
|
|
*,
|
|
|
|
|
lessons:lesson(
|
|
|
|
|
*,
|
|
|
|
|
exercise:id(
|
|
|
|
|
id, title, description, due_by,
|
|
|
|
|
questions:question(
|
|
|
|
|
*,
|
|
|
|
|
options:option(*),
|
|
|
|
|
question_type:question_type_id(id, label)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
`
|
|
|
|
|
)
|
|
|
|
|
.match({ id: courseId })
|
|
|
|
|
.single();
|
|
|
|
|
|
|
|
|
|
return { data, error };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function cloneGroupAndBasicCourse(
|
|
|
|
|
course: Course,
|
|
|
|
|
newTitle: string
|
|
|
|
|
): Promise<{ newCourse: Course }> {
|
|
|
|
|
const { description } = course;
|
|
|
|
|
|
|
|
|
|
const { data: newGroup } = await supabase
|
|
|
|
|
.from('group')
|
2023-08-02 19:35:27 +01:00
|
|
|
.insert({ name: newTitle, description })
|
|
|
|
|
.select();
|
2021-12-30 22:30:30 +02:00
|
|
|
|
|
|
|
|
console.log(`newGroup`, newGroup);
|
|
|
|
|
if (!Array.isArray(newGroup)) {
|
|
|
|
|
throw new Error('Group wasnt created successfully');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { id: group_id } = newGroup[0];
|
|
|
|
|
|
|
|
|
|
// 2. Create course with group_id
|
2023-08-02 19:35:27 +01:00
|
|
|
const { data: newCourse } = await supabase
|
|
|
|
|
.from('course')
|
|
|
|
|
.insert({
|
|
|
|
|
...course,
|
|
|
|
|
title: newTitle,
|
|
|
|
|
description,
|
|
|
|
|
group_id,
|
|
|
|
|
lessons: undefined,
|
|
|
|
|
id: undefined,
|
|
|
|
|
updated_at: undefined,
|
2023-08-03 02:51:02 +01:00
|
|
|
created_at: undefined
|
2023-08-02 19:35:27 +01:00
|
|
|
})
|
|
|
|
|
.select();
|
2021-12-30 22:30:30 +02:00
|
|
|
|
|
|
|
|
console.log(`newCourse`, newCourse);
|
|
|
|
|
|
|
|
|
|
// 3. Add group members
|
|
|
|
|
|
|
|
|
|
const profileStoreValue: Profile = get(profile);
|
|
|
|
|
|
|
|
|
|
// Get profile of author and add as member
|
|
|
|
|
await addGroupMember({
|
|
|
|
|
profile_id: profileStoreValue.id,
|
|
|
|
|
email: profileStoreValue.email,
|
|
|
|
|
group_id,
|
2023-08-03 02:51:02 +01:00
|
|
|
role_id: ROLE.TUTOR
|
2021-12-30 22:30:30 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('profileStoreValue', profileStoreValue);
|
|
|
|
|
|
|
|
|
|
return {
|
2023-08-03 02:51:02 +01:00
|
|
|
newCourse: newCourse?.[0]
|
2021-12-30 22:30:30 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function cloneLessons(lessons: Lesson[], courseId: Course['id']) {
|
|
|
|
|
const clonedLessons = lessons
|
2023-08-03 02:51:02 +01:00
|
|
|
.sort((a, b) => new Date(a.created_at || '').getTime() - new Date(b.created_at || '').getTime())
|
2021-12-30 22:30:30 +02:00
|
|
|
.map((lesson, index) => ({
|
|
|
|
|
call_url: lesson.call_url,
|
|
|
|
|
course_id: courseId,
|
2023-08-03 02:51:02 +01:00
|
|
|
is_unlocked: lesson.is_unlocked,
|
2021-12-30 22:30:30 +02:00
|
|
|
lesson_at: new Date(),
|
|
|
|
|
note: lesson.note,
|
|
|
|
|
order: lesson.order || index + 1,
|
|
|
|
|
public: lesson.public,
|
|
|
|
|
slide_url: lesson.slide_url,
|
|
|
|
|
title: lesson.title,
|
2023-08-10 12:46:14 +01:00
|
|
|
videos: lesson.videos
|
2021-12-30 22:30:30 +02:00
|
|
|
}));
|
|
|
|
|
|
2023-08-02 19:35:27 +01:00
|
|
|
const { data } = await supabase.from('lesson').insert(clonedLessons).select();
|
2021-12-30 22:30:30 +02:00
|
|
|
|
|
|
|
|
const newLessons = data?.map((dataItem, dataIndex) => {
|
|
|
|
|
return {
|
|
|
|
|
...dataItem,
|
2022-12-30 13:30:15 +01:00
|
|
|
// @ts-ignore
|
2023-08-03 02:51:02 +01:00
|
|
|
exercise: lessons[dataIndex].exercise
|
2021-12-30 22:30:30 +02:00
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('newLessons', newLessons);
|
|
|
|
|
return { newLessons };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function cloneExercises(lessons: Lesson[]) {
|
|
|
|
|
console.log('lessons', lessons);
|
|
|
|
|
|
|
|
|
|
// Lessons
|
|
|
|
|
for (const lesson of lessons) {
|
2022-12-30 13:30:15 +01:00
|
|
|
// @ts-ignore
|
2021-12-30 22:30:30 +02:00
|
|
|
const { id: lessonId, exercise = [] } = lesson;
|
|
|
|
|
|
|
|
|
|
// Exercises
|
|
|
|
|
for (const exerciseItem of exercise) {
|
|
|
|
|
const { title, description, questions = [] } = exerciseItem;
|
|
|
|
|
// Insert
|
2023-08-02 19:35:27 +01:00
|
|
|
const { data } = await supabase
|
|
|
|
|
.from('exercise')
|
|
|
|
|
.insert({
|
|
|
|
|
description,
|
|
|
|
|
due_by: new Date(),
|
|
|
|
|
lesson_id: lessonId,
|
2023-08-03 02:51:02 +01:00
|
|
|
title
|
2023-08-02 19:35:27 +01:00
|
|
|
})
|
|
|
|
|
.select();
|
2021-12-30 22:30:30 +02:00
|
|
|
const newExercise = Array.isArray(data) ? data[0] : data;
|
|
|
|
|
console.log('newExercise', newExercise);
|
|
|
|
|
|
|
|
|
|
// Questions
|
|
|
|
|
for (const question of questions) {
|
|
|
|
|
const { options = [] } = question;
|
|
|
|
|
|
|
|
|
|
// Insert
|
2023-08-02 19:35:27 +01:00
|
|
|
const { data } = await supabase
|
|
|
|
|
.from('question')
|
|
|
|
|
.insert({
|
|
|
|
|
name: question.name,
|
|
|
|
|
title: question.title,
|
|
|
|
|
points: question.points,
|
|
|
|
|
order: question.order,
|
|
|
|
|
question_type_id: question.question_type_id,
|
2023-08-03 02:51:02 +01:00
|
|
|
exercise_id: newExercise.id
|
2023-08-02 19:35:27 +01:00
|
|
|
})
|
|
|
|
|
.select();
|
2021-12-30 22:30:30 +02:00
|
|
|
const newQuestion = Array.isArray(data) ? data[0] : data;
|
|
|
|
|
console.log('newQuestion', newQuestion);
|
|
|
|
|
|
|
|
|
|
// Options: Don't map options for 'Paragraph' questions
|
|
|
|
|
if (QUESTION_TYPE.TEXTAREA !== newQuestion.question_type_id) {
|
2022-12-30 13:30:15 +01:00
|
|
|
// @ts-ignore
|
2021-12-30 22:30:30 +02:00
|
|
|
const newOptions = options.map((option) => ({
|
|
|
|
|
value: option.value,
|
|
|
|
|
label: option.label,
|
|
|
|
|
is_correct: option.is_correct,
|
2023-08-03 02:51:02 +01:00
|
|
|
question_id: newQuestion.id
|
2021-12-30 22:30:30 +02:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Insert[Batch]
|
2023-08-02 19:35:27 +01:00
|
|
|
await supabase.from('option').insert(newOptions).select();
|
2021-12-30 22:30:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 02:51:02 +01:00
|
|
|
export async function cloneCourse(courseId: string, newTitle: string): Promise<Course> {
|
2021-12-30 22:30:30 +02:00
|
|
|
const { data: course, error } = await fetchCourseData(courseId);
|
|
|
|
|
console.log(`course`, course);
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
console.error('Error when cloning', error);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 1. Copy course table
|
|
|
|
|
* 2. Copy lessons table
|
|
|
|
|
* 3. Copy exercises table
|
|
|
|
|
* 4. Copy questions table
|
|
|
|
|
* 5. Copy options table
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// tables: group, groupmember, course(group_id)
|
|
|
|
|
const { newCourse } = await cloneGroupAndBasicCourse(course, newTitle);
|
|
|
|
|
console.log('returned -> newCourse', newCourse);
|
|
|
|
|
|
2022-12-30 13:30:15 +01:00
|
|
|
// @ts-ignore
|
2021-12-30 22:30:30 +02:00
|
|
|
const { newLessons } = await cloneLessons(course.lessons, newCourse.id);
|
|
|
|
|
console.log('returned -> newLessons', newLessons);
|
|
|
|
|
|
|
|
|
|
const cloneExercisesRes = await cloneExercises(newLessons || []);
|
|
|
|
|
console.log('returned -> cloneExercisesRes', cloneExercisesRes);
|
|
|
|
|
|
|
|
|
|
return newCourse;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
1. Click on 3 dots to clone course
|
|
|
|
|
|
|
|
|
|
2. Show a modal with a new name "Copy of previous course name"
|
|
|
|
|
|
|
|
|
|
-> Note the following information will be copied
|
|
|
|
|
|
|
|
|
|
3. Things to copy
|
|
|
|
|
Overview
|
|
|
|
|
Lessons
|
|
|
|
|
Exercises - questions, options, everything basically.
|
|
|
|
|
|
|
|
|
|
Technical approach
|
|
|
|
|
- Fetch all the data to the client
|
|
|
|
|
- Manually call functions to create
|
|
|
|
|
|
|
|
|
|
- call a psql function with newname, course_id
|
|
|
|
|
|
|
|
|
|
- copy all in course table
|
|
|
|
|
- copy all in group table by course_id
|
|
|
|
|
- add only one group member as admin
|
|
|
|
|
|
|
|
|
|
- get all lessons in course
|
|
|
|
|
- copy each one with unique ids
|
|
|
|
|
|
|
|
|
|
- get all exercises by course id
|
|
|
|
|
- copy exercise
|
|
|
|
|
|
|
|
|
|
- get questions
|
|
|
|
|
- copy questions
|
|
|
|
|
|
|
|
|
|
- get options
|
|
|
|
|
- copy options
|
|
|
|
|
*/
|