Files
CT/src/Model/Files/fileModel.ts
T

245 lines
6.6 KiB
TypeScript
Raw Normal View History

2026-04-18 11:55:01 +00:00
import { v4 } from "uuid";
import BoardsAndTasksModel from "./boardsAndTasksModel";
2024-07-22 11:49:05 +02:00
import {
2026-04-01 08:29:39 +00:00
StringEntryObject,
createTimestamp,
parseValidObject,
stringify,
2024-07-22 11:49:05 +02:00
} from "../Utility/utility";
2026-09-26 23:32:38 +02:00
import {
checkMatchesObjectStructure,
DATA_VERSION,
ValidObject,
} from "../Utility/typeSafety";
2026-04-18 11:55:01 +00:00
import StorageModel, {
StorageModelSubPaths,
filePaths,
} from "../Global/storageModel";
2024-07-26 03:14:55 +02:00
import SettingsModel from "../Global/settingsModel";
2026-09-26 23:32:38 +02:00
import ChatModel, {
ChatInfoFileContent,
ChatInfoReference,
} from "../Chat/chatModel";
2024-07-21 21:45:18 +02:00
export default class FileModel {
2026-04-13 10:58:21 +00:00
readonly storageModel: StorageModel;
readonly settingsModel: SettingsModel;
2026-04-01 08:29:39 +00:00
2026-04-13 10:58:21 +00:00
readonly chatModel: ChatModel;
readonly boardsAndTasksModel: BoardsAndTasksModel;
2026-04-01 08:29:39 +00:00
// paths
2026-04-18 11:55:01 +00:00
get basePath(): string[] {
2026-04-01 08:29:39 +00:00
return StorageModel.getPath(
2026-04-08 14:02:12 +00:00
StorageModelSubPaths.Chat,
2026-04-01 08:29:39 +00:00
filePaths.chat.files(this.chatModel.id),
);
2026-08-29 02:10:26 +02:00
}
2026-04-01 08:29:39 +00:00
2026-04-18 11:55:01 +00:00
readonly getFileContainerPath = (): string[] => {
return [...this.basePath, FileModelSubPath.Data];
2026-04-01 08:29:39 +00:00
};
2026-08-29 02:10:26 +02:00
readonly getModelContainerPath = (
modelName: FileModelSubPath,
): string[] => {
2026-04-18 11:55:01 +00:00
return [...this.basePath, FileModelSubPath.Model, modelName];
2026-04-01 08:29:39 +00:00
};
2026-04-18 11:55:01 +00:00
readonly getFilePath = (fileId: string): string[] => {
2026-04-01 08:29:39 +00:00
return [...this.getFileContainerPath(), fileId];
};
2026-08-29 02:10:26 +02:00
readonly getFileContentPath = (
fileId: string,
fileContentId: string,
): string[] => {
2026-04-01 08:29:39 +00:00
const filePath: string[] = this.getFilePath(fileId);
return [...filePath, fileContentId];
};
// handlers
2026-08-29 02:10:26 +02:00
readonly handleStringifiedFileContent = (
stringifiedFileContent: string,
): void => {
2026-04-01 08:29:39 +00:00
const fileContent: FileContent<string> | null = parseValidObject(
stringifiedFileContent,
FileContentReference,
);
if (fileContent == null) return;
this.handleFileContent(fileContent);
};
2026-04-18 11:55:01 +00:00
readonly handleFileContent = (fileContent: FileContent<string>): void => {
2026-09-26 23:32:38 +02:00
console.log(fileContent.type);
if (fileContent.type == "chat-info") {
if (
checkMatchesObjectStructure(fileContent, ChatInfoReference) ==
false
)
return;
this.chatModel.handleInfo(fileContent as ChatInfoFileContent);
}
const didStore: boolean = this.storeFileContent(fileContent);
if (didStore == false) return;
switch (fileContent.type) {
case "board-info":
case "task":
this.boardsAndTasksModel.handleFileContent(fileContent);
break;
case "reaction":
this.chatModel.handleReaction(fileContent);
break;
}
2026-04-01 08:29:39 +00:00
};
// methods
2026-08-29 02:10:26 +02:00
readonly addFileContentAndSend = (
2026-09-26 23:32:38 +02:00
fileContent: FileContent<string>,
2026-08-29 02:10:26 +02:00
): void => {
2026-09-26 23:32:38 +02:00
this.handleFileContent(fileContent);
this.chatModel.sendMessage("", undefined, fileContent);
2026-04-01 08:29:39 +00:00
};
// storage
2026-04-18 11:55:01 +00:00
readonly storeFileContent = (fileContent: FileContent<string>): boolean => {
2026-09-26 23:32:38 +02:00
const fileContentPath: string[] = this.getFileContentPath(
fileContent.fileId,
fileContent.fileContentId,
);
// check if fileContent already exists
const existingFileContent: string | null =
this.storageModel.read(fileContentPath);
if (existingFileContent != null) return false;
const stringifiedContent: string = stringify(fileContent);
this.storageModel.write(fileContentPath, stringifiedContent);
return true;
2026-04-01 08:29:39 +00:00
};
2026-04-18 11:55:01 +00:00
readonly listFileIds = (): string[] => {
2026-09-26 23:32:38 +02:00
return this.storageModel.list(this.basePath);
2026-04-01 08:29:39 +00:00
};
2026-04-18 11:55:01 +00:00
readonly listFileContentIds = (fileId: string): string[] => {
2026-09-26 23:32:38 +02:00
const filePath: string[] = this.getFilePath(fileId);
return this.storageModel.list(filePath);
2026-04-01 08:29:39 +00:00
};
2026-04-18 11:55:01 +00:00
readonly selectLatestFileContentId = (
2026-09-26 23:32:38 +02:00
fileContentIds: string[],
2026-04-01 08:29:39 +00:00
): string | undefined => {
2026-09-26 23:32:38 +02:00
return fileContentIds[fileContentIds.length - 1];
2026-04-01 08:29:39 +00:00
};
2026-04-18 11:55:01 +00:00
readonly getFileContent = <T extends FileContent<string>>(
2026-09-26 23:32:38 +02:00
fileId: string,
fileContentName: string,
reference: T,
2026-04-01 08:29:39 +00:00
): T | null => {
2026-09-26 23:32:38 +02:00
const filePath: string[] = this.getFileContentPath(
fileId,
fileContentName,
);
const fileContentOrNull: T | null = this.storageModel.readStringifiable(
filePath,
reference,
);
return fileContentOrNull;
2026-04-01 08:29:39 +00:00
};
2026-04-18 11:55:01 +00:00
readonly getLatestFileContent = <T extends FileContent<string>>(
2026-09-26 23:32:38 +02:00
fileId: string,
reference: T,
2026-04-01 08:29:39 +00:00
): T | null => {
2026-09-26 23:32:38 +02:00
const fileContentsIds: string[] = this.listFileContentIds(fileId);
const latestFileContentId: string | undefined =
this.selectLatestFileContentId(fileContentsIds);
if (latestFileContentId == undefined) return null;
const fileContent: T | null = this.getFileContent(
fileId,
latestFileContentId,
reference,
);
return fileContent;
2026-04-01 08:29:39 +00:00
};
// init
constructor(
2026-09-26 23:32:38 +02:00
storageModel: StorageModel,
settingsModel: SettingsModel,
chatModel: ChatModel,
2026-04-01 08:29:39 +00:00
) {
2026-09-26 23:32:38 +02:00
this.chatModel = chatModel;
this.settingsModel = settingsModel;
this.storageModel = storageModel;
this.boardsAndTasksModel = new BoardsAndTasksModel(
this.storageModel,
this.settingsModel,
chatModel,
this,
);
2026-04-01 08:29:39 +00:00
}
// utility
static generateFileContentId = (creationDate: string): string => {
2026-09-26 23:32:38 +02:00
return creationDate + v4();
2026-04-01 08:29:39 +00:00
};
static createFileContent = <T extends string>(
2026-09-26 23:32:38 +02:00
fileId: string,
type: T,
2026-04-01 08:29:39 +00:00
): FileContent<T> => {
2026-09-26 23:32:38 +02:00
const creationDate: string = createTimestamp();
const fileContentId: string =
FileModel.generateFileContentId(creationDate);
return {
dataVersion: DATA_VERSION,
fileId,
fileContentId,
creationDate,
type,
};
2026-04-01 08:29:39 +00:00
};
2024-07-21 20:54:18 +02:00
}
2024-07-22 12:39:26 +02:00
// paths
2024-07-23 18:23:26 +02:00
export enum FileModelSubPath {
2026-04-01 08:29:39 +00:00
Data = "data",
2026-09-26 23:32:38 +02:00
Model = "model",
Chat = "chat",
ModelView = "view",
ModelTask = "tasks",
ModelCalendar = "calendar",
2024-07-26 03:14:55 +02:00
}
2024-07-22 12:39:26 +02:00
2024-07-21 23:32:20 +02:00
// types
2024-07-26 03:14:55 +02:00
export interface FileContent<T extends string>
2026-04-01 08:29:39 +00:00
extends ValidObject, StringEntryObject {
2026-09-26 23:32:38 +02:00
readonly fileId: string;
readonly fileContentId: string;
readonly creationDate: string;
2024-07-21 23:32:20 +02:00
2026-09-26 23:32:38 +02:00
readonly type: T;
}
2024-07-22 01:22:59 +02:00
// references
2024-07-22 18:11:18 +02:00
export const FileContentReference: FileContent<string> = {
2026-04-01 08:29:39 +00:00
dataVersion: DATA_VERSION,
2024-07-22 01:22:59 +02:00
2026-04-01 08:29:39 +00:00
fileId: "",
fileContentId: "",
creationDate: "",
2024-07-22 01:22:59 +02:00
2026-04-01 08:29:39 +00:00
type: "",
2024-07-22 01:38:08 +02:00
};