From c8a0c4c5d356764a5f4d8c34d55984f62c71be0f Mon Sep 17 00:00:00 2001 From: Sergey Konovalov Date: Thu, 31 Mar 2022 18:50:06 +0300 Subject: [PATCH] [bug] For bug 46818 --- DocService/sources/DocsCoServer.js | 21 ++++++++++- DocService/sources/baseConnector.js | 46 ++++++++++++++++++++++- DocService/sources/canvasservice.js | 36 ++++++++++++++++-- DocService/sources/taskresult.js | 5 +++ schema/mysql/createdb.sql | 1 + schema/mysql/upgrade/upgradev710.sql | 19 ++++++++++ schema/postgresql/createdb.sql | 1 + schema/postgresql/upgrade/upgradev710.sql | 9 +++++ 8 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 schema/mysql/upgrade/upgradev710.sql create mode 100644 schema/postgresql/upgrade/upgradev710.sql diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js index 6bb3f43a..e1cacefa 100644 --- a/DocService/sources/DocsCoServer.js +++ b/DocService/sources/DocsCoServer.js @@ -2145,7 +2145,23 @@ exports.install = function(server, callbackFunction) { } let format = data.openCmd && data.openCmd.format; upsertRes = yield canvasService.commandOpenStartPromise(docId, utils.getBaseUrlByConnection(conn), true, data.documentCallbackUrl, format); - curIndexUser = upsertRes.affectedRows == 1 ? 1 : upsertRes.insertId; + let isInserted = upsertRes.affectedRows == 1; + curIndexUser = isInserted ? 1 : upsertRes.insertId; + if (isInserted && undefined !== data.timezoneOffset) { + //todo insert in commandOpenStartPromise. insert here for database compatibility + if (false === canvasService.hasAdditionalCol) { + let selectRes = yield taskResult.select(docId); + canvasService.hasAdditionalCol = selectRes.length > 0 && undefined !== selectRes[0].additional; + } + if (canvasService.hasAdditionalCol) { + let task = new taskResult.TaskResultData(); + task.key = docId; + task.additional = sqlBase.DocumentAdditional.prototype.setTimezoneOffset(data.timezoneOffset); + yield taskResult.update(task); + } else { + logger.warn('auth unknown column "additional": docId = %s', docId); + } + } } if (constants.CONN_CLOSED === conn.readyState) { //closing could happen during async action @@ -3098,6 +3114,9 @@ exports.install = function(server, callbackFunction) { } outputData.setData(url); } + if (undefined !== data.openedAt) { + outputData.setOpenedAt(data.openedAt); + } modifyConnectionForPassword(participant, data.needUrlIsCorrectPassword); } sendData(participant, output); diff --git a/DocService/sources/baseConnector.js b/DocService/sources/baseConnector.js index 3a22bff8..1ebd216a 100644 --- a/DocService/sources/baseConnector.js +++ b/DocService/sources/baseConnector.js @@ -41,6 +41,7 @@ var sqlDataBaseType = { var config = require('config').get('services.CoAuthoring.sql'); var baseConnector = (sqlDataBaseType.mySql === config.get('type') || sqlDataBaseType.mariaDB === config.get('type')) ? require('./mySqlBaseConnector') : require('./postgreSqlBaseConnector'); var logger = require('./../../Common/sources/logger'); +let constants = require('./../../Common/sources/constants'); const tableChanges = config.get('tableChanges'), tableResult = config.get('tableResult'); @@ -286,7 +287,7 @@ UserCallback.prototype.fromValues = function(userIndex, callback){ this.callback = callback; } }; -UserCallback.prototype.delimiter = String.fromCharCode(5); +UserCallback.prototype.delimiter = constants.CHAR_DELIMITER; UserCallback.prototype.toSQLInsert = function(){ return this.delimiter + JSON.stringify(this); }; @@ -351,7 +352,7 @@ DocumentPassword.prototype.fromValues = function(password, change){ this.change = change; } }; -DocumentPassword.prototype.delimiter = String.fromCharCode(5); +DocumentPassword.prototype.delimiter = constants.CHAR_DELIMITER; DocumentPassword.prototype.toSQLInsert = function(){ return this.delimiter + JSON.stringify(this); }; @@ -386,3 +387,44 @@ DocumentPassword.prototype.hasPasswordChanges = function(docId, docPasswordStr) return docPassword.initial !== docPassword.current; }; exports.DocumentPassword = DocumentPassword; + +function DocumentAdditional() { + this.data = []; +} +DocumentAdditional.prototype.delimiter = constants.CHAR_DELIMITER; +DocumentAdditional.prototype.toSQLInsert = function() { + if (this.data.length) { + let vals = this.data.map((currentValue) => { + return JSON.stringify(currentValue); + }); + return this.delimiter + vals.join(this.delimiter); + } else { + return null; + } +}; +DocumentAdditional.prototype.fromString = function(str) { + if (!str) { + return; + } + let vals = str.split(this.delimiter).slice(1); + this.data = vals.map((currentValue) => { + return JSON.parse(currentValue); + }); +}; +DocumentAdditional.prototype.setTimezoneOffset = function(val) { + let additional = new DocumentAdditional(); + additional.data.push({timezoneOffset: val}); + return additional.toSQLInsert(); +}; +DocumentAdditional.prototype.getTimezoneOffset = function(str) { + let res; + let val = new DocumentAdditional(); + val.fromString(str); + val.data.forEach((elem) => { + if (undefined !== elem.timezoneOffset) { + res = elem.timezoneOffset; + } + }); + return res; +}; +exports.DocumentAdditional = DocumentAdditional; diff --git a/DocService/sources/canvasservice.js b/DocService/sources/canvasservice.js index 6b0ace34..561997fe 100644 --- a/DocService/sources/canvasservice.js +++ b/DocService/sources/canvasservice.js @@ -81,6 +81,7 @@ var SAVE_TYPE_COMPLETE_ALL = 3; var clientStatsD = statsDClient.getClient(); var redisKeyShutdown = cfgRedisPrefix + constants.REDIS_KEY_SHUTDOWN; let hasPasswordCol = false;//stub on upgradev630.sql update failure +exports.hasAdditionalCol = false;//stub on upgradev710.sql update failure const retryHttpStatus = new MultiRange(cfgCallbackBackoffOptions.httpStatus); @@ -112,6 +113,7 @@ function OutputData(type) { this['status'] = undefined; this['data'] = undefined; this['filetype'] = undefined; + this['openedAt'] = undefined; } OutputData.prototype = { fromObject: function(data) { @@ -119,6 +121,7 @@ OutputData.prototype = { this['status'] = data['status']; this['data'] = data['data']; this['filetype'] = data['filetype']; + this['openedAt'] = data['openedAt']; }, getType: function() { return this['type']; @@ -143,11 +146,32 @@ OutputData.prototype = { }, setExtName: function(data) { this['filetype'] = data.substring(1); + }, + getOpenedAt: function() { + return this['openedAt']; + }, + setOpenedAt: function(data) { + this['openedAt'] = data; } }; +function getOpenedAt(row) { + let timezoneOffset = sqlBase.DocumentAdditional.prototype.getTimezoneOffset(row.additional); + if (row.created_at && undefined !== timezoneOffset) { + return row.created_at.getTime() + timezoneOffset * 60 * 1000; + } + return undefined; +} +function getOpenedAtJSONParams(row) { + let openedAt = getOpenedAt(row); + if (openedAt) { + return {openedAt: openedAt}; + } + return undefined; +} + var getOutputData = co.wrap(function* (cmd, outputData, key, optConn, optAdditionalOutput, opt_bIsRestore) { - let status, statusInfo, password, creationDate, row; + let status, statusInfo, password, creationDate, openedAt, row; let selectRes = yield taskResult.select(key); if (selectRes.length > 0) { row = selectRes[0]; @@ -155,6 +179,7 @@ var getOutputData = co.wrap(function* (cmd, outputData, key, optConn, optAdditio statusInfo = row.status_info; password = sqlBase.DocumentPassword.prototype.getCurPassword(key, row.password); creationDate = row.created_at && row.created_at.getTime(); + openedAt = getOpenedAt(row); } switch (status) { case taskResult.FileStatus.SaveVersion: @@ -226,6 +251,7 @@ var getOutputData = co.wrap(function* (cmd, outputData, key, optConn, optAdditio outputData.setData(constants.CONVERT_DRM); } } else if (optConn) { + outputData.setOpenedAt(openedAt); outputData.setData(yield storage.getSignedUrls(optConn.baseUrl, key, commonDefines.c_oAscUrlTypes.Session, creationDate)); } else if (optAdditionalOutput) { optAdditionalOutput.needUrlKey = key; @@ -233,6 +259,7 @@ var getOutputData = co.wrap(function* (cmd, outputData, key, optConn, optAdditio optAdditionalOutput.needUrlType = commonDefines.c_oAscUrlTypes.Session; optAdditionalOutput.needUrlIsCorrectPassword = isCorrectPassword; optAdditionalOutput.creationDate = creationDate; + optAdditionalOutput.openedAt = openedAt; } } break; @@ -575,6 +602,7 @@ function* commandSfctByCmd(cmd, opt_priority, opt_expiration, opt_queue) { var row = selectRes.length > 0 ? selectRes[0] : null; addPasswordToCmd(cmd, row && row.password); cmd.setOutputFormat(changeFormatByOrigin(cmd.getDocId(), row, cmd.getOutputFormat())); + cmd.setJsonParams(getOpenedAtJSONParams(row)); var queueData = getSaveTask(cmd); queueData.setFromChanges(true); let priority = null != opt_priority ? opt_priority : constants.QUEUE_PRIORITY_LOW; @@ -1545,6 +1573,7 @@ exports.saveFromChanges = function(docId, statusInfo, optFormat, opt_userId, opt cmd.setStatusInfoIn(statusInfo); cmd.setUserActionId(opt_userId); cmd.setUserActionIndex(opt_userIndex); + cmd.setJsonParams(getOpenedAtJSONParams(row)); addPasswordToCmd(cmd, row && row.password); yield* addRandomKeyTaskCmd(cmd); var queueData = getSaveTask(cmd); @@ -1582,7 +1611,7 @@ exports.receiveTask = function(data, ack) { if (updateRes.affectedRows > 0) { var outputData = new OutputData(cmd.getCommand()); var command = cmd.getCommand(); - var additionalOutput = {needUrlKey: null, needUrlMethod: null, needUrlType: null, needUrlIsCorrectPassword: undefined, creationDate: undefined}; + var additionalOutput = {needUrlKey: null, needUrlMethod: null, needUrlType: null, needUrlIsCorrectPassword: undefined, creationDate: undefined, openedAt: undefined}; if ('open' == command || 'reopen' == command) { yield getOutputData(cmd, outputData, cmd.getDocId(), null, additionalOutput); } else if ('save' == command || 'savefromorigin' == command || 'sfct' == command) { @@ -1605,7 +1634,8 @@ exports.receiveTask = function(data, ack) { needUrlMethod: additionalOutput.needUrlMethod, needUrlType: additionalOutput.needUrlType, needUrlIsCorrectPassword: additionalOutput.needUrlIsCorrectPassword, - creationDate: additionalOutput.creationDate + creationDate: additionalOutput.creationDate, + openedAt: additionalOutput.openedAt }); } } diff --git a/DocService/sources/taskresult.js b/DocService/sources/taskresult.js index a95c64f0..840f1ef5 100644 --- a/DocService/sources/taskresult.js +++ b/DocService/sources/taskresult.js @@ -66,6 +66,7 @@ function TaskResultData() { this.callback = null; this.baseurl = null; this.password = null; + this.additional = null; this.innerPasswordChange = null;//not a DB field } @@ -162,6 +163,10 @@ function toUpdateArray(task, updateTime, isMask, values, setPassword) { let sqlParam = addSqlParam(documentPassword.toSQLInsert(), values); res.push(`password=${concatParams('password', sqlParam)}`); } + if (null != task.additional) { + let sqlParam = addSqlParam(task.additional, values); + res.push(`additional=${concatParams('additional', sqlParam)}`); + } return res; } diff --git a/schema/mysql/createdb.sql b/schema/mysql/createdb.sql index e0c37cb8..e62ce1a9 100644 --- a/schema/mysql/createdb.sql +++ b/schema/mysql/createdb.sql @@ -58,6 +58,7 @@ CREATE TABLE IF NOT EXISTS `task_result` ( `callback` longtext NOT NULL, `baseurl` text NOT NULL, `password` longtext NULL, + `additional` longtext NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/schema/mysql/upgrade/upgradev710.sql b/schema/mysql/upgrade/upgradev710.sql new file mode 100644 index 00000000..fdbdf52a --- /dev/null +++ b/schema/mysql/upgrade/upgradev710.sql @@ -0,0 +1,19 @@ +DELIMITER DLM00 + +DROP PROCEDURE IF EXISTS upgrade710 DLM00 + +CREATE PROCEDURE upgrade710() +BEGIN + + IF NOT EXISTS(SELECT * FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'task_result' AND COLUMN_NAME = 'additional') THEN + ALTER TABLE `task_result` ADD COLUMN `additional` LONGTEXT NULL DEFAULT NULL AFTER `password`; + END IF; + +END DLM00 + +CALL upgrade710() DLM00 + +DELIMITER ; + + + diff --git a/schema/postgresql/createdb.sql b/schema/postgresql/createdb.sql index 0edbb56e..b07901c6 100644 --- a/schema/postgresql/createdb.sql +++ b/schema/postgresql/createdb.sql @@ -33,6 +33,7 @@ CREATE TABLE IF NOT EXISTS "public"."task_result" ( "callback" text COLLATE "default" NOT NULL, "baseurl" text COLLATE "default" NOT NULL, "password" text COLLATE "default" NULL, +"additional" text COLLATE "default" NULL, PRIMARY KEY ("id") ) WITH (OIDS=FALSE); diff --git a/schema/postgresql/upgrade/upgradev710.sql b/schema/postgresql/upgrade/upgradev710.sql new file mode 100644 index 00000000..249b4a7c --- /dev/null +++ b/schema/postgresql/upgrade/upgradev710.sql @@ -0,0 +1,9 @@ +DO $$ + BEGIN + BEGIN + ALTER TABLE "task_result" ADD COLUMN "additional" text; + EXCEPTION + WHEN duplicate_column THEN RAISE NOTICE 'column additional already exists.'; + END; + END; +$$ \ No newline at end of file