Skip to content

Commit 87aae42

Browse files
cdarsowbischofmax
andauthored
BC-10468 - add collabora docs in folder (#3980)
* Refactor editMode mapper --------- Co-authored-by: Max Bischof <[email protected]>
1 parent 0439e97 commit 87aae42

27 files changed

+1043
-135
lines changed

src/components/icons/material/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import {
7171
mdiEyeOutline,
7272
mdiFileCertificateOutline,
7373
mdiFileDocumentOutline,
74+
mdiFileDocumentPlusOutline,
7475
mdiFileMusicOutline,
7576
mdiFileQuestionOutline,
7677
mdiFileReplaceOutline,
@@ -236,6 +237,7 @@ export {
236237
mdiEyeOutline,
237238
mdiFileCertificateOutline,
238239
mdiFileDocumentOutline,
240+
mdiFileDocumentPlusOutline,
239241
mdiFileMusicOutline,
240242
mdiFileQuestionOutline,
241243
mdiFileReplaceOutline,

src/locales/de.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,4 +2013,12 @@ export default {
20132013
"pages.folder.delete-confirmation": "Datei {name} wirklich löschen?",
20142014
"pages.folder.rename-file-dialog.validation.duplicate-file-name": "Der Dateiname existiert bereits.",
20152015
"pages.folder.rename-file-dialog.validation.invalid-characters": "Der Dateiname enthält ungültige Zeichen.",
2016+
"pages.folder.fab.upload-file": "Datei hochladen",
2017+
"pages.folder.fab.create-document": "Dokument erstellen",
2018+
"pages.folder.add-collabora-file-dialog.title": "Dokument erstellen",
2019+
"pages.folder.add-collabora-file-dialog.doc-types": "Dokumententyp",
2020+
"pages.folder.add-collabora-file-dialog.untitled-file": "Unbenanntes Dokument",
2021+
"pages.folder.add-collabora-file-dialog.option.text": ".docx (Text)",
2022+
"pages.folder.add-collabora-file-dialog.option.spreadsheet": ".xlsx (Tabelle)",
2023+
"pages.folder.add-collabora-file-dialog.option.presentation": ".pptx (Präsentation)",
20162024
};

src/locales/en.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1977,4 +1977,12 @@ export default {
19771977
"pages.folder.delete-confirmation": "Do you really want to delete file {name}?",
19781978
"pages.folder.rename-file-dialog.validation.duplicate-file-name": "The file name already exists.",
19791979
"pages.folder.rename-file-dialog.validation.invalid-characters": "The file name contains invalid characters.",
1980+
"pages.folder.fab.upload-file": "Upload file",
1981+
"pages.folder.fab.create-document": "Create document",
1982+
"pages.folder.add-collabora-file-dialog.title": "Create document",
1983+
"pages.folder.add-collabora-file-dialog.doc-types": "Document type",
1984+
"pages.folder.add-collabora-file-dialog.untitled-file": "Untitled document",
1985+
"pages.folder.add-collabora-file-dialog.option.text": ".docx (Text)",
1986+
"pages.folder.add-collabora-file-dialog.option.spreadsheet": ".xlsx (Spreadsheet)",
1987+
"pages.folder.add-collabora-file-dialog.option.presentation": ".pptx (Presentation)",
19801988
};

src/locales/es.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2028,4 +2028,12 @@ export default {
20282028
"pages.folder.rename-file-dialog.validation.duplicate-file-name": "El nombre del archivo ya existe.",
20292029
"pages.folder.rename-file-dialog.validation.invalid-characters":
20302030
"El nombre del archivo contiene caracteres no válidos.",
2031+
"pages.folder.fab.upload-file": "Subir archivo",
2032+
"pages.folder.fab.create-document": "Crear documento",
2033+
"pages.folder.add-collabora-file-dialog.title": "Crear documento",
2034+
"pages.folder.add-collabora-file-dialog.doc-types": "Tipo de documento",
2035+
"pages.folder.add-collabora-file-dialog.untitled-file": "Documento sin título",
2036+
"pages.folder.add-collabora-file-dialog.option.text": ".docx (Texto)",
2037+
"pages.folder.add-collabora-file-dialog.option.spreadsheet": ".xlsx (Hoja de cálculo)",
2038+
"pages.folder.add-collabora-file-dialog.option.presentation": ".pptx (Presentación)",
20312039
};

src/locales/uk.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,4 +1997,12 @@ export default {
19971997
"pages.folder.delete-confirmation": "Дійсно видалити файл {name}?",
19981998
"pages.folder.rename-file-dialog.validation.duplicate-file-name": "Ім'я файлу вже існує.",
19991999
"pages.folder.rename-file-dialog.validation.invalid-characters": "Ім'я файлу містить недопустимі символи.",
2000+
"pages.folder.fab.upload-file": "Завантажити файл",
2001+
"pages.folder.fab.create-document": "Створити документ",
2002+
"pages.folder.add-collabora-file-dialog.title": "Створити документ",
2003+
"pages.folder.add-collabora-file-dialog.doc-types": "Тип документа",
2004+
"pages.folder.add-collabora-file-dialog.untitled-file": "Без назви документ",
2005+
"pages.folder.add-collabora-file-dialog.option.text": ".docx (Документ)",
2006+
"pages.folder.add-collabora-file-dialog.option.spreadsheet": ".xlsx (Таблиця)",
2007+
"pages.folder.add-collabora-file-dialog.option.presentation": ".pptx (Презентація)",
20002008
};

src/modules/data/file/FileStorageApi.composable.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
StorageLocation,
1111
} from "@/types/file/File";
1212
import { $axios, mapAxiosErrorToResponseError } from "@/utils/api";
13-
import { formatFileSize } from "@/utils/fileHelper";
13+
import { formatFileSize, getFileExtension } from "@/utils/fileHelper";
1414
import { notifyError, useAppStore } from "@data-app";
1515
import { useEnvFileConfig } from "@data-env";
1616
import { useI18n } from "vue-i18n";
@@ -26,6 +26,12 @@ export enum ErrorType {
2626
Forbidden = "Forbidden",
2727
}
2828

29+
export enum CollaboraFileType {
30+
Text,
31+
Spreadsheet,
32+
Presentation,
33+
}
34+
2935
export const useFileStorageApi = () => {
3036
const { t } = useI18n();
3137
const fileApi: FileApiInterface = FileApiFactory(undefined, "/v3", $axios);
@@ -69,12 +75,40 @@ export const useFileStorageApi = () => {
6975
}
7076
};
7177

78+
const getCollaboraAssetUrl = (collaboraFileType: CollaboraFileType): string => {
79+
const base = `${window.location.origin}/collabora`;
80+
81+
if (collaboraFileType === CollaboraFileType.Text) {
82+
return `${base}/doc.docx`;
83+
}
84+
if (collaboraFileType === CollaboraFileType.Spreadsheet) {
85+
return `${base}/spreadsheet.xlsx`;
86+
}
87+
88+
return `${base}/presentation.pptx`;
89+
};
90+
91+
const uploadCollaboraFile = async (
92+
type: CollaboraFileType,
93+
parentId: string,
94+
parentType: FileRecordParent,
95+
fileName: string
96+
) => {
97+
const assetUrl = getCollaboraAssetUrl(type);
98+
const fileExtension = getFileExtension(assetUrl);
99+
const fullFileName = `${fileName}.${fileExtension}`;
100+
101+
const fileRecord = await uploadFromUrl(assetUrl, parentId, parentType, fullFileName);
102+
103+
return fileRecord;
104+
};
105+
72106
const uploadFromUrl = async (
73107
imageUrl: string,
74108
parentId: string,
75109
parentType: FileRecordParent,
76110
fileName?: string
77-
): Promise<void> => {
111+
): Promise<FileRecord | void> => {
78112
try {
79113
const { pathname } = new URL(imageUrl);
80114
fileName = fileName ?? pathname.substring(pathname.lastIndexOf("/") + 1);
@@ -93,6 +127,8 @@ export const useFileStorageApi = () => {
93127
);
94128

95129
upsertFileRecords([response.data]);
130+
131+
return response.data;
96132
} catch (error) {
97133
showError(error);
98134
}
@@ -195,5 +231,6 @@ export const useFileStorageApi = () => {
195231
tryGetParentStatisticFromApi: fetchFileStatistic,
196232
getAuthorizedCollaboraDocumentUrl,
197233
fetchFileById,
234+
uploadCollaboraFile,
198235
};
199236
};

src/modules/data/file/FileStorageApi.composable.unit.ts

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ErrorType, useFileStorageApi } from "./FileStorageApi.composable";
1+
import { CollaboraFileType, ErrorType, useFileStorageApi } from "./FileStorageApi.composable";
22
import * as serverApi from "@/fileStorageApi/v3/api/file-api";
33
import * as wopiApi from "@/fileStorageApi/v3/api/wopi-api";
44
import {
@@ -18,6 +18,7 @@ import {
1818
import { apiResponseErrorFactory } from "@@/tests/test-utils/factory/apiResponseErrorFactory";
1919
import { axiosErrorFactory } from "@@/tests/test-utils/factory/axiosErrorFactory";
2020
import { fileRecordFactory } from "@@/tests/test-utils/factory/filerecordResponse.factory";
21+
import { fileUrlParamsFactory } from "@@/tests/test-utils/factory/fileUrlParamsFactory";
2122
import { ObjectIdMock } from "@@/tests/test-utils/ObjectIdMock";
2223
import { useNotificationStore } from "@data-app";
2324
import { createMock } from "@golevelup/ts-vitest";
@@ -445,6 +446,15 @@ describe("FileStorageApi Composable", () => {
445446
expect(fileRecord).toStrictEqual([fileRecordResponse]);
446447
});
447448

449+
it("should return created file record", async () => {
450+
const { parentId, parentType, imageUrl, fileRecordResponse } = setup();
451+
const { uploadFromUrl } = useFileStorageApi();
452+
453+
const createdFileRecord = await uploadFromUrl(imageUrl, parentId, parentType);
454+
455+
expect(createdFileRecord).toStrictEqual(fileRecordResponse);
456+
});
457+
448458
describe("when file name is empty", () => {
449459
it("should upload file with default filename", async () => {
450460
const emptyFileName = "";
@@ -806,4 +816,198 @@ describe("FileStorageApi Composable", () => {
806816
});
807817
});
808818
});
819+
820+
describe("uploadCollaboraFile", () => {
821+
describe("when uploading a collabora text file", () => {
822+
const setup = () => {
823+
const fileName = "newCollaboraFile";
824+
const parentId = ObjectIdMock();
825+
const parentType = FileRecordParent.BOARDNODES;
826+
const fileRecordResponse = fileRecordFactory.build({
827+
parentId,
828+
parentType,
829+
name: fileName + ".docx",
830+
});
831+
const response = createMock<AxiosResponse<FileRecord, unknown>>({
832+
data: fileRecordResponse,
833+
});
834+
835+
const fileApi = createMock<serverApi.FileApiInterface>();
836+
vi.spyOn(serverApi, "FileApiFactory").mockReturnValueOnce(fileApi);
837+
fileApi.uploadFromUrl.mockResolvedValueOnce(response);
838+
839+
const { uploadCollaboraFile } = useFileStorageApi();
840+
841+
const fileParams = fileUrlParamsFactory.build({
842+
fileName: `${fileName}.docx`,
843+
headers: {
844+
"User-Agent": "Embed Request User Agent",
845+
},
846+
url: `http://localhost:3000/collabora/doc.docx`,
847+
});
848+
849+
return {
850+
uploadCollaboraFile,
851+
fileRecordResponse,
852+
fileName,
853+
fileApi,
854+
fileParams,
855+
};
856+
};
857+
858+
it("returns created file record", async () => {
859+
const { uploadCollaboraFile, fileRecordResponse, fileName } = setup();
860+
const newFile = await uploadCollaboraFile(
861+
CollaboraFileType.Text,
862+
"parentId",
863+
FileRecordParent.BOARDNODES,
864+
fileName
865+
);
866+
867+
expect(newFile).toBe(fileRecordResponse);
868+
});
869+
870+
it("calls uploadFromUrl with correct params", async () => {
871+
const { uploadCollaboraFile, fileName, fileApi, fileParams } = setup();
872+
873+
await uploadCollaboraFile(CollaboraFileType.Text, "parentId", FileRecordParent.BOARDNODES, fileName);
874+
875+
expect(fileApi.uploadFromUrl).toHaveBeenCalledWith(
876+
"schoolId",
877+
StorageLocation.SCHOOL,
878+
"parentId",
879+
FileRecordParent.BOARDNODES,
880+
fileParams
881+
);
882+
});
883+
});
884+
885+
describe("when uploading a collabora spreadsheet file", () => {
886+
const setup = () => {
887+
const fileName = "newCollaboraFile";
888+
const parentId = ObjectIdMock();
889+
const parentType = FileRecordParent.BOARDNODES;
890+
const fileRecordResponse = fileRecordFactory.build({
891+
parentId,
892+
parentType,
893+
name: fileName + ".xlsx",
894+
});
895+
const response = createMock<AxiosResponse<FileRecord, unknown>>({
896+
data: fileRecordResponse,
897+
});
898+
899+
const fileApi = createMock<serverApi.FileApiInterface>();
900+
vi.spyOn(serverApi, "FileApiFactory").mockReturnValueOnce(fileApi);
901+
fileApi.uploadFromUrl.mockResolvedValueOnce(response);
902+
903+
const { uploadCollaboraFile } = useFileStorageApi();
904+
905+
const fileParams = fileUrlParamsFactory.build({
906+
fileName: `${fileName}.xlsx`,
907+
headers: {
908+
"User-Agent": "Embed Request User Agent",
909+
},
910+
url: `http://localhost:3000/collabora/spreadsheet.xlsx`,
911+
});
912+
913+
return {
914+
uploadCollaboraFile,
915+
fileRecordResponse,
916+
fileName,
917+
fileApi,
918+
fileParams,
919+
};
920+
};
921+
922+
it("returns created file record", async () => {
923+
const { uploadCollaboraFile, fileRecordResponse, fileName } = setup();
924+
const newFile = await uploadCollaboraFile(
925+
CollaboraFileType.Spreadsheet,
926+
"parentId",
927+
FileRecordParent.BOARDNODES,
928+
fileName
929+
);
930+
931+
expect(newFile).toBe(fileRecordResponse);
932+
});
933+
934+
it("calls uploadFromUrl with correct params", async () => {
935+
const { uploadCollaboraFile, fileName, fileApi, fileParams } = setup();
936+
937+
await uploadCollaboraFile(CollaboraFileType.Spreadsheet, "parentId", FileRecordParent.BOARDNODES, fileName);
938+
939+
expect(fileApi.uploadFromUrl).toHaveBeenCalledWith(
940+
"schoolId",
941+
StorageLocation.SCHOOL,
942+
"parentId",
943+
FileRecordParent.BOARDNODES,
944+
fileParams
945+
);
946+
});
947+
});
948+
949+
describe("when uploading a collabora presentation file", () => {
950+
const setup = () => {
951+
const fileName = "newCollaboraFile";
952+
const parentId = ObjectIdMock();
953+
const parentType = FileRecordParent.BOARDNODES;
954+
const fileRecordResponse = fileRecordFactory.build({
955+
parentId,
956+
parentType,
957+
name: fileName + ".pptx",
958+
});
959+
const response = createMock<AxiosResponse<FileRecord, unknown>>({
960+
data: fileRecordResponse,
961+
});
962+
963+
const fileApi = createMock<serverApi.FileApiInterface>();
964+
vi.spyOn(serverApi, "FileApiFactory").mockReturnValueOnce(fileApi);
965+
fileApi.uploadFromUrl.mockResolvedValueOnce(response);
966+
967+
const { uploadCollaboraFile } = useFileStorageApi();
968+
969+
const fileParams = fileUrlParamsFactory.build({
970+
fileName: `${fileName}.pptx`,
971+
headers: {
972+
"User-Agent": "Embed Request User Agent",
973+
},
974+
url: `http://localhost:3000/collabora/presentation.pptx`,
975+
});
976+
977+
return {
978+
uploadCollaboraFile,
979+
fileRecordResponse,
980+
fileName,
981+
fileApi,
982+
fileParams,
983+
};
984+
};
985+
986+
it("returns created file record", async () => {
987+
const { uploadCollaboraFile, fileRecordResponse, fileName } = setup();
988+
const newFile = await uploadCollaboraFile(
989+
CollaboraFileType.Presentation,
990+
"parentId",
991+
FileRecordParent.BOARDNODES,
992+
fileName
993+
);
994+
995+
expect(newFile).toBe(fileRecordResponse);
996+
});
997+
998+
it("calls uploadFromUrl with correct params", async () => {
999+
const { uploadCollaboraFile, fileName, fileApi, fileParams } = setup();
1000+
1001+
await uploadCollaboraFile(CollaboraFileType.Presentation, "parentId", FileRecordParent.BOARDNODES, fileName);
1002+
1003+
expect(fileApi.uploadFromUrl).toHaveBeenCalledWith(
1004+
"schoolId",
1005+
StorageLocation.SCHOOL,
1006+
"parentId",
1007+
FileRecordParent.BOARDNODES,
1008+
fileParams
1009+
);
1010+
});
1011+
});
1012+
});
8091013
});

src/modules/data/file/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from "./FileRecords.state";
2-
export { useFileStorageApi } from "./FileStorageApi.composable";
2+
export { CollaboraFileType, useFileStorageApi } from "./FileStorageApi.composable";

0 commit comments

Comments
 (0)