mirror of
https://github.com/ONLYOFFICE/server.git
synced 2026-04-07 14:04:35 +08:00
Merge branch 'release/v9.1.0' into feature/admin-panel2
This commit is contained in:
@ -433,8 +433,7 @@
|
||||
},
|
||||
"mysqlExtraOptions": {
|
||||
"connectTimeout": 60000,
|
||||
"queryTimeout": 60000,
|
||||
"autoCommit": false
|
||||
"queryTimeout": 60000
|
||||
}
|
||||
},
|
||||
"redis": {
|
||||
|
||||
@ -70,6 +70,36 @@
|
||||
"description": "HTTP error code to return when IP is not allowed"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sql": {
|
||||
"type": "object",
|
||||
"description": "Database connection settings for the CoAuthoring service",
|
||||
"additionalProperties": false,
|
||||
"x-scope": "admin",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Database type (e.g., 'mysql', 'mariadb', 'mssql', 'postgres', 'dameng', 'oracle')",
|
||||
"examples": ["postgres"]
|
||||
},
|
||||
"dbHost": {
|
||||
"type": "string",
|
||||
"description": "Database host name or IP address",
|
||||
"examples": ["localhost"]
|
||||
},
|
||||
"dbPort": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 65535,
|
||||
"description": "Database TCP port",
|
||||
"examples": [5432]
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string",
|
||||
"description": "Database name",
|
||||
"examples": ["onlyoffice"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +76,13 @@ Context.prototype.initFromConnection = function (conn) {
|
||||
const userSessionId = utils.getSessionIdByConnection(this, conn);
|
||||
this.init(tenant, docId || this.docId, userId || this.userId, shardKey, wopiSrc, userSessionId);
|
||||
};
|
||||
Context.prototype.initFromConnectionRequest = function (req) {
|
||||
this.initFromRequest(req);
|
||||
const docIdParsed = constants.DOC_ID_SOCKET_PATTERN.exec(req.url);
|
||||
if (docIdParsed && 1 < docIdParsed.length) {
|
||||
this.setDocId(docIdParsed[1]);
|
||||
}
|
||||
};
|
||||
Context.prototype.initFromRequest = function (req) {
|
||||
const tenant = tenantManager.getTenantByRequest(this, req);
|
||||
const shardKey = utils.getShardKeyByRequest(this, req);
|
||||
|
||||
@ -924,6 +924,25 @@ exports.getSessionIdByConnection = getSessionIdByConnection;
|
||||
exports.getShardKeyByRequest = getShardKeyByRequest;
|
||||
exports.getWopiSrcByRequest = getWopiSrcByRequest;
|
||||
exports.getSessionIdByRequest = getSessionIdByRequest;
|
||||
|
||||
/**
|
||||
* Adapt a raw Node/engine.io IncomingMessage to behave like an Express Request.
|
||||
* @param {http.IncomingMessage} rawReq
|
||||
* @param {Express} app
|
||||
*/
|
||||
exports.expressifyIncomingMessage = function (rawReq, app) {
|
||||
if (!rawReq || !app?.request || rawReq.app) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object.setPrototypeOf(rawReq, app.request);
|
||||
rawReq.app = app;
|
||||
|
||||
// Initialize Express-like properties
|
||||
rawReq.originalUrl = rawReq.originalUrl || rawReq.url || '/';
|
||||
rawReq.query = rawReq.query || (rawReq.url ? url.parse(rawReq.url, true).query : {});
|
||||
};
|
||||
|
||||
function stream2Buffer(stream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!stream.readable) {
|
||||
|
||||
@ -1806,7 +1806,7 @@ async function encryptPasswordParams(ctx, data) {
|
||||
}
|
||||
exports.encryptPasswordParams = encryptPasswordParams;
|
||||
exports.getOpenFormatByEditor = getOpenFormatByEditor;
|
||||
exports.install = function (server, callbackFunction) {
|
||||
exports.install = function (server, app, callbackFunction) {
|
||||
const io = new Server(server, cfgSocketIoConnection);
|
||||
|
||||
io.use((socket, next) => {
|
||||
@ -2022,7 +2022,15 @@ exports.install = function (server, callbackFunction) {
|
||||
}
|
||||
});
|
||||
io.engine.on('connection_error', err => {
|
||||
operationContext.global.logger.warn('io.connection_error code=%s, message=%s', err.code, err.message);
|
||||
let logger = operationContext.global.logger;
|
||||
if (err.req) {
|
||||
const ctx = new operationContext.Context();
|
||||
// Ensure raw IncomingMessage has Express properties for consistent context init
|
||||
utils.expressifyIncomingMessage(err.req, app);
|
||||
ctx.initFromConnectionRequest(err.req);
|
||||
logger = ctx.logger;
|
||||
}
|
||||
logger.warn('io.connection_error code=%s, message=%s, url=%s', err?.code, err?.message, err?.req?.url);
|
||||
});
|
||||
/**
|
||||
*
|
||||
|
||||
@ -34,7 +34,6 @@
|
||||
|
||||
const mysql = require('mysql2/promise');
|
||||
const connectorUtilities = require('./connectorUtilities');
|
||||
const operationContext = require('../../../Common/sources/operationContext');
|
||||
const config = require('config');
|
||||
|
||||
const configSql = config.get('services.CoAuthoring.sql');
|
||||
@ -59,25 +58,9 @@ if (configuration.queryTimeout) {
|
||||
queryTimeout = configuration.queryTimeout;
|
||||
delete configuration.queryTimeout;
|
||||
}
|
||||
let autoCommit = false;
|
||||
if (configuration.autoCommit !== undefined) {
|
||||
//delete to fix issue with invalid configuration option
|
||||
autoCommit = configuration.autoCommit;
|
||||
delete configuration.autoCommit;
|
||||
}
|
||||
|
||||
const pool = mysql.createPool(configuration);
|
||||
|
||||
// Set autocommit once per connection
|
||||
if (autoCommit === true) {
|
||||
pool.on('connection', async conn => {
|
||||
conn
|
||||
.promise()
|
||||
.query('SET autocommit=1')
|
||||
.catch(err => operationContext.global.logger.error('Failed to set autocommit=1:', err.message));
|
||||
});
|
||||
}
|
||||
|
||||
function sqlQuery(ctx, sqlCommand, callbackFunction, opt_noModifyRes = false, opt_noLog = false, opt_values = []) {
|
||||
return executeQuery(ctx, sqlCommand, opt_values, opt_noModifyRes, opt_noLog).then(
|
||||
result => callbackFunction?.(null, result),
|
||||
@ -90,6 +73,12 @@ async function executeQuery(ctx, sqlCommand, values = [], noModifyRes = false, n
|
||||
try {
|
||||
connection = await pool.getConnection();
|
||||
|
||||
// Ensure session autocommit=1 once per physical connection; avoids pool 'connection' race and per-query overhead
|
||||
if (!connection.__autocommitSet) {
|
||||
await connection.query('SET autocommit=1');
|
||||
connection.__autocommitSet = true;
|
||||
}
|
||||
|
||||
const result = await connection.query({sql: sqlCommand, timeout: queryTimeout, values});
|
||||
|
||||
let output;
|
||||
|
||||
@ -87,25 +87,30 @@ const checkFileExpire = function (expireSeconds) {
|
||||
const shardKey = sqlBase.DocumentAdditional.prototype.getShardKey(expired[i].additional);
|
||||
const wopiSrc = sqlBase.DocumentAdditional.prototype.getWopiSrc(expired[i].additional);
|
||||
|
||||
if (currentTenant !== tenant) {
|
||||
ctx.init(tenant, docId, ctx.userId, shardKey, wopiSrc);
|
||||
yield ctx.initTenantCache();
|
||||
currentTenant = tenant;
|
||||
} else {
|
||||
ctx.setDocId(docId);
|
||||
ctx.setShardKey(shardKey);
|
||||
ctx.setWopiSrc(wopiSrc);
|
||||
}
|
||||
|
||||
//todo tenant
|
||||
//check that no one is in the document
|
||||
const editorsCount = yield docsCoServer.getEditorsCountPromise(ctx, docId);
|
||||
if (0 === editorsCount) {
|
||||
if (yield canvasService.cleanupCache(ctx, docId)) {
|
||||
currentRemovedCount++;
|
||||
try {
|
||||
if (currentTenant !== tenant) {
|
||||
ctx.init(tenant, docId, ctx.userId, shardKey, wopiSrc);
|
||||
yield ctx.initTenantCache();
|
||||
currentTenant = tenant;
|
||||
} else {
|
||||
ctx.setDocId(docId);
|
||||
ctx.setShardKey(shardKey);
|
||||
ctx.setWopiSrc(wopiSrc);
|
||||
}
|
||||
} else {
|
||||
ctx.logger.debug('checkFileExpire expire but presence: editorsCount = %d', editorsCount);
|
||||
|
||||
//todo tenant
|
||||
//check that no one is in the document
|
||||
const editorsCount = yield docsCoServer.getEditorsCountPromise(ctx, docId);
|
||||
if (0 === editorsCount) {
|
||||
if (yield canvasService.cleanupCache(ctx, docId)) {
|
||||
currentRemovedCount++;
|
||||
}
|
||||
} else {
|
||||
ctx.logger.debug('checkFileExpire expire but presence: editorsCount = %d', editorsCount);
|
||||
}
|
||||
} catch (error) {
|
||||
ctx.logger.error('checkFileExpire file error: %s', error.stack);
|
||||
// Continue processing other files
|
||||
}
|
||||
}
|
||||
removedCount += currentRemovedCount;
|
||||
|
||||
@ -18,8 +18,7 @@ const cfgEditorStatStorage =
|
||||
// Initialize editor stat storage
|
||||
const editorStatStorage = require(`../${cfgEditorStatStorage}`);
|
||||
const editorStat = new editorStatStorage.EditorStat();
|
||||
console.error(`../${cfgEditorStatStorage}`);
|
||||
console.error(editorStat);
|
||||
|
||||
// Constants
|
||||
const PRECISION = [
|
||||
{name: 'hour', val: ms('1h')},
|
||||
@ -242,3 +241,5 @@ function createInfoRouter() {
|
||||
}
|
||||
|
||||
module.exports = createInfoRouter;
|
||||
// Export handler for reuse
|
||||
module.exports.licenseInfo = licenseInfo;
|
||||
|
||||
@ -157,7 +157,7 @@ try {
|
||||
// If you want to use 'development' and 'production',
|
||||
// then with app.settings.env (https://github.com/strongloop/express/issues/936)
|
||||
// If error handling is needed, now it's like this https://github.com/expressjs/errorhandler
|
||||
docsCoServer.install(server, () => {
|
||||
docsCoServer.install(server, app, () => {
|
||||
operationContext.global.logger.info('Start callbackFunction');
|
||||
|
||||
server.listen(config.get('services.CoAuthoring.server.port'), () => {
|
||||
|
||||
@ -75,13 +75,12 @@ for file in filesReplace:
|
||||
|
||||
testDevelopVersion = sdkjsDirectory + "/.git"
|
||||
if not os.path.isdir(testDevelopVersion):
|
||||
print("Not in develop version, skipping x2t cache update")
|
||||
print("Update x2t cache...")
|
||||
x2tDir = curDirectory + "/../FileConverter/bin"
|
||||
cur_dir = os.getcwd()
|
||||
os.chdir(x2tDir)
|
||||
x2tBin = curDirectory + "/../FileConverter/bin/x2t"
|
||||
if ("windows" == platform.system().lower()):
|
||||
subprocess.call(["x2t.exe", "-create-js-cache"], stderr=subprocess.STDOUT, shell=True)
|
||||
else:
|
||||
subprocess.call("x2t -create-js-cache", stderr=subprocess.STDOUT, shell=True)
|
||||
subprocess.call("./x2t -create-js-cache", stderr=subprocess.STDOUT, shell=True)
|
||||
os.chdir(cur_dir)
|
||||
|
||||
6660
npm-shrinkwrap.json
generated
6660
npm-shrinkwrap.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,9 +19,9 @@
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"express": "4.21.2",
|
||||
"globals": "15.12.0",
|
||||
"husky": "^9.1.7",
|
||||
"husky": "8.0.3",
|
||||
"jest": "29.7.0",
|
||||
"lint-staged": "^16.1.5",
|
||||
"lint-staged": "15.2.10",
|
||||
"prettier": "3.4.2"
|
||||
},
|
||||
"scripts": {
|
||||
@ -31,7 +31,6 @@
|
||||
"format:check": "prettier . --check",
|
||||
"code:check": "run-s lint:check format:check",
|
||||
"code:fix": "run-s lint:fix format:fix",
|
||||
"prepare": "husky",
|
||||
"perf-expired": "cd ./DocService&& cross-env NODE_ENV=development-windows NODE_CONFIG_DIR=../Common/config node ../tests/perf/checkFileExpire.js",
|
||||
"perf-exif": "cd ./DocService&& cross-env NODE_ENV=development-windows NODE_CONFIG_DIR=../Common/config node ../tests/perf/fixImageExifRotation.js",
|
||||
"perf-png": "cd ./DocService&& cross-env NODE_ENV=development-windows NODE_CONFIG_DIR=../Common/config node ../tests/perf/convertImageToPng.js",
|
||||
@ -46,7 +45,7 @@
|
||||
"install:FileConverter": "npm ci --prefix ./FileConverter",
|
||||
"install:Metrics": "npm ci --prefix ./Metrics",
|
||||
"install:AdminPanel/server": "npm ci --prefix ./AdminPanel/server",
|
||||
"install:AdminPanel/client": "npm ci --prefix ./AdminPanel/client && npm --prefix ./AdminPanel/client run build",
|
||||
"install:AdminPanel/client": "npm ci --include=dev --prefix ./AdminPanel/client && npm --prefix ./AdminPanel/client run build",
|
||||
"3d-party-lic-json:Common": "license-report --output=json --package=./Common/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json",
|
||||
"3d-party-lic-json:DocService": "license-report --output=json --package=./DocService/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json",
|
||||
"3d-party-lic-json:FileConverter": "license-report --output=json --package=./FileConverter/package.json --config ./3d-party-lic-report/license-report-config.json > ./3d-party-lic-report/license-report.json",
|
||||
|
||||
46
tests/fixtures/README.md
vendored
Normal file
46
tests/fixtures/README.md
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# info.json Fixtures for Rendering Tests
|
||||
|
||||
This directory contains sample `info.json` payloads that exercise different rendering paths in:
|
||||
|
||||
- Static page: `branding/info/index.html`
|
||||
- React AdminPanel: `AdminPanel/client/src/components/Statistics/`
|
||||
|
||||
Each file is self-contained and adheres to the server `info.json` schema used by the UI.
|
||||
|
||||
## Automatic Fixture Cycling
|
||||
|
||||
To enable automatic cycling through fixtures on each request, add this code to your `licenseInfo` function:
|
||||
|
||||
```javascript
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Request counter for cycling through fixtures (persistent across calls)
|
||||
licenseInfo.requestCounter = (licenseInfo.requestCounter || 0) + 1;
|
||||
licenseInfo.fixtureFiles = licenseInfo.fixtureFiles || [];
|
||||
|
||||
// Load fixture files list on first call
|
||||
if (licenseInfo.fixtureFiles.length === 0) {
|
||||
try {
|
||||
const fixturesDir = path.join(__dirname, '../../../tests/fixtures/info');
|
||||
const files = fs.readdirSync(fixturesDir);
|
||||
licenseInfo.fixtureFiles = files.filter(file => file.endsWith('.json'));
|
||||
} catch (e) {
|
||||
// If fixtures directory doesn't exist, continue with normal flow
|
||||
}
|
||||
}
|
||||
|
||||
// Cycle through fixtures on every request
|
||||
if (licenseInfo.fixtureFiles.length > 0) {
|
||||
const fixtureIndex = (licenseInfo.requestCounter - 1) % licenseInfo.fixtureFiles.length;
|
||||
const fixturePath = path.join(__dirname, '../../../tests/fixtures/info', licenseInfo.fixtureFiles[fixtureIndex]);
|
||||
try {
|
||||
const fixtureData = JSON.parse(fs.readFileSync(fixturePath, 'utf8'));
|
||||
return res.json(fixtureData);
|
||||
} catch (e) {
|
||||
// If fixture fails to load, continue with normal flow
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Files
|
||||
42
tests/fixtures/info/connections_basic.json
vendored
Normal file
42
tests/fixtures/info/connections_basic.json
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-20T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-20T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"connections": 50,
|
||||
"connectionsView": 30,
|
||||
"usersCount": 0,
|
||||
"usersViewCount": 0
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "1234",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"connectionsCount": 20},
|
||||
"view": {"connectionsCount": 28},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {
|
||||
"hour": {
|
||||
"edit": {"max": 52, "avr": 40},
|
||||
"liveview": {"max": 29, "avr": 27}
|
||||
},
|
||||
"day": {
|
||||
"edit": {"max": 45, "avr": 30},
|
||||
"liveview": {"max": 30, "avr": 22}
|
||||
},
|
||||
"week": {
|
||||
"edit": {"max": 50, "avr": 35},
|
||||
"liveview": {"max": 31, "avr": 26}
|
||||
},
|
||||
"month": {
|
||||
"edit": {"max": 40, "avr": 28},
|
||||
"liveview": {"max": 25, "avr": 20}
|
||||
}
|
||||
}
|
||||
}
|
||||
25
tests/fixtures/info/connections_critical_remaining.json
vendored
Normal file
25
tests/fixtures/info/connections_critical_remaining.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-10T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-10T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"connections": 20,
|
||||
"connectionsView": 10,
|
||||
"usersCount": 0,
|
||||
"usersViewCount": 0
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "1236",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"connectionsCount": 19},
|
||||
"view": {"connectionsCount": 9},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
32
tests/fixtures/info/connections_missing_periods.json
vendored
Normal file
32
tests/fixtures/info/connections_missing_periods.json
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-15T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-15T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"connections": 40,
|
||||
"connectionsView": 25,
|
||||
"usersCount": 0,
|
||||
"usersViewCount": 0
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "1235",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"connectionsCount": 12},
|
||||
"view": {"connectionsCount": 9},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {
|
||||
"hour": {
|
||||
"edit": {"max": 10, "avr": 8}
|
||||
},
|
||||
"day": {
|
||||
"liveview": {"max": 20, "avr": 12}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
tests/fixtures/info/developer_edition_users.json
vendored
Normal file
35
tests/fixtures/info/developer_edition_users.json
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 2,
|
||||
"buildDate": "2025-08-18T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-18T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"usersCount": 200,
|
||||
"usersViewCount": 150,
|
||||
"usersExpire": 2592000
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2007",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 120, "anonymous": 30}},
|
||||
"view": {"usersCount": {"unique": 100, "anonymous": 20}},
|
||||
"byMonth": [
|
||||
{
|
||||
"date": "2025-06-01T00:00:00Z",
|
||||
"users": {"a": {}, "b": {}, "c": {"anonym": true}},
|
||||
"usersView": {"d": {}, "e": {"anonym": true}}
|
||||
},
|
||||
{
|
||||
"date": "2025-07-01T00:00:00Z",
|
||||
"users": {"f": {}, "g": {"anonym": true}},
|
||||
"usersView": {"h": {}, "i": {}, "j": {"anonym": true}}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
27
tests/fixtures/info/open_source_connection.json
vendored
Normal file
27
tests/fixtures/info/open_source_connection.json
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 0,
|
||||
"buildDate": "2025-08-12T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-12T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"connections": 15,
|
||||
"connectionsView": 10,
|
||||
"usersCount": 0,
|
||||
"usersViewCount": 0
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "1237",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"connectionsCount": 5},
|
||||
"view": {"connectionsCount": 3},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {
|
||||
"hour": {"edit": {"max": 12, "avr": 7}, "liveview": {"max": 9, "avr": 5}}
|
||||
}
|
||||
}
|
||||
35
tests/fixtures/info/users_basic.json
vendored
Normal file
35
tests/fixtures/info/users_basic.json
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-01T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-01T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"usersCount": 100,
|
||||
"usersViewCount": 60,
|
||||
"usersExpire": 2592000
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2001",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 55, "anonymous": 5}},
|
||||
"view": {"usersCount": {"unique": 45, "anonymous": 2}},
|
||||
"byMonth": [
|
||||
{
|
||||
"date": "2025-06-01T00:00:00Z",
|
||||
"users": {"1": {}, "2": {"anonym": true}, "3": {}},
|
||||
"usersView": {"10": {}, "11": {"anonym": true}}
|
||||
},
|
||||
{
|
||||
"date": "2025-07-01T00:00:00Z",
|
||||
"users": {"4": {}, "5": {}, "6": {"anonym": true}},
|
||||
"usersView": {"12": {}, "13": {"anonym": true}, "14": {"anonym": true}}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
24
tests/fixtures/info/users_critical_remaining.json
vendored
Normal file
24
tests/fixtures/info/users_critical_remaining.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-05T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2026-08-05T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"usersCount": 10,
|
||||
"usersViewCount": 5,
|
||||
"usersExpire": 604800
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2002",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 10, "anonymous": 2}},
|
||||
"view": {"usersCount": {"unique": 5, "anonymous": 1}},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
24
tests/fixtures/info/users_license_invalid_type.json
vendored
Normal file
24
tests/fixtures/info/users_license_invalid_type.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-01T00:00:00Z",
|
||||
"mode": 4,
|
||||
"endDate": "2025-12-01T00:00:00Z",
|
||||
"type": 2,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"usersCount": 100,
|
||||
"usersViewCount": 80,
|
||||
"usersExpire": 2592000
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2005",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 50, "anonymous": 10}},
|
||||
"view": {"usersCount": {"unique": 40, "anonymous": 5}},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
24
tests/fixtures/info/users_no_license.json
vendored
Normal file
24
tests/fixtures/info/users_no_license.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-08-01T00:00:00Z",
|
||||
"mode": 0,
|
||||
"endDate": null,
|
||||
"type": 0,
|
||||
"startDate": "2025-08-01T00:00:00Z",
|
||||
"usersCount": 50,
|
||||
"usersViewCount": 40,
|
||||
"usersExpire": 1209600
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2003",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 5, "anonymous": 1}},
|
||||
"view": {"usersCount": {"unique": 2, "anonymous": 0}},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
24
tests/fixtures/info/users_trial_limited_start_critical.json
vendored
Normal file
24
tests/fixtures/info/users_trial_limited_start_critical.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-09-01T00:00:00Z",
|
||||
"mode": 5,
|
||||
"endDate": "2026-09-01T00:00:00Z",
|
||||
"type": 16,
|
||||
"startDate": "2025-09-10T00:00:00Z",
|
||||
"usersCount": 100,
|
||||
"usersViewCount": 100,
|
||||
"usersExpire": 2592000
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2004",
|
||||
"date": "2025-09-05T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 1, "anonymous": 0}},
|
||||
"view": {"usersCount": {"unique": 1, "anonymous": 0}},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
24
tests/fixtures/info/users_updates_unavailable.json
vendored
Normal file
24
tests/fixtures/info/users_updates_unavailable.json
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"licenseInfo": {
|
||||
"packageType": 1,
|
||||
"buildDate": "2025-07-01T00:00:00Z",
|
||||
"mode": 0,
|
||||
"endDate": "2025-09-01T00:00:00Z",
|
||||
"type": 0,
|
||||
"startDate": "2025-07-01T00:00:00Z",
|
||||
"usersCount": 100,
|
||||
"usersViewCount": 80,
|
||||
"usersExpire": 2592000
|
||||
},
|
||||
"serverInfo": {
|
||||
"buildVersion": "8.2",
|
||||
"buildNumber": "2006",
|
||||
"date": "2025-09-10T12:00:00Z"
|
||||
},
|
||||
"quota": {
|
||||
"edit": {"usersCount": {"unique": 50, "anonymous": 5}},
|
||||
"view": {"usersCount": {"unique": 40, "anonymous": 4}},
|
||||
"byMonth": []
|
||||
},
|
||||
"connectionsStat": {}
|
||||
}
|
||||
Reference in New Issue
Block a user