implement model methods for backup
This commit is contained in:
@@ -137,7 +137,7 @@ export default class ChatModel {
|
||||
this.storeInfo();
|
||||
this.subscribe();
|
||||
};
|
||||
|
||||
|
||||
readonly setNamespace = (namespace: string): void => {
|
||||
this.info.namespace = namespace;
|
||||
this.storeInfo();
|
||||
|
||||
@@ -57,7 +57,10 @@ export default class BoardsAndTasksModel {
|
||||
];
|
||||
};
|
||||
|
||||
readonly getTaskReferencePath = (boardId: string, fileId: string): string[] => {
|
||||
readonly getTaskReferencePath = (
|
||||
boardId: string,
|
||||
fileId: string,
|
||||
): string[] => {
|
||||
return [...this.getTaskContainerPath(boardId), fileId];
|
||||
};
|
||||
|
||||
@@ -99,17 +102,23 @@ export default class BoardsAndTasksModel {
|
||||
return boardInfoFileContent;
|
||||
};
|
||||
|
||||
readonly updateBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
readonly updateBoard = (
|
||||
boardInfoFileContent: BoardInfoFileContent,
|
||||
): void => {
|
||||
this.storeBoard(boardInfoFileContent);
|
||||
this.boardHandlerManager.trigger(boardInfoFileContent);
|
||||
};
|
||||
|
||||
readonly updateBoardAndSend = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
readonly updateBoardAndSend = (
|
||||
boardInfoFileContent: BoardInfoFileContent,
|
||||
): void => {
|
||||
this.updateBoard(boardInfoFileContent);
|
||||
this.chatModel.sendMessage("", undefined, boardInfoFileContent);
|
||||
};
|
||||
|
||||
readonly storeBoard = (boardInfoFileContent: BoardInfoFileContent): void => {
|
||||
readonly storeBoard = (
|
||||
boardInfoFileContent: BoardInfoFileContent,
|
||||
): void => {
|
||||
// store info
|
||||
this.fileModel.storeFileContent(boardInfoFileContent);
|
||||
|
||||
@@ -194,7 +203,9 @@ export default class BoardsAndTasksModel {
|
||||
return versionIds;
|
||||
};
|
||||
|
||||
readonly getLatestTaskFileContent = (taskId: string): TaskFileContent | null => {
|
||||
readonly getLatestTaskFileContent = (
|
||||
taskId: string,
|
||||
): TaskFileContent | null => {
|
||||
const taskFileContentOrNull: TaskFileContent | null =
|
||||
this.fileModel.getLatestFileContent(
|
||||
taskId,
|
||||
|
||||
@@ -12,11 +12,11 @@ export default class CalendarModel {
|
||||
readonly settingsModel: SettingsModel;
|
||||
|
||||
// paths
|
||||
get basePath (): string[] {
|
||||
get basePath(): string[] {
|
||||
return this.fileModel.getModelContainerPath(
|
||||
FileModelSubPath.ModelCalendar,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
readonly getViewPath = (): string[] => {
|
||||
return [...this.basePath, FileModelSubPath.ModelView];
|
||||
@@ -44,7 +44,10 @@ export default class CalendarModel {
|
||||
this.storageModel.write(referencePath, "");
|
||||
};
|
||||
|
||||
readonly deleteTaskReference = (monthString: string, taskId: string): void => {
|
||||
readonly deleteTaskReference = (
|
||||
monthString: string,
|
||||
taskId: string,
|
||||
): void => {
|
||||
const monthPath: string[] = this.getMonthPath(monthString);
|
||||
const referencePath: string[] = [...monthPath, taskId];
|
||||
|
||||
|
||||
@@ -29,13 +29,15 @@ export default class FileModel {
|
||||
StorageModelSubPaths.Chat,
|
||||
filePaths.chat.files(this.chatModel.id),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
readonly getFileContainerPath = (): string[] => {
|
||||
return [...this.basePath, FileModelSubPath.Data];
|
||||
};
|
||||
|
||||
readonly getModelContainerPath = (modelName: FileModelSubPath): string[] => {
|
||||
readonly getModelContainerPath = (
|
||||
modelName: FileModelSubPath,
|
||||
): string[] => {
|
||||
return [...this.basePath, FileModelSubPath.Model, modelName];
|
||||
};
|
||||
|
||||
@@ -43,13 +45,18 @@ export default class FileModel {
|
||||
return [...this.getFileContainerPath(), fileId];
|
||||
};
|
||||
|
||||
readonly getFileContentPath = (fileId: string, fileContentId: string): string[] => {
|
||||
readonly getFileContentPath = (
|
||||
fileId: string,
|
||||
fileContentId: string,
|
||||
): string[] => {
|
||||
const filePath: string[] = this.getFilePath(fileId);
|
||||
return [...filePath, fileContentId];
|
||||
};
|
||||
|
||||
// handlers
|
||||
readonly handleStringifiedFileContent = (stringifiedFileContent: string): void => {
|
||||
readonly handleStringifiedFileContent = (
|
||||
stringifiedFileContent: string,
|
||||
): void => {
|
||||
const fileContent: FileContent<string> | null = parseValidObject(
|
||||
stringifiedFileContent,
|
||||
FileContentReference,
|
||||
@@ -68,7 +75,9 @@ export default class FileModel {
|
||||
};
|
||||
|
||||
// methods
|
||||
readonly addFileContentAndSend = (fileContent: FileContent<string>): void => {
|
||||
readonly addFileContentAndSend = (
|
||||
fileContent: FileContent<string>,
|
||||
): void => {
|
||||
this.handleFileContent(fileContent);
|
||||
this.chatModel.sendMessage("", undefined, fileContent);
|
||||
};
|
||||
|
||||
@@ -69,7 +69,9 @@ export default class FileTransferModel {
|
||||
this.handleTransferredFile(data.messageBody);
|
||||
};
|
||||
|
||||
readonly handleTransferredFile = async (encryptedFileData: string): Promise<void> => {
|
||||
readonly handleTransferredFile = async (
|
||||
encryptedFileData: string,
|
||||
): Promise<void> => {
|
||||
if (this.transferData == undefined) return;
|
||||
|
||||
const decrypted: string = await decryptString(
|
||||
@@ -77,9 +79,22 @@ export default class FileTransferModel {
|
||||
this.transferData.key,
|
||||
);
|
||||
|
||||
this.handleDecryptedFile(decrypted);
|
||||
this.handleDecryptedFile(decrypted);
|
||||
};
|
||||
|
||||
readonly handleBackupFile = async (encryptedBackup: string, passphrase: string): Promise<void> => {
|
||||
const decrypted: string = await decryptString(encryptedBackup, passphrase);
|
||||
const parsed = parse(decrypted);
|
||||
if (!Array.isArray(parsed)) {
|
||||
console.error("Canceling backup - not an array", decrypted);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const file of parsed) {
|
||||
this.handleDecryptedFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
readonly handleDecryptedFile = (data: string): void => {
|
||||
const parsed: any = parse(data);
|
||||
const isFileData: boolean = checkMatchesObjectStructure(
|
||||
@@ -95,25 +110,40 @@ export default class FileTransferModel {
|
||||
...fileData.path,
|
||||
);
|
||||
this.fileHandlerManager.trigger(pathString);
|
||||
}
|
||||
};
|
||||
|
||||
// sending
|
||||
readonly sendFiles = (
|
||||
directoryPaths: IteratorObject<string[]>,
|
||||
callback: (path: string) => void,
|
||||
fileCallback: (path: string) => void,
|
||||
): void => {
|
||||
for (const directoryPath of directoryPaths) {
|
||||
this.storageModel.recurse(directoryPath, (filePath: string[]) => {
|
||||
this.prepareFileForSending(filePath);
|
||||
const stringifiedFileData =
|
||||
this.prepareFileForSending(filePath);
|
||||
this.sendFile(stringifiedFileData);
|
||||
const pathString: string = StorageModel.pathComponentsToString(
|
||||
...filePath,
|
||||
);
|
||||
callback(pathString);
|
||||
fileCallback(pathString);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
readonly prepareFileForSending = (filePath: string[]): void => {
|
||||
readonly generateBackup = async (directoryPaths: IteratorObject<string[]>, passphrase: string): Promise<string> => {
|
||||
const files: string[] = [];
|
||||
for (const directoryPath of directoryPaths) {
|
||||
this.storageModel.recurse(directoryPath, (filePath: string[]) => {
|
||||
const stringifiedFileData =
|
||||
this.prepareFileForSending(filePath);
|
||||
files.push(stringifiedFileData);
|
||||
});
|
||||
}
|
||||
const rawBackup = stringify(files);
|
||||
return await encryptString(rawBackup, passphrase);
|
||||
};
|
||||
|
||||
readonly prepareFileForSending = (filePath: string[]): string => {
|
||||
if (this.transferData == undefined) return;
|
||||
const fileContent: string | null = this.storageModel.read(filePath);
|
||||
if (fileContent == null) return;
|
||||
@@ -122,8 +152,7 @@ export default class FileTransferModel {
|
||||
path: filePath,
|
||||
body: fileContent,
|
||||
};
|
||||
const stringifiedFileData: string = stringify(fileData);
|
||||
this.sendFile(stringifiedFileData);
|
||||
return stringify(fileData);
|
||||
};
|
||||
|
||||
readonly sendFile = async (stringifiedFileData: string): Promise<void> => {
|
||||
|
||||
@@ -21,7 +21,7 @@ export default class SettingsModel {
|
||||
filePaths.settingsModel[pathName],
|
||||
);
|
||||
this.storageModel.write(path, value);
|
||||
}
|
||||
};
|
||||
|
||||
readonly setName = (newValue: string): void => {
|
||||
this.username = newValue;
|
||||
|
||||
@@ -69,7 +69,10 @@ export default class StorageModel {
|
||||
};
|
||||
|
||||
// recursion
|
||||
readonly recurse = (rootDirectory: string[], fn: (path: string[]) => void): void => {
|
||||
readonly recurse = (
|
||||
rootDirectory: string[],
|
||||
fn: (path: string[]) => void,
|
||||
): void => {
|
||||
loop_over_files: for (const key of Object.keys(localStorage)) {
|
||||
// get path of current entity
|
||||
const pathComponentsOfCurrentEntity: string[] =
|
||||
|
||||
@@ -81,4 +81,4 @@
|
||||
#chat-page > div > #main > #calendar-page .grid-pane-wrapper {
|
||||
border-right: 1px solid var(--border);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +103,7 @@ export function SettingsPage(
|
||||
coreViewModel.translations.chatPage.settings
|
||||
.setNamespaceButtonAudioLabel
|
||||
}
|
||||
on:click={
|
||||
settingsPageViewModel.setNamespace
|
||||
}
|
||||
on:click={settingsPageViewModel.setNamespace}
|
||||
toggle:disabled={
|
||||
settingsPageViewModel.cannotSetNamespace
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ export default class NotificationViewModel {
|
||||
if (this.chatListViewModel.selectedChat.value == undefined) return;
|
||||
|
||||
const currentChat =
|
||||
this.chatListViewModel.selectedChat.value.chatModel.
|
||||
unwrappedPrimaryChannel
|
||||
this.chatListViewModel.selectedChat.value.chatModel
|
||||
.unwrappedPrimaryChannel;
|
||||
const currentPage =
|
||||
this.chatListViewModel.selectedChat.value.selectedPage.value;
|
||||
if (
|
||||
@@ -41,7 +41,8 @@ export default class NotificationViewModel {
|
||||
const chat = [
|
||||
...this.chatListViewModel.chatViewModels.value.values(),
|
||||
].find(
|
||||
(chat) => chat.chatModel.unwrappedPrimaryChannel == notification.chat,
|
||||
(chat) =>
|
||||
chat.chatModel.unwrappedPrimaryChannel == notification.chat,
|
||||
);
|
||||
chat.open();
|
||||
chat.openPage(ChatPageTypes.Messages);
|
||||
@@ -79,7 +80,7 @@ export default class NotificationViewModel {
|
||||
};
|
||||
|
||||
// init
|
||||
constructor(public readonly chatListViewModel: ChatListViewModel) { }
|
||||
constructor(public readonly chatListViewModel: ChatListViewModel) {}
|
||||
|
||||
// util
|
||||
static createNotification(message: ChatMessage): Notification {
|
||||
|
||||
@@ -32,8 +32,7 @@ export default class SettingsPageViewModel extends Context {
|
||||
);
|
||||
cannotSetNamespace: React.State<boolean> = React.createProxyState(
|
||||
[this.namespace, this.namespaceInput],
|
||||
() =>
|
||||
this.namespaceInput.value == this.namespace.value,
|
||||
() => this.namespaceInput.value == this.namespace.value,
|
||||
);
|
||||
cannotAddSecondaryChannel: React.State<boolean> = React.createProxyState(
|
||||
[this.newSecondaryChannelInput],
|
||||
@@ -53,11 +52,8 @@ export default class SettingsPageViewModel extends Context {
|
||||
};
|
||||
|
||||
setNamespace = (): void => {
|
||||
this.chatViewModel.chatModel.setNamespace(
|
||||
this.namespaceInput.value,
|
||||
);
|
||||
this.namespace.value =
|
||||
this.chatViewModel.chatModel.info.namespace;
|
||||
this.chatViewModel.chatModel.setNamespace(this.namespaceInput.value);
|
||||
this.namespace.value = this.chatViewModel.chatModel.info.namespace;
|
||||
};
|
||||
|
||||
addSecondaryChannel = (): void => {
|
||||
@@ -101,17 +97,14 @@ export default class SettingsPageViewModel extends Context {
|
||||
preloadData = (): void => {
|
||||
this.primaryChannel.value =
|
||||
this.chatViewModel.chatModel.info.primaryChannel;
|
||||
this.namespace.value =
|
||||
this.chatViewModel.chatModel.info.namespace;
|
||||
this.namespace.value = this.chatViewModel.chatModel.info.namespace;
|
||||
|
||||
this.color.value = this.chatViewModel.chatModel.color;
|
||||
};
|
||||
|
||||
loadData = (): void => {
|
||||
this.primaryChannelInput.value =
|
||||
this.primaryChannel.value;
|
||||
this.namespaceInput.value =
|
||||
this.namespace.value;
|
||||
this.primaryChannelInput.value = this.primaryChannel.value;
|
||||
this.namespaceInput.value = this.namespace.value;
|
||||
|
||||
this.loadSecondaryChannels();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user