Skip to content

Commit

Permalink
Merge branch 'develop' into refactor/livechat-ts-2
Browse files Browse the repository at this point in the history
  • Loading branch information
KevLehman authored Oct 17, 2023
2 parents c404115 + dd5b236 commit 422ed43
Show file tree
Hide file tree
Showing 29 changed files with 176 additions and 109 deletions.
5 changes: 5 additions & 0 deletions .changeset/perfect-pianos-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/presence': minor
---

Add peak connections monitoring and methods to get and reset the counter
5 changes: 5 additions & 0 deletions .changeset/rich-dogs-smell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': minor
---

Fix typing indicator of Apps user
7 changes: 7 additions & 0 deletions .changeset/slow-coats-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": minor
---

Add the daily and monthly peaks of concurrent connections to statistics
- Added `dailyPeakConnections` statistic for monitoring the daily peak of concurrent connections in a workspace;
- Added `maxMonthlyPeakConnections` statistic for monitoring the last 30 days peak of concurrent connections in a workspace;
5 changes: 5 additions & 0 deletions .changeset/weak-cameras-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixed issue with message read receipts not being created when accessing a room the first time
6 changes: 5 additions & 1 deletion apps/meteor/app/apps/server/bridges/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ export class AppMessageBridge extends MessageBridge {
protected async typing({ scope, id, username, isTyping }: ITypingDescriptor): Promise<void> {
switch (scope) {
case 'room':
notifications.notifyRoom(id, 'typing', username!, isTyping);
if (!username) {
throw new Error('Invalid username');
}

notifications.notifyRoom(id, 'user-activity', username, isTyping ? ['user-typing'] : []);
return;
default:
throw new Error('Unrecognized typing scope provided');
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/cas/server/cas_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ Accounts.registerLoginHandler('cas', async (options) => {
if (roomName) {
let room = await Rooms.findOneByNameAndType(roomName, 'c');
if (!room) {
room = await createRoom('c', roomName, user.username);
room = await createRoom('c', roomName, user);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default async function handleJoinedChannel(args) {
let room = await Rooms.findOneByName(args.roomName);

if (!room) {
const createdRoom = await createRoom('c', args.roomName, user.username, []);
const createdRoom = await createRoom('c', args.roomName, user, []);
room = await Rooms.findOne({ _id: createdRoom.rid });

this.log(`${user.username} created room ${args.roomName}`);
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/slackbridge/server/RocketAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ export default class RocketAdapter {

try {
const isPrivate = slackChannel.is_private;
const rocketChannel = await createRoom(isPrivate ? 'p' : 'c', slackChannel.name, rocketUserCreator.username, rocketUsers);
const rocketChannel = await createRoom(isPrivate ? 'p' : 'c', slackChannel.name, rocketUserCreator, rocketUsers);
slackChannel.rocketId = rocketChannel.rid;
} catch (e) {
if (!hasRetried) {
Expand Down
7 changes: 6 additions & 1 deletion apps/meteor/app/statistics/server/lib/statistics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { log } from 'console';
import os from 'os';

import { Analytics, Team, VideoConf } from '@rocket.chat/core-services';
import { Analytics, Team, VideoConf, Presence } from '@rocket.chat/core-services';
import type { IRoom, IStats } from '@rocket.chat/core-typings';
import { UserStatus } from '@rocket.chat/core-typings';
import {
Expand Down Expand Up @@ -579,6 +579,11 @@ export const statistics = {
const defaultLoggedInCustomScript = (await Settings.findOneById('Custom_Script_Logged_In'))?.packageValue;
statistics.loggedInCustomScriptChanged = settings.get('Custom_Script_Logged_In') !== defaultLoggedInCustomScript;

statistics.dailyPeakConnections = await Presence.getPeakConnections(true);

const peak = await Statistics.findMonthlyPeakConnections();
statistics.maxMonthlyPeakConnections = Math.max(statistics.dailyPeakConnections, peak?.dailyPeakConnections || 0);

statistics.matrixFederation = await getMatrixFederationStatistics();

// Omnichannel call stats
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ export default {
totalWebRTCCalls: 0,
uncaughtExceptionsCount: 0,
push: 0,
dailyPeakConnections: 0,
maxMonthlyPeakConnections: 0,
matrixFederation: {
enabled: false,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ export default {
totalWebRTCCalls: 0,
uncaughtExceptionsCount: 0,
push: 0,
dailyPeakConnections: 0,
maxMonthlyPeakConnections: 0,
matrixFederation: {
enabled: false,
},
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/client/views/admin/info/UsageCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ export default {
totalWebRTCCalls: 0,
uncaughtExceptionsCount: 0,
push: 0,
dailyPeakConnections: 0,
maxMonthlyPeakConnections: 0,
matrixFederation: {
enabled: false,
},
Expand Down
7 changes: 5 additions & 2 deletions apps/meteor/ee/server/api/licenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ API.v1.addRoute(

API.v1.addRoute(
'licenses.info',
{ authRequired: true, validateParams: isLicensesInfoProps, permissionsRequired: ['view-privileged-setting'] },
{ authRequired: true, validateParams: isLicensesInfoProps },
{
async get() {
const data = await License.getInfo(Boolean(this.queryParams.loadValues));
const unrestrictedAccess = await hasPermissionAsync(this.userId, 'view-privileged-setting');
const loadCurrentValues = unrestrictedAccess && Boolean(this.queryParams.loadValues);

const data = await License.getInfo({ limits: unrestrictedAccess, license: unrestrictedAccess, currentValues: loadCurrentValues });

return API.v1.success({ data });
},
Expand Down
4 changes: 3 additions & 1 deletion apps/meteor/server/cron/statistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,7 @@ export async function statsCron(logger: Logger): Promise<void> {

const now = new Date();

await cronJobs.add(name, `12 ${now.getHours()} * * *`, async () => generateStatistics(logger));
await cronJobs.add(name, `12 ${now.getHours()} * * *`, async () => {
await generateStatistics(logger);
});
}
5 changes: 3 additions & 2 deletions apps/meteor/server/lib/readMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { callbacks } from '../../lib/callbacks';
export async function readMessages(rid: IRoom['_id'], uid: IUser['_id'], readThreads: boolean): Promise<void> {
await callbacks.run('beforeReadMessages', rid, uid);

const projection = { ls: 1, tunread: 1, alert: 1 };
const projection = { ls: 1, tunread: 1, alert: 1, ts: 1 };
const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, uid, { projection });
if (!sub) {
throw new Error('error-invalid-subscription');
Expand All @@ -19,5 +19,6 @@ export async function readMessages(rid: IRoom['_id'], uid: IUser['_id'], readThr

await NotificationQueue.clearQueueByUserId(uid);

callbacks.runAsync('afterReadMessages', rid, { uid, lastSeen: sub.ls });
const lastSeen = sub.ls || sub.ts;
callbacks.runAsync('afterReadMessages', rid, { uid, lastSeen });
}
21 changes: 21 additions & 0 deletions apps/meteor/server/models/raw/Statistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,25 @@ export class StatisticsRaw extends BaseRaw<IStats> implements IStatisticsModel {
).toArray();
return records?.[0];
}

async findMonthlyPeakConnections() {
const oneMonthAgo = new Date();
oneMonthAgo.setDate(oneMonthAgo.getDate() - 30);
oneMonthAgo.setHours(0, 0, 0, 0);

return this.findOne<Pick<IStats, 'dailyPeakConnections' | 'createdAt'>>(
{
createdAt: { $gte: oneMonthAgo },
},
{
sort: {
dailyPeakConnections: -1,
},
projection: {
dailyPeakConnections: 1,
createdAt: 1,
},
},
);
}
}
46 changes: 46 additions & 0 deletions apps/meteor/tests/end-to-end/api/20-licenses.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,52 @@ describe('licenses', function () {
});
});

describe('[/licenses.info]', () => {
it('should fail if not logged in', (done) => {
request
.get(api('licenses.info'))
.expect('Content-Type', 'application/json')
.expect(401)
.expect((res) => {
expect(res.body).to.have.property('status', 'error');
expect(res.body).to.have.property('message');
})
.end(done);
});

it('should return limited information if user is unauthorized', (done) => {
request
.get(api('licenses.info'))
.set(unauthorizedUserCredentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('data').and.to.be.an('object');
expect(res.body.data).to.not.have.property('license');
expect(res.body.data).to.have.property('tags').and.to.be.an('array');
})
.end(done);
});

it('should return unrestricted info if user is logged in and is authorized', (done) => {
request
.get(api('licenses.info'))
.set(credentials)
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('data').and.to.be.an('object');
if (process.env.IS_EE) {
expect(res.body.data).to.have.property('license').and.to.be.an('object');
}
expect(res.body.data).to.have.property('tags').and.to.be.an('array');
})

.end(done);
});
});

describe('[/licenses.isEnterprise]', () => {
it('should fail if not logged in', (done) => {
request
Expand Down
11 changes: 0 additions & 11 deletions ee/packages/license/babel.config.json

This file was deleted.

9 changes: 1 addition & 8 deletions ee/packages/license/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,11 @@
"version": "0.0.1",
"private": true,
"devDependencies": {
"@babel/cli": "^7.23.0",
"@babel/core": "^7.23.0",
"@babel/preset-env": "^7.22.20",
"@babel/preset-typescript": "^7.23.0",
"@swc/core": "^1.3.66",
"@swc/jest": "^0.2.26",
"@types/babel__core": "^7",
"@types/babel__preset-env": "^7",
"@types/bcrypt": "^5.0.0",
"@types/jest": "~29.5.3",
"@types/ws": "^8.5.5",
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
"eslint": "~8.45.0",
"jest": "~29.6.1",
"jest-environment-jsdom": "~29.6.1",
Expand All @@ -29,7 +22,7 @@
"testunit": "jest",
"build": "npm run build:types && npm run build:js",
"build:types": "tsc --emitDeclarationOnly",
"build:js": "babel src --out-dir dist --extensions \".ts,.tsx\" --source-maps inline",
"build:js": "rm -rf dist && tsc -p tsconfig.json",
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput"
},
"main": "./dist/index.js",
Expand Down
10 changes: 10 additions & 0 deletions ee/packages/license/src/definition/LicenseInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { ILicenseTag } from './ILicenseTag';
import type { ILicenseV3, LicenseLimitKind } from './ILicenseV3';
import type { LicenseModule } from './LicenseModule';

export type LicenseInfo = {
license?: ILicenseV3;
activeModules: LicenseModule[];
limits: Record<LicenseLimitKind, { value?: number; max: number }>;
tags: ILicenseTag[];
};
11 changes: 4 additions & 7 deletions ee/packages/license/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ILicenseV3, LicenseLimitKind } from './definition/ILicenseV3';
import type { LicenseModule } from './definition/LicenseModule';
import type { LicenseLimitKind } from './definition/ILicenseV3';
import type { LicenseInfo } from './definition/LicenseInfo';
import type { LimitContext } from './definition/LimitContext';
import { getAppsConfig, getMaxActiveUsers, getUnmodifiedLicenseAndModules } from './deprecated';
import { onLicense } from './events/deprecated';
Expand All @@ -24,6 +24,7 @@ export * from './definition/ILicenseTag';
export * from './definition/ILicenseV2';
export * from './definition/ILicenseV3';
export * from './definition/LicenseBehavior';
export * from './definition/LicenseInfo';
export * from './definition/LicenseLimit';
export * from './definition/LicenseModule';
export * from './definition/LicensePeriod';
Expand All @@ -49,11 +50,7 @@ interface License {
onBehaviorTriggered: typeof onBehaviorTriggered;
revalidateLicense: () => Promise<void>;

getInfo: (loadCurrentValues: boolean) => Promise<{
license: ILicenseV3 | undefined;
activeModules: LicenseModule[];
limits: Record<LicenseLimitKind, { value?: number; max: number }>;
}>;
getInfo: (info: { limits: boolean; currentValues: boolean; license: boolean }) => Promise<LicenseInfo>;

// Deprecated:
onLicense: typeof onLicense;
Expand Down
19 changes: 13 additions & 6 deletions ee/packages/license/src/license.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { type ILicenseTag } from './definition/ILicenseTag';
import type { ILicenseV2 } from './definition/ILicenseV2';
import type { ILicenseV3, LicenseLimitKind } from './definition/ILicenseV3';
import type { BehaviorWithContext } from './definition/LicenseBehavior';
import type { LicenseInfo } from './definition/LicenseInfo';
import type { LicenseModule } from './definition/LicenseModule';
import type { LicenseValidationOptions } from './definition/LicenseValidationOptions';
import type { LimitContext } from './definition/LimitContext';
Expand Down Expand Up @@ -291,17 +292,22 @@ export class LicenseManager extends Emitter<LicenseEvents> {
return isBehaviorsInResult(validationResult, ['prevent_action']);
}

public async getInfo(loadCurrentValues = false): Promise<{
license: ILicenseV3 | undefined;
activeModules: LicenseModule[];
limits: Record<LicenseLimitKind, { value?: number; max: number }>;
}> {
public async getInfo({
limits: includeLimits,
currentValues: loadCurrentValues,
license: includeLicense,
}: {
limits: boolean;
currentValues: boolean;
license: boolean;
}): Promise<LicenseInfo> {
const activeModules = getModules.call(this);
const license = this.getLicense();

// Get all limits present in the license and their current value
const limits = (
(license &&
includeLimits &&
(await Promise.all(
globalLimitKinds
.map((limitKey) => ({
Expand All @@ -322,9 +328,10 @@ export class LicenseManager extends Emitter<LicenseEvents> {
).reduce((prev, curr) => ({ ...prev, ...curr }), {});

return {
license,
license: (includeLicense && license) || undefined,
activeModules,
limits: limits as Record<LicenseLimitKind, { max: number; value: number }>,
tags: license?.information.tags || [],
};
}
}
2 changes: 1 addition & 1 deletion ee/packages/license/src/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { ILicenseV3 } from './definition/ILicenseV3';
const PUBLIC_LICENSE_KEY_V2 =
'LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQ0lqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FnOEFNSUlDQ2dLQ0FnRUFxV1Nza2Q5LzZ6Ung4a3lQY2ljcwpiMzJ3Mnd4VnV3N3lCVDk2clEvOEQreU1lQ01POXdTU3BIYS85bkZ5d293RXRpZ3B0L3dyb1BOK1ZHU3didHdQCkZYQmVxRWxCbmRHRkFsODZlNStFbGlIOEt6L2hHbkNtSk5tWHB4RUsyUkUwM1g0SXhzWVg3RERCN010eC9pcXMKY2pCL091dlNCa2ppU2xlUzdibE5JVC9kQTdLNC9DSjNvaXUwMmJMNEV4Y2xDSGVwenFOTWVQM3dVWmdweE9uZgpOT3VkOElYWUs3M3pTY3VFOEUxNTdZd3B6Q0twVmFIWDdaSmY4UXVOc09PNVcvYUlqS2wzTDYyNjkrZUlPRXJHCndPTm1hSG56Zmc5RkxwSmh6Z3BPMzhhVm43NnZENUtLakJhaldza1krNGEyZ1NRbUtOZUZxYXFPb3p5RUZNMGUKY0ZXWlZWWjNMZWg0dkVNb1lWUHlJeng5Nng4ZjIveW1QbmhJdXZRdjV3TjRmeWVwYTdFWTVVQ2NwNzF6OGtmUAo0RmNVelBBMElEV3lNaWhYUi9HNlhnUVFaNEdiL3FCQmh2cnZpSkNGemZZRGNKZ0w3RmVnRllIUDNQR0wwN1FnCnZMZXZNSytpUVpQcnhyYnh5U3FkUE9rZ3VyS2pWclhUVXI0QTlUZ2lMeUlYNVVsSnEzRS9SVjdtZk9xWm5MVGEKU0NWWEhCaHVQbG5DR1pSMDFUb1RDZktoTUcxdTBDRm5MMisxNWhDOWZxT21XdjlRa2U0M3FsSjBQZ0YzVkovWAp1eC9tVHBuazlnbmJHOUpIK21mSDM5Um9GdlROaW5Zd1NNdll6dXRWT242OXNPemR3aERsYTkwbDNBQ2g0eENWCks3Sk9YK3VIa29OdTNnMmlWeGlaVU0wQ0F3RUFBUT09Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo=';

const PUBLIC_LICENSE_KEY_V3 = process.env.PUBLIC_LICENSE_KEY_V3 || PUBLIC_LICENSE_KEY_V2;
const PUBLIC_LICENSE_KEY_V3 = PUBLIC_LICENSE_KEY_V2;

let TEST_KEYS: [string, string] | undefined = undefined;

Expand Down
Loading

0 comments on commit 422ed43

Please sign in to comment.