diff --git a/Common/sources/commondefines.js b/Common/sources/commondefines.js index 97e286fc..aacbe869 100644 --- a/Common/sources/commondefines.js +++ b/Common/sources/commondefines.js @@ -1044,7 +1044,8 @@ const c_oPublishType = { closeConnection: 13, changesNotify: 14, changeConnecitonInfo: 15, - rpc: 16 + rpc: 16, + dropTenantConnections: 17 }; const c_oAscCsvDelimiter = { None: 0, diff --git a/Common/sources/tenantManager.js b/Common/sources/tenantManager.js index a7c07ded..0f2b6d39 100644 --- a/Common/sources/tenantManager.js +++ b/Common/sources/tenantManager.js @@ -32,6 +32,7 @@ 'use strict'; +const { rm } = require('fs/promises'); const config = require('config'); const co = require('co'); const NodeCache = require( "node-cache" ); @@ -406,6 +407,18 @@ async function readLicenseTenant(ctx, licenseFile, baseVerifiedLicense) { return [res, oLicense]; } + +async function deleteTenant(ctx) { + try { + if (isMultitenantMode(ctx) && !isDefaultTenant(ctx)) { + let tenantPath = utils.removeIllegalCharacters(ctx.tenant); + await rm(path.join(cfgTenantsBaseDir, tenantPath), {force: true, recursive: true, maxRetries: 3}); + } + } catch (error) { + ctx.logger.error('deleteTenants error: ', error.stack); + } +} + exports.getAllTenants = getAllTenants; exports.getDefautTenant = getDefautTenant; exports.getTenantByConnection = getTenantByConnection; @@ -419,3 +432,4 @@ exports.setDefLicense = setDefLicense; exports.isMultitenantMode = isMultitenantMode; exports.setMultitenantMode = setMultitenantMode; exports.isDefaultTenant = isDefaultTenant; +exports.deleteTenant = deleteTenant; diff --git a/DocService/sources/DocsCoServer.js b/DocService/sources/DocsCoServer.js index 0891e0c3..6d144e1f 100644 --- a/DocService/sources/DocsCoServer.js +++ b/DocService/sources/DocsCoServer.js @@ -1273,6 +1273,15 @@ function dropUserFromDocument(ctx, docId, userId, description) { } } } + +function dropTenantConnections(ctx, code, description) { + for (let i = 0; i < connections.length; ++i) { + let conn = connections[i]; + if (conn.tenant === ctx.tenant && !(conn.user?.view || conn.isCloseCoAuthoring)) { + sendDataDrop(ctx, conn, code, description); + } + } +} function getLocalConnectionCount(ctx, docId) { let tenant = ctx.tenant; return connections.reduce(function(count, conn) { @@ -3568,6 +3577,9 @@ exports.install = function(server, callbackFunction) { dropUserFromDocument(ctx, data.docId, data.users[i], data.description); } break; + case commonDefines.c_oPublishType.dropTenantConnections: + dropTenantConnections(ctx, constants.DROP_CODE, constants.DROP_REASON); + break; case commonDefines.c_oPublishType.closeConnection: closeUsersConnection(ctx, data.docId, data.usersMap, data.isOriginalId, data.code, data.description); break; @@ -4194,7 +4206,7 @@ exports.licenseInfo = function(req, res) { }); }; function validateInputParams(ctx, authRes, command) { - const commandsWithoutKey = ['version', 'license', 'getForgottenList']; + const commandsWithoutKey = ['version', 'license', 'getForgottenList', 'deleteTenant']; const isValidWithoutKey = commandsWithoutKey.includes(command.c); const isDocIdString = typeof command.key === 'string'; @@ -4361,6 +4373,15 @@ function* commandHandle(ctx, params, req, output) { forgottenData.keys = yield* getFilesKeys(ctx, tenForgottenFiles); break; } + case 'deleteTenant': { + if (tenantManager.isMultitenantMode(ctx)) { + yield publish(ctx, {type: commonDefines.c_oPublishType.dropTenantConnections, ctx: ctx}); + yield tenantManager.deleteTenant(ctx); + } else { + ctx.logger.warn('commandFromServer deleteTenant works only when tenants is enabled'); + } + break; + } case 'version': { output.version = `${commonDefines.buildVersion}.${commonDefines.buildNumber}`; break;