Skip to content

Commit dd24f9a

Browse files
Merge branch 'develop' into feat/openapi-chat-postMessage
2 parents 2e4fe2b + afaabea commit dd24f9a

File tree

98 files changed

+675
-222
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

98 files changed

+675
-222
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/message-parser': patch
3+
---
4+
5+
Fixed blockquotes with empty lines between paragraphs not rendering as a single blockquote. Lines like `> ` or `>` (empty quote lines) are now treated as part of the surrounding blockquote rather than breaking it into separate quotes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': patch
3+
---
4+
5+
Fixes wrong i18n key in RegisterWorkspace confirmation step so the text is translated instead of showing a missing key.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rocket.chat/message-parser": patch
3+
---
4+
5+
Fixes trailing punctuation (e.g. periods, exclamation marks) being incorrectly included in parsed URLs when they appear at the end of a message. For example, `go to https://www.google.com.` now correctly parses the URL as `https://www.google.com` without the trailing period.

.changeset/olive-hairs-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': patch
3+
---
4+
5+
Fixes version update banner showing outdated versions after server upgrade.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': minor
3+
---
4+
5+
Migrates `ldap.testConnection` and `ldap.testSearch` REST API endpoints from legacy `addRoute` pattern to the new chained `.post()` API pattern with typed response schemas and AJV body validation (replacing Meteor `check()`).
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@rocket.chat/meteor': minor
3+
---
4+
5+
Migrates `presence.getConnections` and `presence.enableBroadcast` REST API endpoints from legacy `addRoute` pattern to the new chained `.get()`/`.post()` API pattern with typed response schemas.

.github/actions/build-docker/action.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ runs:
108108
--allow=fs.read=/tmp/build \
109109
--set "*.tags+=${IMAGE}-gha-run-${{ github.run_id }}" \
110110
--set "*.labels.org.opencontainers.image.description=Build run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
111+
--set "*.labels.org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}" \
111112
--set *.platform=linux/${{ inputs.arch }} \
112113
--set *.cache-from=type=gha \
113114
--set *.cache-to=type=gha,mode=max \

apps/meteor/app/api/server/helpers/getUserInfo.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import { getUserInfo } from './getUserInfo';
22
import type { CachedSettings } from '../../../settings/server/CachedSettings';
33

4+
const mockInfoVersion = jest.fn(() => '7.5.0');
5+
6+
jest.mock('../../../utils/rocketchat.info', () => ({
7+
Info: {
8+
get version() {
9+
return mockInfoVersion();
10+
},
11+
},
12+
}));
13+
414
jest.mock('@rocket.chat/models', () => ({
515
Users: {
616
findOneById: jest.fn().mockResolvedValue({
@@ -198,4 +208,50 @@ describe('getUserInfo', () => {
198208
});
199209
});
200210
});
211+
212+
describe('version update banner filtering', () => {
213+
beforeEach(() => {
214+
mockInfoVersion.mockReturnValue('7.5.0');
215+
});
216+
217+
it('should filter out versionUpdate banners for versions <= current installed', async () => {
218+
user.banners = {
219+
'versionUpdate-6_2_0': {
220+
id: 'versionUpdate-6_2_0',
221+
priority: 10,
222+
title: 'Update',
223+
text: 'New version',
224+
modifiers: [],
225+
link: '',
226+
read: false,
227+
},
228+
};
229+
const userInfo = await getUserInfo(user);
230+
expect(userInfo.banners).toEqual({});
231+
});
232+
233+
it('should keep versionUpdate banners for versions > current installed', async () => {
234+
user.banners = {
235+
'versionUpdate-8_0_0': {
236+
id: 'versionUpdate-8_0_0',
237+
priority: 10,
238+
title: 'Update',
239+
text: 'New version',
240+
modifiers: [],
241+
link: '',
242+
read: false,
243+
},
244+
};
245+
const userInfo = await getUserInfo(user);
246+
expect(userInfo.banners).toHaveProperty('versionUpdate-8_0_0');
247+
});
248+
249+
it('should keep non-versionUpdate banners unchanged', async () => {
250+
user.banners = {
251+
'other-banner': { id: 'other-banner', priority: 10, title: 'Other', text: 'Other banner', modifiers: [], link: '', read: false },
252+
};
253+
const userInfo = await getUserInfo(user);
254+
expect(userInfo.banners).toHaveProperty('other-banner');
255+
});
256+
});
201257
});

apps/meteor/app/api/server/helpers/getUserInfo.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { isOAuthUser, type IUser, type IUserEmail, type IUserCalendar } from '@rocket.chat/core-typings';
2+
import semver from 'semver';
23

34
import { settings } from '../../../settings/server';
5+
import { Info } from '../../../utils/rocketchat.info';
46
import { getURL } from '../../../utils/server/getURL';
57
import { getUserPreference } from '../../../utils/server/lib/getUserPreference';
68

@@ -25,6 +27,23 @@ const getUserPreferences = async (me: IUser): Promise<Record<string, unknown>> =
2527
return accumulator;
2628
};
2729

30+
const filterOutdatedVersionUpdateBanners = (banners: NonNullable<IUser['banners']>): IUser['banners'] => {
31+
return Object.fromEntries(
32+
Object.entries(banners).filter(([id]) => {
33+
if (!id.startsWith('versionUpdate-')) {
34+
return true;
35+
}
36+
37+
const version = id.replace('versionUpdate-', '').replace(/_/g, '.');
38+
if (!semver.valid(version) || semver.lte(version, Info.version)) {
39+
return false;
40+
}
41+
42+
return true;
43+
}),
44+
);
45+
};
46+
2847
/**
2948
* Returns the user's calendar settings based on their email domain and the configured mapping.
3049
* If the email is not provided or the domain is not found in the mapping,
@@ -80,6 +99,7 @@ export async function getUserInfo(
8099

81100
return {
82101
...me,
102+
...(me.banners && { banners: filterOutdatedVersionUpdateBanners(me.banners) }),
83103
email: verifiedEmail ? verifiedEmail.address : undefined,
84104
settings: {
85105
profile: {},
Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,86 @@
11
import { LDAP } from '@rocket.chat/core-services';
2-
import { Match, check } from 'meteor/check';
2+
import { ajv, isLdapTestSearch, validateUnauthorizedErrorResponse, validateForbiddenErrorResponse } from '@rocket.chat/rest-typings';
33

44
import { SystemLogger } from '../../../../server/lib/logger/system';
55
import { settings } from '../../../settings/server';
66
import { API } from '../api';
77

8-
API.v1.addRoute(
8+
const messageResponseSchema = {
9+
type: 'object' as const,
10+
properties: {
11+
message: { type: 'string' as const },
12+
success: {
13+
type: 'boolean' as const,
14+
enum: [true] as const,
15+
},
16+
},
17+
required: ['message', 'success'] as const,
18+
additionalProperties: false,
19+
};
20+
21+
API.v1.post(
922
'ldap.testConnection',
10-
{ authRequired: true, permissionsRequired: ['test-admin-options'] },
1123
{
12-
async post() {
13-
if (!this.userId) {
14-
throw new Error('error-invalid-user');
15-
}
16-
17-
if (settings.get<boolean>('LDAP_Enable') !== true) {
18-
throw new Error('LDAP_disabled');
19-
}
20-
21-
try {
22-
await LDAP.testConnection();
23-
} catch (err) {
24-
SystemLogger.error({ err });
25-
throw new Error('Connection_failed');
26-
}
27-
28-
return API.v1.success({
29-
message: 'LDAP_Connection_successful' as const,
30-
});
24+
authRequired: true,
25+
permissionsRequired: ['test-admin-options'],
26+
response: {
27+
200: ajv.compile<{ message: string; success: true }>(messageResponseSchema),
28+
401: validateUnauthorizedErrorResponse,
29+
403: validateForbiddenErrorResponse,
3130
},
3231
},
32+
async function action() {
33+
if (!this.userId) {
34+
throw new Error('error-invalid-user');
35+
}
36+
37+
if (settings.get<boolean>('LDAP_Enable') !== true) {
38+
throw new Error('LDAP_disabled');
39+
}
40+
41+
try {
42+
await LDAP.testConnection();
43+
} catch (err) {
44+
SystemLogger.error({ err });
45+
throw new Error('Connection_failed');
46+
}
47+
48+
return API.v1.success({
49+
message: 'LDAP_Connection_successful' as const,
50+
});
51+
},
3352
);
3453

35-
API.v1.addRoute(
54+
API.v1.post(
3655
'ldap.testSearch',
37-
{ authRequired: true, permissionsRequired: ['test-admin-options'] },
3856
{
39-
async post() {
40-
check(
41-
this.bodyParams,
42-
Match.ObjectIncluding({
43-
username: String,
44-
}),
45-
);
46-
47-
if (!this.userId) {
48-
throw new Error('error-invalid-user');
49-
}
50-
51-
if (settings.get('LDAP_Enable') !== true) {
52-
throw new Error('LDAP_disabled');
53-
}
57+
authRequired: true,
58+
permissionsRequired: ['test-admin-options'],
59+
body: isLdapTestSearch,
60+
response: {
61+
200: ajv.compile<{ message: string; success: true }>(messageResponseSchema),
62+
401: validateUnauthorizedErrorResponse,
63+
403: validateForbiddenErrorResponse,
64+
},
65+
},
66+
async function action() {
67+
if (!this.userId) {
68+
throw new Error('error-invalid-user');
69+
}
5470

71+
if (settings.get<boolean>('LDAP_Enable') !== true) {
72+
throw new Error('LDAP_disabled');
73+
}
74+
75+
try {
5576
await LDAP.testSearch(this.bodyParams.username);
77+
} catch (err) {
78+
SystemLogger.error({ err });
79+
throw new Error('LDAP_search_failed');
80+
}
5681

57-
return API.v1.success({
58-
message: 'LDAP_User_Found' as const,
59-
});
60-
},
82+
return API.v1.success({
83+
message: 'LDAP_User_Found' as const,
84+
});
6185
},
6286
);

0 commit comments

Comments
 (0)