From 97a535c7eb890d8995e3f96fb35f8d3c16fa3456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Sun, 20 Dec 2020 23:51:15 +0100 Subject: [PATCH 1/9] Backend reporting encountered errors --- src/backend/move.ts | 108 +++++++++++++++++++++------------ src/interfaces/MoveErrors.ts | 3 + src/interfaces/MoveResponse.ts | 1 + 3 files changed, 73 insertions(+), 39 deletions(-) create mode 100644 src/interfaces/MoveErrors.ts diff --git a/src/backend/move.ts b/src/backend/move.ts index c6d90e5f..217252ab 100644 --- a/src/backend/move.ts +++ b/src/backend/move.ts @@ -17,13 +17,23 @@ function isSharedDriveEmpty( return response.items!.length === 0; } -function moveFile(file: string, source: string, destination: string): void { - Drive.Files!.update({}, file, null, { - addParents: destination, - removeParents: source, - supportsAllDrives: true, - fields: "", - }); +function moveFile( + file: string, + name: string, + source: string, + destination: string +): MoveErrors { + try { + Drive.Files!.update({}, file, null, { + addParents: destination, + removeParents: source, + supportsAllDrives: true, + fields: "", + }); + return []; + } catch (_) { + return [name]; + } } function copyFileComments(source: string, destination: string): void { @@ -67,17 +77,22 @@ function moveFileByCopy( name: string, destination: string, copyComments: boolean -): void { - const copy = Drive.Files!.copy( - { - parents: [{ id: destination }], - title: name, - }, - file, - { supportsAllDrives: true, fields: "id" } - ); - if (copyComments) { - copyFileComments(file, copy.id!); +): MoveErrors { + try { + const copy = Drive.Files!.copy( + { + parents: [{ id: destination }], + title: name, + }, + file, + { supportsAllDrives: true, fields: "id" } + ); + if (copyComments) { + copyFileComments(file, copy.id!); + } + return []; + } catch (_) { + return [name]; } } @@ -85,7 +100,7 @@ function moveFolderContentsFiles( source: string, destination: string, copyComments: boolean -): void { +): MoveErrors { const files = []; let pageToken = null; do { @@ -108,17 +123,23 @@ function moveFolderContentsFiles( } pageToken = response.nextPageToken; } while (pageToken !== undefined); + const errors: MoveErrors = []; for (const file of files) { if (file.canMove) { try { - moveFile(file.id!, source, destination); + errors.concat(moveFile(file.id!, file.name!, source, destination)); } catch (_) { - moveFileByCopy(file.id!, file.name!, destination, copyComments); + errors.concat( + moveFileByCopy(file.id!, file.name!, destination, copyComments) + ); } } else { - moveFileByCopy(file.id!, file.name!, destination, copyComments); + errors.concat( + moveFileByCopy(file.id!, file.name!, destination, copyComments) + ); } } + return errors; } function deleteFolderIfEmpty(folder: string): void { @@ -144,7 +165,7 @@ function moveFolderContentsFolders( source: string, destination: string, copyComments: boolean -): void { +): MoveErrors { const folders = []; let pageToken = null; do { @@ -162,28 +183,37 @@ function moveFolderContentsFolders( } pageToken = response.nextPageToken; } while (pageToken !== undefined); + let errors: MoveErrors = []; for (const folder of folders) { - const newFolder = Drive.Files!.insert( - { - parents: [{ id: destination }], - title: folder.name, - mimeType: "application/vnd.google-apps.folder", - }, - undefined, - { supportsAllDrives: true, fields: "id" } - ); - moveFolderContents(folder.id!, newFolder.id!, copyComments); // eslint-disable-line @typescript-eslint/no-use-before-define - deleteFolderIfEmpty(folder.id!); + try { + const newFolder = Drive.Files!.insert( + { + parents: [{ id: destination }], + title: folder.name, + mimeType: "application/vnd.google-apps.folder", + }, + undefined, + { supportsAllDrives: true, fields: "id" } + ); + errors = errors.concat( + moveFolderContents(folder.id!, newFolder.id!, copyComments) // eslint-disable-line @typescript-eslint/no-use-before-define + ); + deleteFolderIfEmpty(folder.id!); + } catch (_) { + errors.push(folder.name!); + } } + return errors; } function moveFolderContents( source: string, destination: string, copyComments: boolean -): void { - moveFolderContentsFiles(source, destination, copyComments); - moveFolderContentsFolders(source, destination, copyComments); +): MoveErrors { + return moveFolderContentsFiles(source, destination, copyComments).concat( + moveFolderContentsFolders(source, destination, copyComments) + ); } function move( @@ -195,6 +225,6 @@ function move( if (!isSharedDriveEmpty(sharedDrive, notEmptyOverride)) { return { status: "error", reason: "notEmpty" }; } - moveFolderContents(folder, sharedDrive, copyComments); - return { status: "success" }; + const errors = moveFolderContents(folder, sharedDrive, copyComments); + return { status: "success", errors }; } diff --git a/src/interfaces/MoveErrors.ts b/src/interfaces/MoveErrors.ts new file mode 100644 index 00000000..050ce22d --- /dev/null +++ b/src/interfaces/MoveErrors.ts @@ -0,0 +1,3 @@ +/* exported MoveErrors */ + +type MoveErrors = Array; diff --git a/src/interfaces/MoveResponse.ts b/src/interfaces/MoveResponse.ts index 988c913b..d3bf846f 100644 --- a/src/interfaces/MoveResponse.ts +++ b/src/interfaces/MoveResponse.ts @@ -3,4 +3,5 @@ interface MoveResponse { status: "success" | "error"; reason?: string; + errors?: MoveErrors; } From 684e0a4e6c3453a7d3d17cd9fd7036ded9ad87de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 22 Dec 2020 16:58:00 +0100 Subject: [PATCH 2/9] Returning error message on move error --- src/backend/move.ts | 55 +++++++++---------- src/interfaces/GoogleJsonResponseException.ts | 5 ++ src/interfaces/MoveError.ts | 6 ++ src/interfaces/MoveErrors.ts | 3 - src/interfaces/MoveResponse.ts | 2 +- 5 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 src/interfaces/GoogleJsonResponseException.ts create mode 100644 src/interfaces/MoveError.ts delete mode 100644 src/interfaces/MoveErrors.ts diff --git a/src/backend/move.ts b/src/backend/move.ts index 217252ab..c8166d53 100644 --- a/src/backend/move.ts +++ b/src/backend/move.ts @@ -22,18 +22,13 @@ function moveFile( name: string, source: string, destination: string -): MoveErrors { - try { - Drive.Files!.update({}, file, null, { - addParents: destination, - removeParents: source, - supportsAllDrives: true, - fields: "", - }); - return []; - } catch (_) { - return [name]; - } +): void { + Drive.Files!.update({}, file, null, { + addParents: destination, + removeParents: source, + supportsAllDrives: true, + fields: "", + }); } function copyFileComments(source: string, destination: string): void { @@ -77,7 +72,7 @@ function moveFileByCopy( name: string, destination: string, copyComments: boolean -): MoveErrors { +): MoveError | null { try { const copy = Drive.Files!.copy( { @@ -90,9 +85,9 @@ function moveFileByCopy( if (copyComments) { copyFileComments(file, copy.id!); } - return []; - } catch (_) { - return [name]; + return null; + } catch (e) { + return { file: name, error: (e as GoogleJsonResponseException).message }; } } @@ -100,7 +95,7 @@ function moveFolderContentsFiles( source: string, destination: string, copyComments: boolean -): MoveErrors { +): Array { const files = []; let pageToken = null; do { @@ -123,20 +118,20 @@ function moveFolderContentsFiles( } pageToken = response.nextPageToken; } while (pageToken !== undefined); - const errors: MoveErrors = []; + const errors: Array = []; for (const file of files) { + let error = null; if (file.canMove) { try { - errors.concat(moveFile(file.id!, file.name!, source, destination)); + moveFile(file.id!, file.name!, source, destination); } catch (_) { - errors.concat( - moveFileByCopy(file.id!, file.name!, destination, copyComments) - ); + error = moveFileByCopy(file.id!, file.name!, destination, copyComments); } } else { - errors.concat( - moveFileByCopy(file.id!, file.name!, destination, copyComments) - ); + error = moveFileByCopy(file.id!, file.name!, destination, copyComments); + } + if (error !== null) { + errors.push(error); } } return errors; @@ -165,7 +160,7 @@ function moveFolderContentsFolders( source: string, destination: string, copyComments: boolean -): MoveErrors { +): Array { const folders = []; let pageToken = null; do { @@ -183,7 +178,7 @@ function moveFolderContentsFolders( } pageToken = response.nextPageToken; } while (pageToken !== undefined); - let errors: MoveErrors = []; + let errors: Array = []; for (const folder of folders) { try { const newFolder = Drive.Files!.insert( @@ -199,8 +194,8 @@ function moveFolderContentsFolders( moveFolderContents(folder.id!, newFolder.id!, copyComments) // eslint-disable-line @typescript-eslint/no-use-before-define ); deleteFolderIfEmpty(folder.id!); - } catch (_) { - errors.push(folder.name!); + } catch (e) { + errors.push({ file: folder.name!, error: e as string }); } } return errors; @@ -210,7 +205,7 @@ function moveFolderContents( source: string, destination: string, copyComments: boolean -): MoveErrors { +): Array { return moveFolderContentsFiles(source, destination, copyComments).concat( moveFolderContentsFolders(source, destination, copyComments) ); diff --git a/src/interfaces/GoogleJsonResponseException.ts b/src/interfaces/GoogleJsonResponseException.ts new file mode 100644 index 00000000..51f4d806 --- /dev/null +++ b/src/interfaces/GoogleJsonResponseException.ts @@ -0,0 +1,5 @@ +/* exported GoogleJsonResponseException */ + +interface GoogleJsonResponseException { + message: string; +} diff --git a/src/interfaces/MoveError.ts b/src/interfaces/MoveError.ts new file mode 100644 index 00000000..6b25bd5d --- /dev/null +++ b/src/interfaces/MoveError.ts @@ -0,0 +1,6 @@ +/* exported MoveError */ + +interface MoveError { + file: string; + error: string; +} diff --git a/src/interfaces/MoveErrors.ts b/src/interfaces/MoveErrors.ts deleted file mode 100644 index 050ce22d..00000000 --- a/src/interfaces/MoveErrors.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* exported MoveErrors */ - -type MoveErrors = Array; diff --git a/src/interfaces/MoveResponse.ts b/src/interfaces/MoveResponse.ts index d3bf846f..b670443b 100644 --- a/src/interfaces/MoveResponse.ts +++ b/src/interfaces/MoveResponse.ts @@ -3,5 +3,5 @@ interface MoveResponse { status: "success" | "error"; reason?: string; - errors?: MoveErrors; + errors?: Array; } From 1f5b0503430c799482922f60155b4c8f826199e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 22 Dec 2020 17:40:27 +0100 Subject: [PATCH 3/9] parameter rename --- src/backend/move.ts | 86 ++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/src/backend/move.ts b/src/backend/move.ts index c8166d53..b59083fa 100644 --- a/src/backend/move.ts +++ b/src/backend/move.ts @@ -1,7 +1,7 @@ /* exported move */ -function isSharedDriveEmpty( - sharedDrive: string, +function isDirectoryEmpty( + directoryID: string, notEmptyOverride: boolean ): boolean { if (notEmptyOverride) { @@ -10,7 +10,7 @@ function isSharedDriveEmpty( const response = Drive.Files!.list({ includeItemsFromAllDrives: true, maxResults: 1, - q: '"' + sharedDrive + '" in parents and trashed = false', + q: '"' + directoryID + '" in parents and trashed = false', supportsAllDrives: true, fields: "items(id)", }); @@ -18,25 +18,24 @@ function isSharedDriveEmpty( } function moveFile( - file: string, - name: string, - source: string, - destination: string + fileID: string, + sourceID: string, + destinationID: string ): void { - Drive.Files!.update({}, file, null, { - addParents: destination, - removeParents: source, + Drive.Files!.update({}, fileID, null, { + addParents: destinationID, + removeParents: sourceID, supportsAllDrives: true, fields: "", }); } -function copyFileComments(source: string, destination: string): void { +function copyFileComments(sourceID: string, destinationID: string): void { const comments = []; let pageToken = null; do { const response: GoogleAppsScript.Drive.Schema.CommentList = Drive.Comments!.list( - source, + sourceID, { maxResults: 100, pageToken: pageToken, @@ -56,34 +55,34 @@ function copyFileComments(source: string, destination: string): void { } const replies = comment.replies!; delete comment.replies; - const commentId = Drive.Comments!.insert(comment, destination).commentId!; + const commentId = Drive.Comments!.insert(comment, destinationID).commentId!; for (const reply of replies) { if (!reply.author!.isAuthenticatedUser) { reply.content = "*" + reply.author!.displayName! + ":*\n" + reply.content!; } - Drive.Replies!.insert(reply, destination, commentId); + Drive.Replies!.insert(reply, destinationID, commentId); } } } function moveFileByCopy( - file: string, + fileID: string, name: string, - destination: string, + destinationID: string, copyComments: boolean ): MoveError | null { try { const copy = Drive.Files!.copy( { - parents: [{ id: destination }], + parents: [{ id: destinationID }], title: name, }, - file, + fileID, { supportsAllDrives: true, fields: "id" } ); if (copyComments) { - copyFileComments(file, copy.id!); + copyFileComments(fileID, copy.id!); } return null; } catch (e) { @@ -92,8 +91,8 @@ function moveFileByCopy( } function moveFolderContentsFiles( - source: string, - destination: string, + sourceID: string, + destinationID: string, copyComments: boolean ): Array { const files = []; @@ -102,7 +101,7 @@ function moveFolderContentsFiles( const response: GoogleAppsScript.Drive.Schema.FileList = Drive.Files!.list({ q: '"' + - source + + sourceID + '" in parents and mimeType != "application/vnd.google-apps.folder" and trashed = false', pageToken: pageToken, maxResults: 1000, @@ -123,12 +122,17 @@ function moveFolderContentsFiles( let error = null; if (file.canMove) { try { - moveFile(file.id!, file.name!, source, destination); + moveFile(file.id!, sourceID, destinationID); } catch (_) { - error = moveFileByCopy(file.id!, file.name!, destination, copyComments); + error = moveFileByCopy( + file.id!, + file.name!, + destinationID, + copyComments + ); } } else { - error = moveFileByCopy(file.id!, file.name!, destination, copyComments); + error = moveFileByCopy(file.id!, file.name!, destinationID, copyComments); } if (error !== null) { errors.push(error); @@ -137,28 +141,28 @@ function moveFolderContentsFiles( return errors; } -function deleteFolderIfEmpty(folder: string): void { +function deleteFolderIfEmpty(folderID: string): void { const response = Drive.Files!.list({ maxResults: 1, - q: '"' + folder + '" in parents and trashed = false', + q: '"' + folderID + '" in parents and trashed = false', fields: "items(id)", }); if (response.items!.length === 0) { - const response2 = Drive.Files!.get(folder, { + const response2 = Drive.Files!.get(folderID, { fields: "userPermission(role)", }); if ( response2.userPermission!.role === "owner" || response2.userPermission!.role === "organizer" ) { - Drive.Files!.remove(folder); + Drive.Files!.remove(folderID); } } } function moveFolderContentsFolders( - source: string, - destination: string, + sourceID: string, + destinationID: string, copyComments: boolean ): Array { const folders = []; @@ -167,7 +171,7 @@ function moveFolderContentsFolders( const response: GoogleAppsScript.Drive.Schema.FileList = Drive.Files!.list({ q: '"' + - source + + sourceID + '" in parents and mimeType = "application/vnd.google-apps.folder" and trashed = false', pageToken: pageToken, maxResults: 1000, @@ -183,7 +187,7 @@ function moveFolderContentsFolders( try { const newFolder = Drive.Files!.insert( { - parents: [{ id: destination }], + parents: [{ id: destinationID }], title: folder.name, mimeType: "application/vnd.google-apps.folder", }, @@ -202,24 +206,24 @@ function moveFolderContentsFolders( } function moveFolderContents( - source: string, - destination: string, + sourceID: string, + destinationID: string, copyComments: boolean ): Array { - return moveFolderContentsFiles(source, destination, copyComments).concat( - moveFolderContentsFolders(source, destination, copyComments) + return moveFolderContentsFiles(sourceID, destinationID, copyComments).concat( + moveFolderContentsFolders(sourceID, destinationID, copyComments) ); } function move( - folder: string, - sharedDrive: string, + sourceID: string, + destinationID: string, copyComments: boolean, notEmptyOverride: boolean ): MoveResponse { - if (!isSharedDriveEmpty(sharedDrive, notEmptyOverride)) { + if (!isDirectoryEmpty(destinationID, notEmptyOverride)) { return { status: "error", reason: "notEmpty" }; } - const errors = moveFolderContents(folder, sharedDrive, copyComments); + const errors = moveFolderContents(sourceID, destinationID, copyComments); return { status: "success", errors }; } From bf6c050f87071dfbc2032641030d297d760e0e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 22 Dec 2020 19:38:21 +0100 Subject: [PATCH 4/9] Returning whole path on error --- src/backend/move.ts | 38 ++++++++++++++++++++++++++++++------- src/interfaces/MoveError.ts | 2 +- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/backend/move.ts b/src/backend/move.ts index b59083fa..b3838aea 100644 --- a/src/backend/move.ts +++ b/src/backend/move.ts @@ -70,6 +70,7 @@ function moveFileByCopy( fileID: string, name: string, destinationID: string, + path: Array, copyComments: boolean ): MoveError | null { try { @@ -86,13 +87,17 @@ function moveFileByCopy( } return null; } catch (e) { - return { file: name, error: (e as GoogleJsonResponseException).message }; + return { + file: path.concat([name]), + error: (e as GoogleJsonResponseException).message, + }; } } function moveFolderContentsFiles( sourceID: string, destinationID: string, + path: Array, copyComments: boolean ): Array { const files = []; @@ -128,11 +133,18 @@ function moveFolderContentsFiles( file.id!, file.name!, destinationID, + path, copyComments ); } } else { - error = moveFileByCopy(file.id!, file.name!, destinationID, copyComments); + error = moveFileByCopy( + file.id!, + file.name!, + destinationID, + path, + copyComments + ); } if (error !== null) { errors.push(error); @@ -163,6 +175,7 @@ function deleteFolderIfEmpty(folderID: string): void { function moveFolderContentsFolders( sourceID: string, destinationID: string, + path: Array, copyComments: boolean ): Array { const folders = []; @@ -195,11 +208,16 @@ function moveFolderContentsFolders( { supportsAllDrives: true, fields: "id" } ); errors = errors.concat( - moveFolderContents(folder.id!, newFolder.id!, copyComments) // eslint-disable-line @typescript-eslint/no-use-before-define + moveFolderContents( + folder.id!, + newFolder.id!, + path.concat([folder.name!]), + copyComments + ) ); deleteFolderIfEmpty(folder.id!); } catch (e) { - errors.push({ file: folder.name!, error: e as string }); + errors.push({ file: path.concat([folder.name!]), error: e as string }); } } return errors; @@ -208,10 +226,16 @@ function moveFolderContentsFolders( function moveFolderContents( sourceID: string, destinationID: string, + path: Array, copyComments: boolean ): Array { - return moveFolderContentsFiles(sourceID, destinationID, copyComments).concat( - moveFolderContentsFolders(sourceID, destinationID, copyComments) + return moveFolderContentsFiles( + sourceID, + destinationID, + path, + copyComments + ).concat( + moveFolderContentsFolders(sourceID, destinationID, path, copyComments) ); } @@ -224,6 +248,6 @@ function move( if (!isDirectoryEmpty(destinationID, notEmptyOverride)) { return { status: "error", reason: "notEmpty" }; } - const errors = moveFolderContents(sourceID, destinationID, copyComments); + const errors = moveFolderContents(sourceID, destinationID, [], copyComments); return { status: "success", errors }; } diff --git a/src/interfaces/MoveError.ts b/src/interfaces/MoveError.ts index 6b25bd5d..63cbc01f 100644 --- a/src/interfaces/MoveError.ts +++ b/src/interfaces/MoveError.ts @@ -1,6 +1,6 @@ /* exported MoveError */ interface MoveError { - file: string; + file: Array; error: string; } From 8d2b374468a36c39b9a3724b66258e53522e0397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 22 Dec 2020 19:39:18 +0100 Subject: [PATCH 5/9] Logging move errors --- src/backend/move.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/move.ts b/src/backend/move.ts index b3838aea..fbe03125 100644 --- a/src/backend/move.ts +++ b/src/backend/move.ts @@ -249,5 +249,8 @@ function move( return { status: "error", reason: "notEmpty" }; } const errors = moveFolderContents(sourceID, destinationID, [], copyComments); + if (errors.length > 0) { + console.error(errors); + } return { status: "success", errors }; } From c3d6f68dbb779783642e44249f0a896de013592d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 22 Dec 2020 20:10:13 +0100 Subject: [PATCH 6/9] Added logic for Error reporting in frontend --- src/frontend/App.vue | 4 +++- src/frontend/Done.vue | 28 ++++++++++++++++++++++++++-- src/frontend/index.ts | 2 ++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/frontend/App.vue b/src/frontend/App.vue index a35aeefa..4d35e9f5 100644 --- a/src/frontend/App.vue +++ b/src/frontend/App.vue @@ -53,7 +53,7 @@ - + , }; }, created() { @@ -198,6 +199,7 @@ export default Vue.extend({ this.displayNonEmptyDialog = true; } } else { + this.errors = response.errors!; this.activeStep = "done"; } }, diff --git a/src/frontend/Done.vue b/src/frontend/Done.vue index 95c827d2..e9e77733 100644 --- a/src/frontend/Done.vue +++ b/src/frontend/Done.vue @@ -1,13 +1,37 @@