diff --git a/client/src/components/CourseEditor.vue b/client/src/components/CourseEditor.vue deleted file mode 100644 index dce9c608..00000000 --- a/client/src/components/CourseEditor.vue +++ /dev/null @@ -1,89 +0,0 @@ - - - Course Editor - - {{ handlerText }} mode? - - - - - - Show preview? - - - Name - - {{ state.name?.toUpperCase() }} - Description - - - Content - - - - Id - - - - - - diff --git a/client/src/components/CourseLink.vue b/client/src/components/CourseLink.vue index e3225b65..b4b650af 100644 --- a/client/src/components/CourseLink.vue +++ b/client/src/components/CourseLink.vue @@ -8,7 +8,6 @@ diff --git a/client/src/models/index.ts b/client/src/models/index.ts index cb4d9e0b..0b3ef0c3 100644 --- a/client/src/models/index.ts +++ b/client/src/models/index.ts @@ -7,6 +7,12 @@ export type ViewKey = { height?: number } +export interface ModelEditorState { + isEditMode: boolean + showPreview: boolean + id: string +}; + export abstract class ViewModel { id: Id; @@ -78,7 +84,7 @@ export class Course extends ViewModel { } }; -export class CourseEditorState { +export class CourseEditorState implements ModelEditorState { isEditMode: boolean = false showPreview: boolean = false id: string = '' diff --git a/client/src/services/AssignmentService.ts b/client/src/services/AssignmentService.ts index 278411be..f1c7ed20 100644 --- a/client/src/services/AssignmentService.ts +++ b/client/src/services/AssignmentService.ts @@ -1,8 +1,8 @@ -import BlobService from './BlobService'; import HttpServiceV1, { type HttpOptions } from './HttpServiceV1'; import { Assignment, AssignmentMetadata, type AssignmentIndex, type Id, type ViewKey } from '@/models'; +import type ModelService from './ModelService'; -export default class AssignmentService { +export default class AssignmentService implements ModelService { objectViewKeys: ViewKey[] = [ { key: 'id', kind: 'text' }, ]; @@ -33,26 +33,6 @@ export default class AssignmentService { } } - static async fillTemplateAsync(template: string, options: HttpOptions = {}): Promise { - if (!template) { - return ''; - } - // NOTE: Match and captures what is between ${}, to replace with presigned URLss - const re = /"\${([0-9a-zA-Z_\-\/\.]+)}"/g; - const presignedUrls = new Map(); - for (let match of template.matchAll(re)) { - const textToReplace = match[0]; - const filePath = match[1]; - if (!(textToReplace in presignedUrls)) { - presignedUrls.set(textToReplace, await BlobService.getPresignedUrlAsync(filePath, options)); - } - } - for (let [key, value] of presignedUrls) { - template = template.replace(key, value); - } - return template; - } - static async getAsync(id: Id, options: HttpOptions = {}): Promise { try { return new Assignment( diff --git a/client/src/services/BlobService.ts b/client/src/services/BlobService.ts index 8bd83e94..5de61c58 100644 --- a/client/src/services/BlobService.ts +++ b/client/src/services/BlobService.ts @@ -1,7 +1,7 @@ import type { Id } from '@/models'; import HttpServiceV1, { type HttpOptions } from './HttpServiceV1'; -export default class BlobService { +export default class BlobService { static async getPresignedUrlAsync(id: Id, options: HttpOptions = {}): Promise { try { return await HttpServiceV1.getTextAsync(`blob?url=${id}`, options); diff --git a/client/src/services/BlogService.ts b/client/src/services/BlogService.ts index 7853698e..9a39708e 100644 --- a/client/src/services/BlogService.ts +++ b/client/src/services/BlogService.ts @@ -1,8 +1,9 @@ import type { BlogIndex, Id, ViewKey } from '@/models'; import { Blog, BlogMetadata } from '@/models'; import HttpServiceV1, { type HttpOptions } from './HttpServiceV1'; +import type ModelService from './ModelService'; -export default class BlogService { +export default class BlogService implements ModelService { objectViewKeys: ViewKey[] = [ { key: 'id', kind: 'text' }, ]; diff --git a/client/src/services/CourseService.ts b/client/src/services/CourseService.ts index 231693d2..63b55db8 100644 --- a/client/src/services/CourseService.ts +++ b/client/src/services/CourseService.ts @@ -1,8 +1,8 @@ import { Course, CourseMetadata, type CourseIndex, type Id, type ViewKey } from '@/models'; -import BlobService from './BlobService'; import HttpServiceV1, { type HttpOptions } from './HttpServiceV1'; +import ModelService from './ModelService'; -export default class CourseService { +export default class CourseService implements ModelService { objectViewKeys: ViewKey[] = [ { key: 'id', kind: 'text' }, { key: 'name', kind: 'code' }, @@ -35,33 +35,12 @@ export default class CourseService { throw err; } } - - static async fillTemplateAsync(template: string, options: HttpOptions = {}): Promise { - if (!template) { - return ''; - } - // NOTE: Match and captures what is between ${}, to replace with presigned URLss - const re = /"\${([0-9a-zA-Z_\-\/\.]+)}"/g; - const presignedUrls = new Map(); - for (let match of template.matchAll(re)) { - const textToReplace = match[0]; - const filePath = match[1]; - if (!(textToReplace in presignedUrls)) { - presignedUrls.set(textToReplace, await BlobService.getPresignedUrlAsync(filePath, options)); - } - } - for (let [key, value] of presignedUrls) { - template = template.replace(key, value); - } - return template; - } - static async getAsync(id: Id, options: HttpOptions = {}): Promise { try { const course = new Course( await HttpServiceV1.getAsync('course', id, options)); try { - course.templatedContent = await CourseService.fillTemplateAsync(course.content, options); + course.templatedContent = await ModelService.fillTemplateAsync(course.content, options); } catch (err: any) { options.toast?.error(`Failed to fill template for course content: ${err}`); diff --git a/client/src/services/ModelService.ts b/client/src/services/ModelService.ts new file mode 100644 index 00000000..aa074d0d --- /dev/null +++ b/client/src/services/ModelService.ts @@ -0,0 +1,50 @@ +import type { ViewKey } from "@/models"; +import BlobService from "./BlobService"; +import type { HttpOptions } from "./HttpServiceV1"; +import SectionService from "./SectionService"; +import CourseService from "./CourseService"; +import AssignmentService from "./AssignmentService"; +import BlogService from "./BlogService"; + +abstract class ModelService { + abstract objectViewKeys: ViewKey[]; + + static inject(kind: string) { + switch (kind) { + case 'assignment': + return new AssignmentService(); + case 'blog': + return new BlogService(); + case 'course': + return new CourseService(); + case 'section': + return new SectionService(); + default: + throw new Error(`Unknown kind: ${kind}`); + } + } + + abstract make(): T; + + static async fillTemplateAsync(template: string, options: HttpOptions = {}): Promise { + if (!template) { + return ''; + } + // NOTE: Match and captures what is between ${}, to replace with presigned URLs + const re = /"\${([0-9a-zA-Z_\-\/\.]+)}"/g; + const presignedUrls = new Map(); + for (let match of template.matchAll(re)) { + const textToReplace = match[0]; + const filePath = match[1]; + if (!(textToReplace in presignedUrls)) { + presignedUrls.set(textToReplace, await BlobService.getPresignedUrlAsync(filePath, options)); + } + } + for (let [key, value] of presignedUrls) { + template = template.replace(key, value); + } + return template; + } +} + +export default ModelService; diff --git a/client/src/services/SectionService.ts b/client/src/services/SectionService.ts index 7f5f398d..af25d533 100644 --- a/client/src/services/SectionService.ts +++ b/client/src/services/SectionService.ts @@ -1,7 +1,8 @@ import { Section, type ViewKey, type Id, type SectionIndex, SectionMetadata } from '@/models'; import HttpServiceV1, { type HttpOptions } from './HttpServiceV1'; +import type ModelService from './ModelService'; -export default class SectionService { +export default class SectionService implements ModelService { objectViewKeys: ViewKey[] = [ { key: 'id', kind: 'text' }, ]; diff --git a/client/src/views/AssignmentView.vue b/client/src/views/AssignmentView.vue index f8d42622..79c3e191 100644 --- a/client/src/views/AssignmentView.vue +++ b/client/src/views/AssignmentView.vue @@ -29,7 +29,7 @@ import AssignmentEditor, { type AssignmentEditorState } from '@/components/Assig import AssignmentLink from '@/components/AssignmentLink.vue'; import AssignmentService from '@/services/AssignmentService'; import Spinner from '@/components/Spinner.vue'; -import type { AssignmentIndex, AssignmentMetadata, Id } from '@/models'; +import type { AssignmentIndex } from '@/models'; import { onMounted, reactive } from 'vue'; import { useAuth0 } from '@auth0/auth0-vue'; import { useToast } from "vue-toastification"; diff --git a/client/src/views/CourseView.vue b/client/src/views/CourseView.vue index f8035cca..c3a77ff9 100644 --- a/client/src/views/CourseView.vue +++ b/client/src/views/CourseView.vue @@ -12,8 +12,7 @@ - + @@ -28,7 +27,7 @@ import Spinner from '@/components/Spinner.vue'; import { onMounted, reactive } from 'vue'; import { useAuth0 } from '@auth0/auth0-vue'; import { useToast } from "vue-toastification"; -import CourseEditor from '@/components/CourseEditor.vue'; +import ModelEditor from '@/components/ModelEditor.vue'; import type { CourseIndex } from '@/models';
{{ state.name?.toUpperCase() }}