[feature] License expiration notification changed

This commit is contained in:
Georgii Petrov
2024-05-29 20:01:04 +03:00
parent ab28ff6009
commit 2ab453d0eb
10 changed files with 38 additions and 149 deletions

View File

@ -37,13 +37,13 @@
"notification": { "notification": {
"enable": false, "enable": false,
"rules": { "rules": {
"licenseExpired": { "licenseExpirationWarning": {
"transportType": [ "transportType": [
"email" "email"
], ],
"template": { "template": {
"title": "License", "title": "License expiration",
"body": "%s license expires in %s!!!" "body": "%s license %s on %s!!!"
}, },
"policies": { "policies": {
"repeatInterval": "1d" "repeatInterval": "1d"
@ -426,7 +426,7 @@
"license_file": "", "license_file": "",
"warning_limit_percents": 70, "warning_limit_percents": 70,
"packageType": 0, "packageType": 0,
"startNotifyFrom": "30d" "warning_license_expiration": "30d"
}, },
"FileConverter": { "FileConverter": {
"converter": { "converter": {

View File

@ -1,3 +0,0 @@
{
}

View File

@ -1986,11 +1986,6 @@
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
} }
}, },
"uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA=="
},
"verror": { "verror": {
"version": "1.10.0", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",

View File

@ -18,14 +18,13 @@
"log4js": "6.4.1", "log4js": "6.4.1",
"mime": "2.3.1", "mime": "2.3.1",
"ms": "2.1.1", "ms": "2.1.1",
"nodemailer": "6.9.13",
"node-cache": "4.2.1", "node-cache": "4.2.1",
"node-statsd": "0.1.1", "node-statsd": "0.1.1",
"nodemailer": "6.9.13",
"request": "2.88.0", "request": "2.88.0",
"request-filtering-agent": "1.0.5", "request-filtering-agent": "1.0.5",
"rhea": "1.0.24", "rhea": "1.0.24",
"uri-js": "4.2.2", "uri-js": "4.2.2",
"uuid": "9.0.1",
"win-ca": "3.5.0" "win-ca": "3.5.0"
} }
} }

View File

@ -59,7 +59,7 @@ exports.readLicense = async function () {
plugins: false, plugins: false,
buildDate: oBuildDate, buildDate: oBuildDate,
startDate: startDate, startDate: startDate,
endDate: '2024-06-29T04:13:00.000Z', endDate: null,
customerId: "", customerId: "",
alias: "" alias: ""
}, null]; }, null];

View File

@ -41,11 +41,11 @@ const cfgMailServer = config.get('email.smtpServerConfiguration');
const cfgMailMessageDefaults = config.get('email.contactDefaults'); const cfgMailMessageDefaults = config.get('email.contactDefaults');
const cfgNotificationEnable = config.get('notification.enable'); const cfgNotificationEnable = config.get('notification.enable');
const defaultRepeatInterval = 1000 * 60 * 60 * 24; const infiniteRepeatInterval = Infinity;
const repeatIntervalsExpired = new Map(); const repeatIntervalsExpired = new Map();
const notificationTypes = { const notificationTypes = {
LICENSE_EXPIRED: "licenseExpired", LICENSE_EXPIRATION_WARNING: 'licenseExpirationWarning',
LICENSE_LIMIT: "licenseLimit" LICENSE_LIMIT: 'licenseLimit'
}; };
class TransportInterface { class TransportInterface {
@ -118,7 +118,7 @@ async function notify(ctx, notificationType, messageParams) {
function checkRulePolicies(ctx, notificationType, tenRule) { function checkRulePolicies(ctx, notificationType, tenRule) {
const { repeatInterval } = tenRule.policies; const { repeatInterval } = tenRule.policies;
const intervalMilliseconds = ms(repeatInterval) ?? defaultRepeatInterval; const intervalMilliseconds = repeatInterval ? ms(repeatInterval) : infiniteRepeatInterval;
const cacheKey = `${notificationType}_${ctx.tenant}`; const cacheKey = `${notificationType}_${ctx.tenant}`;
const expired = repeatIntervalsExpired.get(cacheKey); const expired = repeatIntervalsExpired.get(cacheKey);
@ -127,7 +127,7 @@ function checkRulePolicies(ctx, notificationType, tenRule) {
return true; return true;
} }
ctx.logger.debug(`Notification service: skip rule "%s" due to repeat interval %s`, notificationType, repeatInterval); ctx.logger.debug(`Notification service: skip rule "%s" due to repeat interval = %s`, notificationType, repeatInterval ?? "infinite");
return false; return false;
} }

View File

@ -108,7 +108,6 @@ const cfgEditorDataStorage = config.get('services.CoAuthoring.server.editorDataS
const cfgEditorStatStorage = config.get('services.CoAuthoring.server.editorStatStorage'); const cfgEditorStatStorage = config.get('services.CoAuthoring.server.editorStatStorage');
const editorDataStorage = require('./' + cfgEditorDataStorage); const editorDataStorage = require('./' + cfgEditorDataStorage);
const editorStatStorage = require('./' + (cfgEditorStatStorage || cfgEditorDataStorage)); const editorStatStorage = require('./' + (cfgEditorStatStorage || cfgEditorDataStorage));
const utilsDocService = require("./utilsDocService");
const cfgEditSingleton = config.get('services.CoAuthoring.server.edit_singleton'); const cfgEditSingleton = config.get('services.CoAuthoring.server.edit_singleton');
const cfgEditor = config.get('services.CoAuthoring.editor'); const cfgEditor = config.get('services.CoAuthoring.editor');

View File

@ -38,11 +38,10 @@ const Jimp = require('jimp');
const locale = require('windows-locale'); const locale = require('windows-locale');
const ms = require('ms'); const ms = require('ms');
const utils = require('../../Common/sources/utils');
const tenantManager = require('../../Common/sources/tenantManager'); const tenantManager = require('../../Common/sources/tenantManager');
const { notificationTypes, ...notificationService } = require('../../Common/sources/notificationService'); const { notificationTypes, ...notificationService } = require('../../Common/sources/notificationService');
const cfgStartNotifyFrom = ms(config.get('license.startNotifyFrom')); const cfgStartNotifyFrom = ms(config.get('license.warning_license_expiration'));
async function fixImageExifRotation(ctx, buffer) { async function fixImageExifRotation(ctx, buffer) {
if (!buffer) { if (!buffer) {
@ -78,66 +77,29 @@ function localeToLCID(lang) {
return elem && elem.id; return elem && elem.id;
} }
function humanFriendlyExpirationTime(ctx, endTime) { function humanFriendlyExpirationTime(endTime) {
const timeWithPostfix = (timeName, value) => `${value} ${timeName}${value > 1 ? 's' : ''}`; const month = [
const currentTime = new Date(); 'January',
const oneMinute = 1000 * 60; 'February',
const oneHour = oneMinute * 60; 'March',
const oneDay = oneHour * 24; 'April',
const absoluteDiff = endTime.getTime() - currentTime.getTime(); 'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
currentTime.setUTCSeconds(0,0); return `${month[endTime.getUTCMonth()]} ${endTime.getUTCDate()}, ${endTime.getUTCFullYear()}`
if (endTime.getTime() < currentTime.getTime()) {
ctx.logger.warn(`humanFriendlyExpirationTime(): expiration date value is lesser than current date`);
return '';
}
const floatResult = absoluteDiff / oneDay;
const daysCount = floatResult < 1 ? 0 : Math.round(floatResult);
const monthDiff = utils.getMonthDiff(currentTime, endTime);
if (monthDiff >= 1 && daysCount >= currentTime.getDaysInMonth()) {
return timeWithPostfix('month', monthDiff);
}
if (daysCount > 0) {
return timeWithPostfix('day', daysCount);
}
// This time we cannot just round division operation to the nearest digit because we need minutes value and more accuracy.
let hoursCount = 0
for (; hoursCount * oneHour <= absoluteDiff; hoursCount++) {}
if (hoursCount * oneHour > absoluteDiff) {
hoursCount--;
}
let minutesCount = Math.round((absoluteDiff - hoursCount * oneHour) / oneMinute);
if(minutesCount >= 60) {
hoursCount++;
minutesCount -= 60;
}
let timeString = '';
if (hoursCount > 0) {
timeString += timeWithPostfix('hour', hoursCount);
}
if (minutesCount > 0) {
if (timeString.length !== 0) {
timeString += ' ';
}
timeString += timeWithPostfix('minute', minutesCount);
}
return timeString;
} }
/** /**
* Notify server user about license expiration via configured notification transports. * Notify server user about license expiration via configured notification transports.
* @param {string} ctx Context. * @param {string} ctx Context.
* @param {date} endDate Date of expiration. * @param {Date} endDate Date of expiration.
* @returns {undefined} * @returns {undefined}
*/ */
function notifyLicenseExpiration(ctx, endDate) { function notifyLicenseExpiration(ctx, endDate) {
@ -147,27 +109,16 @@ function notifyLicenseExpiration(ctx, endDate) {
} }
const currentDate = new Date(); const currentDate = new Date();
const licenseEndTime = new Date(endDate); if (currentDate.getTime() >= endDate.getTime() - cfgStartNotifyFrom) {
const formattedExpirationTime = humanFriendlyExpirationTime(endDate);
const tenant = tenantManager.isDefaultTenant(ctx) ? 'server' : ctx.tenant;
if (licenseEndTime < currentDate) { const state = endDate < currentDate ? 'expired' : 'expires';
ctx.logger.warn(`notifyLicenseExpiration(): expiration date(${licenseEndTime}) is lesser than current date(${currentDate})`); ctx.logger.warn('%s license %s on %s!!!', tenant, state, formattedExpirationTime);
return; notificationService.notify(ctx, notificationTypes.LICENSE_EXPIRATION_WARNING, [tenant, state, formattedExpirationTime]);
}
if (currentDate.getTime() >= licenseEndTime.getTime() - cfgStartNotifyFrom) {
const formattedTimeRemaining = humanFriendlyExpirationTime(ctx, licenseEndTime);
let tenant = tenantManager.isDefaultTenant(ctx) ? 'server' : ctx.tenant;
ctx.logger.warn('%s license expires in %s!!!', tenant, formattedTimeRemaining);
notificationService.notify(ctx, notificationTypes.LICENSE_EXPIRED, [formattedTimeRemaining]);
} }
} }
module.exports = { module.exports.fixImageExifRotation = fixImageExifRotation;
fixImageExifRotation, module.exports.localeToLCID = localeToLCID;
localeToLCID, module.exports.notifyLicenseExpiration = notifyLicenseExpiration;
notifyLicenseExpiration
};
if (process.env.NODE_APP_INSTANCE === 'tests') {
module.exports.humanFriendlyExpirationTime = humanFriendlyExpirationTime;
}

View File

@ -39,7 +39,6 @@ const platform = platforms[process.platform];
process.env.NODE_ENV = `development-${platform}`; process.env.NODE_ENV = `development-${platform}`;
process.env.NODE_CONFIG_DIR = '../Common/config'; process.env.NODE_CONFIG_DIR = '../Common/config';
process.env.NODE_APP_INSTANCE = 'tests';
if (platform === 'mac') { if (platform === 'mac') {
process.env.DYLD_LIBRARY_PATH = '../FileConverter/bin/'; process.env.DYLD_LIBRARY_PATH = '../FileConverter/bin/';

View File

@ -1,51 +0,0 @@
const { describe, test, expect } = require('@jest/globals');
const utilsDocService = require('../../DocService/sources/utilsDocService');
const operationContext = require('../../Common/sources/operationContext');
const ctx = new operationContext.Context();
function createEndTime(day, month, year, hours, minutes) {
const date = new Date();
date.setUTCFullYear(year);
date.setUTCMonth(month);
date.setUTCDate(day);
date.setUTCHours(hours, minutes, 0,0);
return date;
}
describe('DocService utils', function () {
describe('humanFriendlyExpirationTime() format', function () {
const currentDate = new Date();
currentDate.setUTCSeconds(0, 0);
const day = currentDate.getUTCDate();
const month = currentDate.getUTCMonth();
const year = currentDate.getUTCFullYear();
const hours = currentDate.getUTCHours();
const minutes = currentDate.getUTCMinutes();
const testSuite = {
'12 months': createEndTime(day, month, year + 1, hours, minutes),
'15 months': createEndTime(day, month + 3, year + 1, hours, minutes),
'6 months': createEndTime(day, month + 6, year, hours, minutes),
'1 month': createEndTime(day, month + 1, year, hours, minutes),
'10 days': createEndTime(day + 10, month, year, hours, minutes),
'2 days': createEndTime(day + 2, month, year, hours, minutes),
// '24 hours': createEndTime(day + 1, month, year, hours, minutes),
// '23 hours': createEndTime(day, month, year, hours + 23, minutes),
// '16 minutes': createEndTime(day, month, year, hours, minutes + 16),
// '1 hour 15 minutes': createEndTime(day, month, year, hours + 1, minutes + 15),
'': createEndTime(day, month, year - 1, hours, minutes),
};
for (const testCase in testSuite) {
test(testCase === '' ? 'wrong end date' : testCase, function () {
const result = utilsDocService.humanFriendlyExpirationTime(ctx, testSuite[testCase]);
expect(result).toEqual(testCase);
});
}
});
});