mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-02-10 18:05:07 +08:00
[feature] License expiration notification changed
This commit is contained in:
@ -37,13 +37,13 @@
|
||||
"notification": {
|
||||
"enable": false,
|
||||
"rules": {
|
||||
"licenseExpired": {
|
||||
"licenseExpirationWarning": {
|
||||
"transportType": [
|
||||
"email"
|
||||
],
|
||||
"template": {
|
||||
"title": "License",
|
||||
"body": "%s license expires in %s!!!"
|
||||
"title": "License expiration",
|
||||
"body": "%s license %s on %s!!!"
|
||||
},
|
||||
"policies": {
|
||||
"repeatInterval": "1d"
|
||||
@ -426,7 +426,7 @@
|
||||
"license_file": "",
|
||||
"warning_limit_percents": 70,
|
||||
"packageType": 0,
|
||||
"startNotifyFrom": "30d"
|
||||
"warning_license_expiration": "30d"
|
||||
},
|
||||
"FileConverter": {
|
||||
"converter": {
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
{
|
||||
|
||||
}
|
||||
5
Common/npm-shrinkwrap.json
generated
5
Common/npm-shrinkwrap.json
generated
@ -1986,11 +1986,6 @@
|
||||
"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": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||
|
||||
@ -18,14 +18,13 @@
|
||||
"log4js": "6.4.1",
|
||||
"mime": "2.3.1",
|
||||
"ms": "2.1.1",
|
||||
"nodemailer": "6.9.13",
|
||||
"node-cache": "4.2.1",
|
||||
"node-statsd": "0.1.1",
|
||||
"nodemailer": "6.9.13",
|
||||
"request": "2.88.0",
|
||||
"request-filtering-agent": "1.0.5",
|
||||
"rhea": "1.0.24",
|
||||
"uri-js": "4.2.2",
|
||||
"uuid": "9.0.1",
|
||||
"win-ca": "3.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ exports.readLicense = async function () {
|
||||
plugins: false,
|
||||
buildDate: oBuildDate,
|
||||
startDate: startDate,
|
||||
endDate: '2024-06-29T04:13:00.000Z',
|
||||
endDate: null,
|
||||
customerId: "",
|
||||
alias: ""
|
||||
}, null];
|
||||
|
||||
@ -41,11 +41,11 @@ const cfgMailServer = config.get('email.smtpServerConfiguration');
|
||||
const cfgMailMessageDefaults = config.get('email.contactDefaults');
|
||||
const cfgNotificationEnable = config.get('notification.enable');
|
||||
|
||||
const defaultRepeatInterval = 1000 * 60 * 60 * 24;
|
||||
const infiniteRepeatInterval = Infinity;
|
||||
const repeatIntervalsExpired = new Map();
|
||||
const notificationTypes = {
|
||||
LICENSE_EXPIRED: "licenseExpired",
|
||||
LICENSE_LIMIT: "licenseLimit"
|
||||
LICENSE_EXPIRATION_WARNING: 'licenseExpirationWarning',
|
||||
LICENSE_LIMIT: 'licenseLimit'
|
||||
};
|
||||
|
||||
class TransportInterface {
|
||||
@ -118,7 +118,7 @@ async function notify(ctx, notificationType, messageParams) {
|
||||
|
||||
function checkRulePolicies(ctx, notificationType, tenRule) {
|
||||
const { repeatInterval } = tenRule.policies;
|
||||
const intervalMilliseconds = ms(repeatInterval) ?? defaultRepeatInterval;
|
||||
const intervalMilliseconds = repeatInterval ? ms(repeatInterval) : infiniteRepeatInterval;
|
||||
const cacheKey = `${notificationType}_${ctx.tenant}`;
|
||||
const expired = repeatIntervalsExpired.get(cacheKey);
|
||||
|
||||
@ -127,7 +127,7 @@ function checkRulePolicies(ctx, notificationType, tenRule) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -108,7 +108,6 @@ const cfgEditorDataStorage = config.get('services.CoAuthoring.server.editorDataS
|
||||
const cfgEditorStatStorage = config.get('services.CoAuthoring.server.editorStatStorage');
|
||||
const editorDataStorage = require('./' + cfgEditorDataStorage);
|
||||
const editorStatStorage = require('./' + (cfgEditorStatStorage || cfgEditorDataStorage));
|
||||
const utilsDocService = require("./utilsDocService");
|
||||
|
||||
const cfgEditSingleton = config.get('services.CoAuthoring.server.edit_singleton');
|
||||
const cfgEditor = config.get('services.CoAuthoring.editor');
|
||||
|
||||
@ -38,11 +38,10 @@ const Jimp = require('jimp');
|
||||
const locale = require('windows-locale');
|
||||
const ms = require('ms');
|
||||
|
||||
const utils = require('../../Common/sources/utils');
|
||||
const tenantManager = require('../../Common/sources/tenantManager');
|
||||
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) {
|
||||
if (!buffer) {
|
||||
@ -78,66 +77,29 @@ function localeToLCID(lang) {
|
||||
return elem && elem.id;
|
||||
}
|
||||
|
||||
function humanFriendlyExpirationTime(ctx, endTime) {
|
||||
const timeWithPostfix = (timeName, value) => `${value} ${timeName}${value > 1 ? 's' : ''}`;
|
||||
const currentTime = new Date();
|
||||
const oneMinute = 1000 * 60;
|
||||
const oneHour = oneMinute * 60;
|
||||
const oneDay = oneHour * 24;
|
||||
const absoluteDiff = endTime.getTime() - currentTime.getTime();
|
||||
function humanFriendlyExpirationTime(endTime) {
|
||||
const month = [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December'
|
||||
];
|
||||
|
||||
currentTime.setUTCSeconds(0,0);
|
||||
|
||||
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;
|
||||
return `${month[endTime.getUTCMonth()]} ${endTime.getUTCDate()}, ${endTime.getUTCFullYear()}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify server user about license expiration via configured notification transports.
|
||||
* @param {string} ctx Context.
|
||||
* @param {date} endDate Date of expiration.
|
||||
* @param {Date} endDate Date of expiration.
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function notifyLicenseExpiration(ctx, endDate) {
|
||||
@ -147,27 +109,16 @@ function notifyLicenseExpiration(ctx, endDate) {
|
||||
}
|
||||
|
||||
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) {
|
||||
ctx.logger.warn(`notifyLicenseExpiration(): expiration date(${licenseEndTime}) is lesser than current date(${currentDate})`);
|
||||
return;
|
||||
}
|
||||
|
||||
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]);
|
||||
const state = endDate < currentDate ? 'expired' : 'expires';
|
||||
ctx.logger.warn('%s license %s on %s!!!', tenant, state, formattedExpirationTime);
|
||||
notificationService.notify(ctx, notificationTypes.LICENSE_EXPIRATION_WARNING, [tenant, state, formattedExpirationTime]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fixImageExifRotation,
|
||||
localeToLCID,
|
||||
notifyLicenseExpiration
|
||||
};
|
||||
|
||||
if (process.env.NODE_APP_INSTANCE === 'tests') {
|
||||
module.exports.humanFriendlyExpirationTime = humanFriendlyExpirationTime;
|
||||
}
|
||||
module.exports.fixImageExifRotation = fixImageExifRotation;
|
||||
module.exports.localeToLCID = localeToLCID;
|
||||
module.exports.notifyLicenseExpiration = notifyLicenseExpiration;
|
||||
|
||||
@ -39,7 +39,6 @@ const platform = platforms[process.platform];
|
||||
|
||||
process.env.NODE_ENV = `development-${platform}`;
|
||||
process.env.NODE_CONFIG_DIR = '../Common/config';
|
||||
process.env.NODE_APP_INSTANCE = 'tests';
|
||||
|
||||
if (platform === 'mac') {
|
||||
process.env.DYLD_LIBRARY_PATH = '../FileConverter/bin/';
|
||||
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user