Skip to content

Commit a57a37d

Browse files
author
SeRoNet Concourse
committed
Merge remote-tracking branch 'rocket.chat/develop' into HEAD
2 parents 9b6c48c + 0f36b36 commit a57a37d

450 files changed

Lines changed: 48641 additions & 101834 deletions

File tree

Some content is hidden

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

app/2fa/server/functions/resetTOTP.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export async function resetTOTP(userId: string, notifyUser = false): Promise<boo
6060
const result = await Users.resetTOTPById(userId);
6161

6262
if (result?.modifiedCount === 1) {
63-
await Users.removeResumeService(userId);
63+
await Users.unsetLoginTokens(userId);
6464
return true;
6565
}
6666

app/api/server/helpers/deprecationWarning.js

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { API } from '../api';
2+
import { apiDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
3+
4+
(API as any).helperMethods.set('deprecationWarning', function _deprecationWarning({ endpoint, versionWillBeRemoved, response }: { endpoint: string; versionWillBeRemoved: string; response: any }) {
5+
const warningMessage = `The endpoint "${ endpoint }" is deprecated and will be removed after version ${ versionWillBeRemoved }`;
6+
apiDeprecationLogger.warn(warningMessage);
7+
if (process.env.NODE_ENV === 'development') {
8+
return {
9+
warning: warningMessage,
10+
...response,
11+
};
12+
}
13+
14+
return response;
15+
});

app/api/server/helpers/isWidget.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { parse } from 'cookie';
2+
3+
import { API } from '../api';
4+
5+
(API as any).helperMethods.set('isWidget', function _isWidget() {
6+
// @ts-expect-error
7+
const { headers } = this.request;
8+
9+
const { rc_room_type: roomType, rc_is_widget: isWidget } = parse(headers.cookie);
10+
11+
const isLivechatRoom = roomType && roomType === 'l';
12+
return !!(isLivechatRoom && isWidget === 't');
13+
});

app/api/server/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import './helpers/insertUserObject';
99
import './helpers/isUserFromParams';
1010
import './helpers/parseJsonQuery';
1111
import './helpers/requestParams';
12+
import './helpers/isWidget';
1213
import './default/info';
1314
import './v1/assets';
1415
import './v1/channels';

app/api/server/v1/banners.ts

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { Promise } from 'meteor/promise';
22
import { Meteor } from 'meteor/meteor';
33
import { Match, check } from 'meteor/check';
4+
import { TextObjectType, BlockType } from '@rocket.chat/apps-engine/definition/uikit';
45

56
import { API } from '../api';
67
import { Banner } from '../../../../server/sdk';
7-
import { BannerPlatform } from '../../../../definition/IBanner';
8+
import { BannerPlatform, IBanner } from '../../../../definition/IBanner';
89

9-
API.v1.addRoute('banners.getNew', { authRequired: true }, {
10+
API.v1.addRoute('banners.getNew', { authRequired: true }, { // deprecated
1011
get() {
1112
check(this.queryParams, Match.ObjectIncluding({
1213
platform: String,
@@ -22,12 +23,129 @@ API.v1.addRoute('banners.getNew', { authRequired: true }, {
2223
throw new Meteor.Error('error-unknown-platform', 'Platform is unknown.');
2324
}
2425

25-
const banners = Promise.await(Banner.getNewBannersForUser(this.userId, platform, bannerId));
26+
const banners = Promise.await(Banner.getBannersForUser(this.userId, platform, bannerId));
2627

2728
return API.v1.success({ banners });
2829
},
2930
});
3031

32+
33+
API.v1.addRoute('banners/:id', { authRequired: true }, {
34+
35+
get() {
36+
check(this.urlParams, Match.ObjectIncluding({
37+
id: String,
38+
}));
39+
40+
const { platform } = this.queryParams;
41+
if (!platform) {
42+
throw new Meteor.Error('error-missing-param', 'The required "platform" param is missing.');
43+
}
44+
45+
const { id } = this.urlParams;
46+
if (!id) {
47+
throw new Meteor.Error('error-missing-param', 'The required "id" param is missing.');
48+
}
49+
50+
const banners = Promise.await(Banner.getBannersForUser(this.userId, platform, id));
51+
52+
return API.v1.success({ banners });
53+
},
54+
});
55+
API.v1.addRoute('banners', { authRequired: true }, {
56+
57+
get() {
58+
check(this.queryParams, Match.ObjectIncluding({
59+
platform: String,
60+
}));
61+
62+
const { platform } = this.queryParams;
63+
if (!platform) {
64+
throw new Meteor.Error('error-missing-param', 'The required "platform" param is missing.');
65+
}
66+
67+
if (!Object.values(BannerPlatform).includes(platform)) {
68+
throw new Meteor.Error('error-unknown-platform', 'Platform is unknown.');
69+
}
70+
71+
const banners = Promise.await(Banner.getBannersForUser(this.userId, platform));
72+
73+
return API.v1.success({ banners });
74+
},
75+
...process.env.NODE_ENV !== 'production' && {
76+
post(): {} {
77+
check(this.bodyParams, Match.ObjectIncluding({
78+
platform: Match.Maybe(String),
79+
bid: String,
80+
}));
81+
82+
const { platform = 'web', bid: bannerId } = this.bodyParams;
83+
84+
if (!platform) {
85+
throw new Meteor.Error('error-missing-param', 'The required "platform" param is missing.');
86+
}
87+
88+
if (!Object.values(BannerPlatform).includes(platform)) {
89+
throw new Meteor.Error('error-unknown-platform', 'Platform is unknown.');
90+
}
91+
const b: IBanner = {
92+
_id: bannerId,
93+
platform: [platform],
94+
expireAt: new Date(new Date().getTime() + (1000 * 60 * 60 * 24 * 7)),
95+
startAt: new Date(),
96+
roles: ['admin'],
97+
createdBy: {
98+
_id: this.userId,
99+
username: this.userId,
100+
},
101+
createdAt: new Date(),
102+
_updatedAt: new Date(),
103+
view: {
104+
viewId: '',
105+
appId: '',
106+
blocks: [{
107+
type: BlockType.SECTION,
108+
blockId: 'attention',
109+
text: {
110+
type: TextObjectType.PLAINTEXT,
111+
text: 'Test',
112+
emoji: false,
113+
},
114+
}],
115+
},
116+
};
117+
118+
const banners = Promise.await(Banner.create(b));
119+
120+
return API.v1.success({ banners });
121+
},
122+
delete(): {} {
123+
check(this.bodyParams, Match.ObjectIncluding({
124+
bid: String,
125+
}));
126+
127+
const { bid } = this.bodyParams;
128+
129+
Promise.await(Banner.disable(bid));
130+
131+
return API.v1.success();
132+
},
133+
134+
patch(): {} {
135+
check(this.bodyParams, Match.ObjectIncluding({
136+
bid: String,
137+
}));
138+
139+
const { bid } = this.bodyParams;
140+
141+
Promise.await(Banner.enable(bid));
142+
143+
return API.v1.success();
144+
},
145+
},
146+
});
147+
148+
31149
API.v1.addRoute('banners.dismiss', { authRequired: true }, {
32150
post() {
33151
check(this.bodyParams, Match.ObjectIncluding({

app/api/server/v1/users.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ API.v1.addRoute('users.logout', { authRequired: true }, {
925925
}
926926

927927
// this method logs the user out automatically, if successful returns 1, otherwise 0
928-
if (!Users.removeResumeService(userId)) {
928+
if (!Users.unsetLoginTokens(userId)) {
929929
throw new Meteor.Error('error-invalid-user-id', 'Invalid user id');
930930
}
931931

app/apps/server/bridges/livechat.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
LivechatRooms,
2020
} from '../../../models/server';
2121
import { AppServerOrchestrator } from '../orchestrator';
22+
import { OmnichannelSourceType } from '../../../../definition/IRoom';
2223

2324
export class AppLivechatBridge extends LivechatBridge {
2425
// eslint-disable-next-line no-empty-function
@@ -45,7 +46,13 @@ export class AppLivechatBridge extends LivechatBridge {
4546
guest: this.orch.getConverters()?.get('visitors').convertAppVisitor(message.visitor),
4647
message: this.orch.getConverters()?.get('messages').convertAppMessage(message),
4748
agent: undefined,
48-
roomInfo: undefined,
49+
roomInfo: {
50+
source: {
51+
type: OmnichannelSourceType.APP,
52+
id: appId,
53+
alias: this.orch.getManager()?.getOneById(appId)?.getNameSlug(),
54+
},
55+
},
4956
});
5057

5158
return msg._id;
@@ -81,7 +88,13 @@ export class AppLivechatBridge extends LivechatBridge {
8188
guest: this.orch.getConverters()?.get('visitors').convertAppVisitor(visitor),
8289
agent: agentRoom,
8390
rid: Random.id(),
84-
roomInfo: undefined,
91+
roomInfo: {
92+
source: {
93+
type: OmnichannelSourceType.APP,
94+
id: appId,
95+
alias: this.orch.getManager()?.getOneById(appId)?.getNameSlug(),
96+
},
97+
},
8598
extraParams: undefined,
8699
});
87100

@@ -167,10 +180,22 @@ export class AppLivechatBridge extends LivechatBridge {
167180
type,
168181
};
169182

183+
let userId;
184+
let transferredTo;
185+
186+
if (targetAgent?.id) {
187+
transferredTo = Users.findOneAgentById(targetAgent.id, { fields: { _id: 1, username: 1, name: 1 } });
188+
if (!transferredTo) {
189+
throw new Error('Invalid target agent, cannot transfer');
190+
}
191+
192+
userId = transferredTo._id;
193+
}
194+
170195
return Livechat.transfer(
171196
this.orch.getConverters()?.get('rooms').convertAppRoom(currentRoom),
172197
this.orch.getConverters()?.get('visitors').convertAppVisitor(visitor),
173-
{ userId: targetAgent ? targetAgent.id : undefined, departmentId, transferredBy },
198+
{ userId, departmentId, transferredBy, transferredTo },
174199
);
175200
}
176201

app/apps/server/orchestrator.js

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,25 @@ import { AppMessagesConverter, AppRoomsConverter, AppSettingsConverter, AppUsers
1212
import { AppDepartmentsConverter } from './converters/departments';
1313
import { AppUploadsConverter } from './converters/uploads';
1414
import { AppVisitorsConverter } from './converters/visitors';
15-
import { AppRealLogsStorage, AppRealStorage } from './storage';
15+
import { AppRealLogsStorage, AppRealStorage, ConfigurableAppSourceStorage } from './storage';
1616

1717
function isTesting() {
1818
return process.env.TEST_MODE === 'true';
1919
}
2020

21+
let appsSourceStorageType;
22+
let appsSourceStorageFilesystemPath;
23+
2124
export class AppServerOrchestrator {
2225
constructor() {
2326
this._isInitialized = false;
2427
}
2528

2629
initialize() {
30+
if (this._isInitialized) {
31+
return;
32+
}
33+
2734
this._rocketchatLogger = new Logger('Rocket.Chat Apps');
2835
Permissions.create('manage-apps', ['admin']);
2936

@@ -38,6 +45,7 @@ export class AppServerOrchestrator {
3845
this._persistModel = new AppsPersistenceModel();
3946
this._storage = new AppRealStorage(this._model);
4047
this._logStorage = new AppRealLogsStorage(this._logModel);
48+
this._appSourceStorage = new ConfigurableAppSourceStorage(appsSourceStorageType, appsSourceStorageFilesystemPath);
4149

4250
this._converters = new Map();
4351
this._converters.set('messages', new AppMessagesConverter(this));
@@ -50,7 +58,12 @@ export class AppServerOrchestrator {
5058

5159
this._bridges = new RealAppBridges(this);
5260

53-
this._manager = new AppManager(this._storage, this._logStorage, this._bridges);
61+
this._manager = new AppManager({
62+
metadataStorage: this._storage,
63+
logStorage: this._logStorage,
64+
bridges: this._bridges,
65+
sourceStorage: this._appSourceStorage,
66+
});
5467

5568
this._communicators = new Map();
5669
this._communicators.set('methods', new AppMethods(this));
@@ -97,6 +110,10 @@ export class AppServerOrchestrator {
97110
return this._manager.getExternalComponentManager().getProvidedComponents();
98111
}
99112

113+
getAppSourceStorage() {
114+
return this._appSourceStorage;
115+
}
116+
100117
isInitialized() {
101118
return this._isInitialized;
102119
}
@@ -215,9 +232,48 @@ settings.addGroup('General', function() {
215232
public: true,
216233
hidden: false,
217234
});
235+
236+
this.add('Apps_Framework_Source_Package_Storage_Type', 'gridfs', {
237+
type: 'select',
238+
values: [{
239+
key: 'gridfs',
240+
i18nLabel: 'GridFS',
241+
}, {
242+
key: 'filesystem',
243+
i18nLabel: 'FileSystem',
244+
}],
245+
public: true,
246+
hidden: false,
247+
alert: 'Apps_Framework_Source_Package_Storage_Type_Alert',
248+
});
249+
250+
this.add('Apps_Framework_Source_Package_Storage_FileSystem_Path', '', {
251+
type: 'string',
252+
public: true,
253+
enableQuery: {
254+
_id: 'Apps_Framework_Source_Package_Storage_Type',
255+
value: 'filesystem',
256+
},
257+
alert: 'Apps_Framework_Source_Package_Storage_FileSystem_Alert',
258+
});
218259
});
219260
});
220261

262+
settings.get('Apps_Framework_Source_Package_Storage_Type', (_, value) => {
263+
if (!Apps.isInitialized()) {
264+
appsSourceStorageType = value;
265+
} else {
266+
Apps.getAppSourceStorage().setStorage(value);
267+
}
268+
});
269+
270+
settings.get('Apps_Framework_Source_Package_Storage_FileSystem_Path', (_, value) => {
271+
if (!Apps.isInitialized()) {
272+
appsSourceStorageFilesystemPath = value;
273+
} else {
274+
Apps.getAppSourceStorage().setFileSystemStoragePath(value);
275+
}
276+
});
221277

222278
settings.get('Apps_Framework_enabled', (key, isEnabled) => {
223279
// In case this gets called before `Meteor.startup`

0 commit comments

Comments
 (0)