From d29624c8160ef394a166b7585188831ab94ad946 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 17 May 2021 18:55:39 +0200 Subject: [PATCH] Desktop: Handle too large items for Joplin Server --- packages/app-desktop/runForSharing.sh | 45 +++++++++++--------- packages/lib/file-api-driver-joplinServer.ts | 15 +++++-- packages/server/src/models/ItemModel.ts | 13 +++++- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/packages/app-desktop/runForSharing.sh b/packages/app-desktop/runForSharing.sh index 352c0cdc81..03283b852c 100755 --- a/packages/app-desktop/runForSharing.sh +++ b/packages/app-desktop/runForSharing.sh @@ -14,32 +14,35 @@ if [ "$1" == "" ]; then fi USER_NUM=$1 - -CMD_FILE="$SCRIPT_DIR/runForSharingCommands-$USER_NUM.txt" -rm -f "$CMD_FILE" - -USER_EMAIL="user$USER_NUM@example.com" +RESET_ALL=$2 PROFILE_DIR=~/.config/joplindev-desktop-$USER_NUM -rm -rf "$PROFILE_DIR" -echo "config keychain.supported 0" >> "$CMD_FILE" -echo "config sync.target 9" >> "$CMD_FILE" -echo "config sync.9.path http://localhost:22300" >> "$CMD_FILE" -echo "config sync.9.username $USER_EMAIL" >> "$CMD_FILE" -echo "config sync.9.password 123456" >> "$CMD_FILE" +if [ "$RESET_ALL" == "1" ]; then + CMD_FILE="$SCRIPT_DIR/runForSharingCommands-$USER_NUM.txt" + rm -f "$CMD_FILE" -if [ "$1" == "1" ]; then - curl --data '{"action": "createTestUsers"}' http://localhost:22300/api/debug + USER_EMAIL="user$USER_NUM@example.com" + rm -rf "$PROFILE_DIR" - echo 'mkbook "shared"' >> "$CMD_FILE" - echo 'mkbook "other"' >> "$CMD_FILE" - echo 'use "shared"' >> "$CMD_FILE" - echo 'mknote "note 1"' >> "$CMD_FILE" - echo 'mknote "note 2"' >> "$CMD_FILE" + echo "config keychain.supported 0" >> "$CMD_FILE" + echo "config sync.target 9" >> "$CMD_FILE" + echo "config sync.9.path http://localhost:22300" >> "$CMD_FILE" + echo "config sync.9.username $USER_EMAIL" >> "$CMD_FILE" + echo "config sync.9.password 123456" >> "$CMD_FILE" + + if [ "$1" == "1" ]; then + curl --data '{"action": "createTestUsers"}' http://localhost:22300/api/debug + + echo 'mkbook "shared"' >> "$CMD_FILE" + echo 'mkbook "other"' >> "$CMD_FILE" + echo 'use "shared"' >> "$CMD_FILE" + echo 'mknote "note 1"' >> "$CMD_FILE" + echo 'mknote "note 2"' >> "$CMD_FILE" + fi + + cd "$ROOT_DIR/packages/app-cli" + npm start -- --profile "$PROFILE_DIR" batch "$CMD_FILE" fi -cd "$ROOT_DIR/packages/app-cli" -npm start -- --profile "$PROFILE_DIR" batch "$CMD_FILE" - cd "$ROOT_DIR/packages/app-desktop" npm start -- --profile "$PROFILE_DIR" diff --git a/packages/lib/file-api-driver-joplinServer.ts b/packages/lib/file-api-driver-joplinServer.ts index bb5d3bfeb3..96c94d4839 100644 --- a/packages/lib/file-api-driver-joplinServer.ts +++ b/packages/lib/file-api-driver-joplinServer.ts @@ -1,3 +1,4 @@ +import JoplinError from './JoplinError'; import JoplinServerApi from './JoplinServerApi'; import { trimSlashes } from './path-utils'; @@ -148,9 +149,17 @@ export default class FileApiDriverJoplinServer { } public async put(path: string, content: any, options: any = null) { - return this.api().exec('PUT', `${this.apiFilePath_(path)}/content`, options && options.shareId ? { share_id: options.shareId } : null, content, { - 'Content-Type': 'application/octet-stream', - }, options); + try { + const output = await this.api().exec('PUT', `${this.apiFilePath_(path)}/content`, options && options.shareId ? { share_id: options.shareId } : null, content, { + 'Content-Type': 'application/octet-stream', + }, options); + return output; + } catch (error) { + if (error.code === 413) { + throw new JoplinError(error.message, 'rejectedByTarget'); + } + throw error; + } } public async delete(path: string) { diff --git a/packages/server/src/models/ItemModel.ts b/packages/server/src/models/ItemModel.ts index d73de7e117..84e050a861 100644 --- a/packages/server/src/models/ItemModel.ts +++ b/packages/server/src/models/ItemModel.ts @@ -6,7 +6,9 @@ import { ModelType } from '@joplin/lib/BaseModel'; import { ApiError, ErrorForbidden, ErrorNotFound, ErrorPayloadTooLarge, ErrorUnprocessableEntity } from '../utils/errors'; import { Knex } from 'knex'; import { ChangePreviousItem } from './ChangeModel'; +import { _ } from '@joplin/lib/locale'; +const prettyBytes = require('pretty-bytes'); const mimeUtils = require('@joplin/lib/mime-utils.js').mime; // Converts "root:/myfile.txt:" to "myfile.txt" @@ -289,6 +291,7 @@ export default class ItemModel extends BaseModel { const isJoplinItem = isJoplinItemName(name); let isNote = false; + let itemTitle = ''; const item: Item = { name, @@ -313,6 +316,8 @@ export default class ItemModel extends BaseModel { delete joplinItem.type_; delete joplinItem.encryption_applied; + itemTitle = joplinItem.title || ''; + item.content = Buffer.from(JSON.stringify(joplinItem)); } else { item.content = buffer; @@ -326,7 +331,13 @@ export default class ItemModel extends BaseModel { // items can be much larger (seems to be up to twice the size but for // safety let's go with 2.2). const maxSize = user.item_max_size * (item.jop_encryption_applied ? 2.2 : 1); - if (maxSize && buffer.byteLength > maxSize) throw new ErrorPayloadTooLarge(); + if (maxSize && buffer.byteLength > maxSize) { + throw new ErrorPayloadTooLarge(_('Cannot save %s "%s" because it is larger than than the allowed limit (%s)', + isNote ? _('note') : _('attachment'), + itemTitle ? itemTitle : name, + prettyBytes(user.item_max_size) + )); + } return this.withTransaction(async () => { const savedItem = await this.saveForUser(user.id, item);