From 9a45c03b0fb9715ade8f4468b5f237e32a95b9f6 Mon Sep 17 00:00:00 2001 From: Kristian Binau Date: Thu, 5 Oct 2023 09:34:27 +0200 Subject: [PATCH] #9 - Clean up & Get Items from Api --- src/components/files/FileBrowser.vue | 56 +++++++++++--- src/components/files/Folder.vue | 29 ++----- src/lib/items.ts | 111 +++++++++++++++++++++++++-- src/pages/u/folder/[id].astro | 9 ++- 4 files changed, 163 insertions(+), 42 deletions(-) diff --git a/src/components/files/FileBrowser.vue b/src/components/files/FileBrowser.vue index 611aef4..f7c42f8 100644 --- a/src/components/files/FileBrowser.vue +++ b/src/components/files/FileBrowser.vue @@ -21,11 +21,12 @@ import { computed, ref, type PropType } from 'vue'; import NoFiles from './NoFiles.vue'; import Folder from './Folder.vue'; import File from './File.vue'; -import { FolderClass, FileClass, ItemClass } from '@lib/items'; +import { FolderClass, FileClass, ItemClass, type FolderType } from '@lib/items'; +import { api } from '@lib/helpers'; const props = defineProps({ modelValue: { - type: Object as PropType, + type: Object as PropType, required: false, }, }); @@ -38,19 +39,52 @@ const items = ref([]); getItems(); function getItems() { - console.log(props.modelValue instanceof FolderClass); - if (props.modelValue instanceof FolderClass) { - // - } + fetch( + api( + `${ + ItemClass.isItem(props.modelValue) && FolderClass.isFolder(props.modelValue) + ? props.modelValue.id + : '' + }`, + ), + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'include', + }, + ) + .then(async (response) => { + if (!response.ok) { + if (response.status >= 400 && response.status < 500) { + throw new Error((await response.json()).error); + } - for (let i = 0; i < 29; i++) { - const item = - Math.random() > 0.5 ? FolderClass.create('jkghk', null) : FileClass.create('grffrw', null); - items.value.push(item); - } + throw new Error(await response.text()); + } + + const rawItems = await response.json(); + + for (let rawItem of rawItems) { + if (!ItemClass.isItem(rawItem)) continue; + + let item = ItemClass.getItemFromObject(rawItem); + + if (item === null) continue; + + items.value.push(item); + } + + return items.value; + }) + .catch((error) => { + console.error('Error:', error); + }); } function updateItem(item: ItemClass) { + // Todo, Should find the item in the array and update it console.log(item); } diff --git a/src/components/files/Folder.vue b/src/components/files/Folder.vue index 527c50e..049fd95 100644 --- a/src/components/files/Folder.vue +++ b/src/components/files/Folder.vue @@ -3,12 +3,7 @@ @@ -52,7 +41,7 @@ diff --git a/src/lib/items.ts b/src/lib/items.ts index 3541e8e..ee847d2 100644 --- a/src/lib/items.ts +++ b/src/lib/items.ts @@ -7,8 +7,8 @@ export abstract class ItemClass { private _mimeType: string; private _ownerId: number; private _parentId: number | null; - private _createdAt: Date | undefined; - private _updatedAt: Date | undefined; + private _createdAt: Date; + private _updatedAt: Date; private _deletedAt: Date | null; protected constructor(ItemObject: ItemType) { @@ -17,9 +17,17 @@ export abstract class ItemClass { this._mimeType = ItemObject.mimeType; this._ownerId = ItemObject.ownerId; this._parentId = ItemObject.parentId; - this._createdAt = ItemObject.createdAt || undefined; - this._updatedAt = ItemObject.updatedAt || undefined; - this._deletedAt = ItemObject.deletedAt || null; + + const createdAt = ItemClass.convertDate(ItemObject.createdAt); + const updatedAt = ItemClass.convertDate(ItemObject.updatedAt); + const deletedAt = ItemClass.convertDate(ItemObject.deletedAt); + + if (createdAt === null) throw new Error('Invalid createdAt'); + if (updatedAt === null) throw new Error('Invalid updatedAt'); + + this._createdAt = createdAt; + this._updatedAt = updatedAt; + this._deletedAt = deletedAt; } get id() { @@ -53,6 +61,76 @@ export abstract class ItemClass { get deletedAt() { return this._deletedAt; } + + static getItemFromObject(object: ItemType) { + if (FolderClass.isFolder(object)) return new FolderClass(object); + if (FileClass.isFile(object)) return new FileClass(object); + + console.error('ItemClass.getItemFromObject: Invalid object'); + return null; + } + + static isItem(object: any): object is ItemType { + // Id + if (!('id' in object && typeof object.id === 'number')) return false; + + // Name + if (!('name' in object && typeof object.name === 'string')) return false; + + // MimeType + if (!('mimeType' in object && typeof object.mimeType === 'string')) return false; + + // OwnerId + if (!('ownerId' in object && typeof object.ownerId === 'number')) return false; + + // ParentId + if ( + !(('parentId' in object && typeof object.parentId === 'number') || object.parentId === null) + ) + return false; + + // CreatedAt + if ( + !( + 'createdAt' in object && + (object.createdAt === undefined || + object.createdAt instanceof Date || + typeof object.createdAt === 'string') + ) + ) + return false; + + // UpdatedAt + if ( + !( + 'updatedAt' in object && + (object.updatedAt === undefined || + object.updatedAt instanceof Date || + typeof object.updatedAt === 'string') + ) + ) + return false; + + // DeletedAt + if ( + !( + 'deletedAt' in object && + (object.deletedAt === undefined || + object.deletedAt === null || + object.deletedAt instanceof Date || + typeof object.deletedAt === 'string') + ) + ) + return false; + + return true; + } + + private static convertDate(date: Date | string | undefined | null) { + if (typeof date === 'string') return new Date(date); + if (date instanceof Date) return date; + return null; + } } export type ItemType = { @@ -61,9 +139,9 @@ export type ItemType = { mimeType: string; ownerId: number; parentId: number | null; - createdAt?: Date; - updatedAt?: Date; - deletedAt?: Date | null; + createdAt?: Date | string; + updatedAt?: Date | string; + deletedAt?: Date | string | null; }; /** @@ -108,6 +186,16 @@ export class FolderClass extends ItemClass { Math.floor(Math.random() * Object.keys(FolderColors).length) ] as FolderColor; } + + static isFolder(object: ItemType): object is FolderType { + // Color + if (!('color' in object && typeof object.color === 'string')) return false; + + // MimeType + if (object.mimeType !== 'application/vnd.cloudstore.folder') return false; + + return true; + } } export type FolderType = { @@ -168,6 +256,13 @@ export class FileClass extends ItemClass { get blobUrl() { return this._blobUrl; } + + static isFile(object: ItemType): object is FileType { + // BlobUrl + if (!('blobUrl' in object && typeof object.blobUrl === 'string')) return false; + + return true; + } } export type FileType = { diff --git a/src/pages/u/folder/[id].astro b/src/pages/u/folder/[id].astro index f6190ac..a442117 100644 --- a/src/pages/u/folder/[id].astro +++ b/src/pages/u/folder/[id].astro @@ -3,7 +3,7 @@ import LayoutSidebar from '@layouts/LayoutSidebar.astro'; import FileBrowser from '@components/files/FileBrowser.vue'; // @ts-ignore https://github.com/withastro/language-tools/issues/476 import { api, url } from '@lib/helpers'; -import { FolderClass } from '@lib/items'; +import { ItemClass, FolderClass } from '@lib/items'; const { id } = Astro.params; @@ -23,8 +23,13 @@ if (!folderResponse || folderResponse?.statusCode <= 400) { return Astro.redirect(url('404')); } +// If the folder isn't a valid folder, redirect +if (!(ItemClass.isItem(folderResponse) && FolderClass.isFolder(folderResponse))) { + return Astro.redirect(url('404')); +} + // Otherwise, create a new folder instance -const folder = new FolderClass(folderResponse.data); +const folder = folderResponse; // We can safely cast this as we know that middleware would have already checked for a valid user const user = Astro.locals.user as User;