Chore: Remove settings Fibers usage (#26465)

Co-authored-by: Diego Sampaio <chinello@gmail.com>
pull/26133/head^2
Guilherme Gazzo 4 years ago committed by GitHub
parent d164c06df3
commit f45b9563f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      apps/meteor/app/apps/server/communication/rest.js
  2. 4
      apps/meteor/app/assets/server/assets.ts
  3. 6
      apps/meteor/app/authentication/server/startup/index.js
  4. 6
      apps/meteor/app/cloud/server/functions/buildRegistrationData.ts
  5. 10
      apps/meteor/app/cloud/server/functions/connectWorkspace.ts
  6. 7
      apps/meteor/app/cloud/server/functions/disconnectWorkspace.ts
  7. 10
      apps/meteor/app/cloud/server/functions/getOAuthAuthorizationUrl.ts
  8. 19
      apps/meteor/app/cloud/server/functions/getWorkspaceAccessToken.ts
  9. 16
      apps/meteor/app/cloud/server/functions/getWorkspaceLicense.ts
  10. 10
      apps/meteor/app/cloud/server/functions/startRegisterWorkspace.ts
  11. 20
      apps/meteor/app/cloud/server/functions/syncWorkspace.ts
  12. 19
      apps/meteor/app/cloud/server/functions/unregisterWorkspace.js
  13. 22
      apps/meteor/app/cloud/server/functions/unregisterWorkspace.ts
  14. 2
      apps/meteor/app/cloud/server/index.js
  15. 3
      apps/meteor/app/error-handler/server/lib/RocketChat.ErrorHandler.js
  16. 7
      apps/meteor/app/file-upload/server/lib/FileUpload.js
  17. 5
      apps/meteor/app/importer-csv/server/importer.js
  18. 4
      apps/meteor/app/importer-hipchat-enterprise/server/importer.js
  19. 5
      apps/meteor/app/importer-slack-users/server/importer.js
  20. 5
      apps/meteor/app/importer-slack/server/importer.js
  21. 33
      apps/meteor/app/importer/server/classes/ImporterBase.js
  22. 4
      apps/meteor/app/irc/server/irc-bridge/index.js
  23. 21
      apps/meteor/app/irc/server/methods/resetIrcConnection.ts
  24. 21
      apps/meteor/app/lib/server/methods/sendInvitationEmail.ts
  25. 10
      apps/meteor/app/livechat/imports/server/rest/upload.js
  26. 29
      apps/meteor/app/livechat/server/api/v1/videoCall.js
  27. 71
      apps/meteor/app/livechat/server/lib/Livechat.js
  28. 2
      apps/meteor/app/livechat/server/methods/facebook.js
  29. 17
      apps/meteor/app/livechat/server/methods/saveAppearance.ts
  30. 55
      apps/meteor/app/livechat/server/methods/saveIntegration.js
  31. 56
      apps/meteor/app/livechat/server/methods/saveIntegration.ts
  32. 4
      apps/meteor/app/mailer/server/api.ts
  33. 2
      apps/meteor/app/models/server/index.ts
  34. 280
      apps/meteor/app/models/server/models/Settings.js
  35. 9
      apps/meteor/app/settings/server/CachedSettings.ts
  36. 22
      apps/meteor/app/settings/server/SettingsRegistry.ts
  37. 6
      apps/meteor/app/settings/server/functions/settings.mocks.ts
  38. 16
      apps/meteor/app/settings/server/index.ts
  39. 31
      apps/meteor/app/settings/server/raw.js
  40. 32
      apps/meteor/app/settings/server/raw.ts
  41. 8
      apps/meteor/app/settings/server/startup.ts
  42. 3
      apps/meteor/app/statistics/server/functions/updateStatsCounter.ts
  43. 38
      apps/meteor/app/statistics/server/lib/statistics.ts
  44. 2
      apps/meteor/app/theme/server/server.js
  45. 14
      apps/meteor/app/ui-master/server/index.js
  46. 93
      apps/meteor/app/version-check/server/functions/checkVersionUpdate.js
  47. 90
      apps/meteor/app/version-check/server/functions/checkVersionUpdate.ts
  48. 72
      apps/meteor/app/version-check/server/functions/getNewUpdates.js
  49. 93
      apps/meteor/app/version-check/server/functions/getNewUpdates.ts
  50. 6
      apps/meteor/app/version-check/server/index.ts
  51. 9
      apps/meteor/definition/externals/meteor/rocketchat-tap-i18n.d.ts
  52. 6
      apps/meteor/ee/app/canned-responses/server/index.js
  53. 9
      apps/meteor/ee/app/license/server/getSeatsRequestLink.ts
  54. 2
      apps/meteor/ee/app/license/server/settings.js
  55. 9
      apps/meteor/ee/app/livechat-enterprise/server/settings.ts
  56. 4
      apps/meteor/ee/app/settings/server/settings.ts
  57. 7
      apps/meteor/ee/server/api/licenses.ts
  58. 2
      apps/meteor/ee/server/requestSeatsRoute.ts
  59. 2
      apps/meteor/ee/server/startup/upsell.ts
  60. 2
      apps/meteor/server/cron/federation.ts
  61. 2
      apps/meteor/server/cron/statistics.js
  62. 2
      apps/meteor/server/lib/sendMessagesToAdmins.ts
  63. 6
      apps/meteor/server/methods/getSetupWizardParameters.ts
  64. 9
      apps/meteor/server/models/raw/Settings.ts
  65. 2
      apps/meteor/server/services/nps/getAndCreateNpsSurvey.ts
  66. 2
      apps/meteor/server/services/nps/sendNpsResults.ts
  67. 9
      apps/meteor/server/startup/migrations/v246.ts
  68. 92
      apps/meteor/tests/unit/app/settings/server/functions/settings.tests.ts
  69. 45
      apps/meteor/tests/unit/app/settings/server/raw.tests.js
  70. 2
      packages/core-typings/src/ISetting.ts
  71. 7
      packages/model-typings/src/models/ISettingsModel.ts

@ -70,13 +70,13 @@ export class AppsRestApi {
'',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
get() {
async get() {
const baseUrl = orchestrator.getMarketplaceUrl();
// Gets the Apps from the marketplace
if (this.queryParams.marketplace) {
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -100,7 +100,7 @@ export class AppsRestApi {
if (this.queryParams.categories) {
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -183,8 +183,8 @@ export class AppsRestApi {
const headers = getDefaultHeaders();
try {
const downloadToken = getWorkspaceAccessToken(true, 'marketplace:download', false);
const marketplaceToken = getWorkspaceAccessToken();
const downloadToken = await getWorkspaceAccessToken(true, 'marketplace:download', false);
const marketplaceToken = await getWorkspaceAccessToken();
const [downloadResponse, marketplaceResponse] = await Promise.all([
fetch(`${baseUrl}/v2/apps/${this.bodyParams.appId}/download/${this.bodyParams.version}?token=${downloadToken}`, {
@ -318,11 +318,11 @@ export class AppsRestApi {
'bundles/:id/apps',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
get() {
async get() {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = {};
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -351,11 +351,11 @@ export class AppsRestApi {
'featured',
{ authRequired: true },
{
get() {
async get() {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -383,12 +383,12 @@ export class AppsRestApi {
':id',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
get() {
async get() {
if (this.queryParams.marketplace && this.queryParams.version) {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = {}; // DO NOT ATTACH THE FRAMEWORK/ENGINE VERSION HERE.
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -414,7 +414,7 @@ export class AppsRestApi {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -466,7 +466,7 @@ export class AppsRestApi {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken(true, 'marketplace:download', false);
const token = await getWorkspaceAccessToken(true, 'marketplace:download', false);
try {
const response = await fetch(
@ -564,11 +564,11 @@ export class AppsRestApi {
':id/versions',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
get() {
async get() {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = {}; // DO NOT ATTACH THE FRAMEWORK/ENGINE VERSION HERE.
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
@ -596,16 +596,16 @@ export class AppsRestApi {
':id/sync',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
post() {
async post() {
const baseUrl = orchestrator.getMarketplaceUrl();
const headers = getDefaultHeaders();
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const workspaceIdSetting = Promise.await(Settings.findOneById('Cloud_Workspace_Id'));
const workspaceIdSetting = await Settings.findOneById('Cloud_Workspace_Id');
let result;
try {
@ -622,7 +622,7 @@ export class AppsRestApi {
return API.v1.failure();
}
Promise.await(Apps.updateAppsMarketplaceInfo([result.data]));
await Apps.updateAppsMarketplaceInfo([result.data]);
return API.v1.success({ app: result.data });
},

@ -9,13 +9,13 @@ import sizeOf from 'image-size';
import sharp from 'sharp';
import { NextHandleFunction } from 'connect';
import { IRocketChatAssets, IRocketChatAsset } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
import { settings, settingsRegistry } from '../../settings/server';
import { getURL } from '../../utils/lib/getURL';
import { getExtension } from '../../utils/lib/mimeTypes';
import { hasPermission } from '../../authorization/server';
import { RocketChatFile } from '../../file';
import { Settings } from '../../models/server';
const RocketChatAssetsInstance = new RocketChatFile.GridFS({
name: 'assets',
@ -347,7 +347,7 @@ function addAssetToSetting(asset: string, value: IRocketChatAsset): void {
if (typeof currentValue === 'object' && currentValue.defaultUrl !== getAssetByKey(asset).defaultUrl) {
currentValue.defaultUrl = getAssetByKey(asset).defaultUrl;
Settings.updateValueById(key, currentValue);
Promise.await(Settings.updateValueById(key, currentValue));
}
}

@ -4,12 +4,12 @@ import { Accounts } from 'meteor/accounts-base';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import _ from 'underscore';
import { escapeRegExp, escapeHTML } from '@rocket.chat/string-helpers';
import { Roles, Users as UsersRaw } from '@rocket.chat/models';
import { Roles, Settings, Users as UsersRaw } from '@rocket.chat/models';
import * as Mailer from '../../../mailer/server/api';
import { settings } from '../../../settings/server';
import { callbacks } from '../../../../lib/callbacks';
import { Settings, Users } from '../../../models/server';
import { Users } from '../../../models/server';
import { addUserRoles } from '../../../../server/lib/roles/addUserRoles';
import { getAvatarSuggestionForUser } from '../../../lib/server/functions/getAvatarSuggestionForUser';
import { parseCSV } from '../../../../lib/utils/parseCSV';
@ -295,7 +295,7 @@ Accounts.insertUserDoc = _.wrap(Accounts.insertUserDoc, function (insertUserDoc,
if (!roles.includes('admin') && !hasAdmin) {
roles.push('admin');
if (settings.get('Show_Setup_Wizard') === 'pending') {
Settings.updateValueById('Show_Setup_Wizard', 'in_progress');
Promise.await(Settings.updateValueById('Show_Setup_Wizard', 'in_progress'));
}
}

@ -6,12 +6,12 @@ import { Users } from '../../../models/server';
import { statistics } from '../../../statistics/server';
import { LICENSE_VERSION } from '../license';
type WorkspaceRegistrationData = {
type WorkspaceRegistrationData<T> = {
uniqueId: string;
workspaceId: SettingValue;
address: SettingValue;
contactName: string;
contactEmail: string;
contactEmail: T;
seats: number;
allowMarketing: SettingValue;
accountName: SettingValue;
@ -33,7 +33,7 @@ type WorkspaceRegistrationData = {
npsEnabled: SettingValue;
};
export async function buildWorkspaceRegistrationData(contactEmail: string): Promise<WorkspaceRegistrationData> {
export async function buildWorkspaceRegistrationData<T extends string | undefined>(contactEmail: T): Promise<WorkspaceRegistrationData<T>> {
const stats = (await Statistics.findLast()) || (await statistics.get());
const address = settings.get('Site_Url');

@ -1,16 +1,16 @@
import { HTTP } from 'meteor/http';
import { Settings } from '@rocket.chat/models';
import { getRedirectUri } from './getRedirectUri';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { Settings } from '../../../models/server';
import { settings } from '../../../settings/server';
import { saveRegistrationData } from './saveRegistrationData';
import { SystemLogger } from '../../../../server/lib/logger/system';
export function connectWorkspace(token) {
export async function connectWorkspace(token: string) {
const { connectToCloud } = retrieveRegistrationStatus();
if (!connectToCloud) {
Settings.updateValueById('Register_Server', true);
await Settings.updateValueById('Register_Server', true);
}
// shouldn't get here due to checking this on the method
@ -36,7 +36,7 @@ export function connectWorkspace(token) {
},
data: regInfo,
});
} catch (e) {
} catch (e: any) {
if (e.response && e.response.data && e.response.data.error) {
SystemLogger.error(`Failed to register with Rocket.Chat Cloud. Error: ${e.response.data.error}`);
} else {
@ -52,7 +52,7 @@ export function connectWorkspace(token) {
return false;
}
Promise.await(saveRegistrationData(data));
await saveRegistrationData(data);
return true;
}

@ -1,13 +1,14 @@
import { Settings } from '@rocket.chat/models';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { Settings } from '../../../models/server';
export function disconnectWorkspace() {
export async function disconnectWorkspace() {
const { connectToCloud } = retrieveRegistrationStatus();
if (!connectToCloud) {
return true;
}
Settings.updateValueById('Register_Server', false);
await Settings.updateValueById('Register_Server', false);
return true;
}

@ -1,20 +1,20 @@
import { Random } from 'meteor/random';
import { Settings } from '@rocket.chat/models';
import { getRedirectUri } from './getRedirectUri';
import { Settings } from '../../../models/server';
import { settings } from '../../../settings/server';
import { userScopes } from '../oauthScopes';
export function getOAuthAuthorizationUrl() {
export async function getOAuthAuthorizationUrl() {
const state = Random.id();
Settings.updateValueById('Cloud_Workspace_Registration_State', state);
await Settings.updateValueById('Cloud_Workspace_Registration_State', state);
const cloudUrl = settings.get('Cloud_Url');
const client_id = settings.get('Cloud_Workspace_Client_Id');
const clientId = settings.get('Cloud_Workspace_Client_Id');
const redirectUri = getRedirectUri();
const scope = userScopes.join(' ');
return `${cloudUrl}/authorize?response_type=code&client_id=${client_id}&redirect_uri=${redirectUri}&scope=${scope}&state=${state}`;
return `${cloudUrl}/authorize?response_type=code&client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}&state=${state}`;
}

@ -1,6 +1,7 @@
import { Settings } from '@rocket.chat/models';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { getWorkspaceAccessTokenWithScope } from './getWorkspaceAccessTokenWithScope';
import { Settings } from '../../../models/server';
import { settings } from '../../../settings/server';
/**
@ -9,25 +10,31 @@ import { settings } from '../../../settings/server';
* @param {boolean} save
* @returns string
*/
export function getWorkspaceAccessToken(forceNew = false, scope = '', save = true) {
export async function getWorkspaceAccessToken(forceNew = false, scope = '', save = true) {
const { connectToCloud, workspaceRegistered } = retrieveRegistrationStatus();
if (!connectToCloud || !workspaceRegistered) {
return '';
}
const expires = Settings.findOneById('Cloud_Workspace_Access_Token_Expires_At');
const expires = await Settings.findOneById('Cloud_Workspace_Access_Token_Expires_At');
if (expires === null) {
throw new Error('Cloud_Workspace_Access_Token_Expires_At is not set');
}
const now = new Date();
if (now < expires.value && !forceNew) {
if (expires.value && now < expires.value && !forceNew) {
return settings.get('Cloud_Workspace_Access_Token');
}
const accessToken = getWorkspaceAccessTokenWithScope(scope);
if (save) {
Settings.updateValueById('Cloud_Workspace_Access_Token', accessToken.token);
Settings.updateValueById('Cloud_Workspace_Access_Token_Expires_At', accessToken.expiresAt);
await Promise.all([
Settings.updateValueById('Cloud_Workspace_Access_Token', accessToken.token),
Settings.updateValueById('Cloud_Workspace_Access_Token_Expires_At', accessToken.expiresAt),
]);
}
return accessToken.token;

@ -1,14 +1,14 @@
import { HTTP } from 'meteor/http';
import { Settings } from '@rocket.chat/models';
import { getWorkspaceAccessToken } from './getWorkspaceAccessToken';
import { settings } from '../../../settings/server';
import { Settings } from '../../../models/server';
import { callbacks } from '../../../../lib/callbacks';
import { LICENSE_VERSION } from '../license';
import { SystemLogger } from '../../../../server/lib/logger/system';
export function getWorkspaceLicense() {
const token = getWorkspaceAccessToken();
export async function getWorkspaceLicense() {
const token = await getWorkspaceAccessToken();
if (!token) {
return { updated: false, license: '' };
@ -21,7 +21,7 @@ export function getWorkspaceLicense() {
Authorization: `Bearer ${token}`,
},
});
} catch (e) {
} catch (e: any) {
if (e.response && e.response.data && e.response.data.error) {
SystemLogger.error(`Failed to update license from Rocket.Chat Cloud. Error: ${e.response.data.error}`);
} else {
@ -32,13 +32,17 @@ export function getWorkspaceLicense() {
}
const remoteLicense = licenseResult.data;
const currentLicense = settings.get('Cloud_Workspace_License');
const currentLicense = await Settings.findOne('Cloud_Workspace_License');
if (!currentLicense || !currentLicense._updatedAt) {
throw new Error('Failed to retrieve current license');
}
if (remoteLicense.updatedAt <= currentLicense._updatedAt) {
return { updated: false, license: '' };
}
Settings.updateValueById('Cloud_Workspace_License', remoteLicense.license);
await Settings.updateValueById('Cloud_Workspace_License', remoteLicense.license);
callbacks.run('workspaceLicenseChanged', remoteLicense.license);

@ -1,9 +1,9 @@
import { HTTP } from 'meteor/http';
import { Settings } from '@rocket.chat/models';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { syncWorkspace } from './syncWorkspace';
import { settings } from '../../../settings/server';
import { Settings } from '../../../models/server';
import { buildWorkspaceRegistrationData } from './buildRegistrationData';
import { SystemLogger } from '../../../../server/lib/logger/system';
@ -15,9 +15,9 @@ export async function startRegisterWorkspace(resend = false) {
return true;
}
Settings.updateValueById('Register_Server', true);
await Settings.updateValueById('Register_Server', true);
const regInfo = await buildWorkspaceRegistrationData();
const regInfo = await buildWorkspaceRegistrationData(undefined);
const cloudUrl = settings.get('Cloud_Url');
@ -26,7 +26,7 @@ export async function startRegisterWorkspace(resend = false) {
result = HTTP.post(`${cloudUrl}/api/v2/register/workspace?resend=${resend}`, {
data: regInfo,
});
} catch (e) {
} catch (e: any) {
if (e.response && e.response.data && e.response.data.error) {
SystemLogger.error(`Failed to register with Rocket.Chat Cloud. ErrorCode: ${e.response.data.error}`);
} else {
@ -39,7 +39,7 @@ export async function startRegisterWorkspace(resend = false) {
return false;
}
Settings.updateValueById('Cloud_Workspace_Id', data.id);
await Settings.updateValueById('Cloud_Workspace_Id', data.id);
return true;
}

@ -1,10 +1,10 @@
import { HTTP } from 'meteor/http';
import { Settings } from '@rocket.chat/models';
import { buildWorkspaceRegistrationData } from './buildRegistrationData';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { getWorkspaceAccessToken } from './getWorkspaceAccessToken';
import { getWorkspaceLicense } from './getWorkspaceLicense';
import { Settings } from '../../../models/server';
import { settings } from '../../../settings/server';
import { getAndCreateNpsSurvey } from '../../../../server/services/nps/getAndCreateNpsSurvey';
import { NPS, Banner } from '../../../../server/sdk';
@ -16,14 +16,14 @@ export async function syncWorkspace(reconnectCheck = false) {
return false;
}
const info = await buildWorkspaceRegistrationData();
const info = await buildWorkspaceRegistrationData(undefined);
const workspaceUrl = settings.get('Cloud_Workspace_Registration_Client_Uri');
let result;
try {
const headers = {};
const token = getWorkspaceAccessToken(true);
const headers: Record<string, string> = {};
const token = await getWorkspaceAccessToken(true);
if (token) {
headers.Authorization = `Bearer ${token}`;
@ -36,8 +36,8 @@ export async function syncWorkspace(reconnectCheck = false) {
headers,
});
getWorkspaceLicense();
} catch (e) {
await getWorkspaceLicense();
} catch (e: any) {
if (e.response && e.response.data && e.response.data.error) {
SystemLogger.error(`Failed to sync with Rocket.Chat Cloud. Error: ${e.response.data.error}`);
} else {
@ -53,11 +53,11 @@ export async function syncWorkspace(reconnectCheck = false) {
}
if (data.publicKey) {
Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey);
await Settings.updateValueById('Cloud_Workspace_PublicKey', data.publicKey);
}
if (data.trial?.trialId) {
Settings.updateValueById('Cloud_Workspace_Had_Trial', true);
await Settings.updateValueById('Cloud_Workspace_Had_Trial', true);
}
if (data.nps) {
@ -69,6 +69,10 @@ export async function syncWorkspace(reconnectCheck = false) {
npsId,
startAt,
expireAt: new Date(expireAt),
createdBy: {
_id: 'rocket.cat',
username: 'rocket.cat',
},
});
const now = new Date();

@ -1,19 +0,0 @@
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { Settings } from '../../../models/server';
export function unregisterWorkspace() {
const { workspaceRegistered } = retrieveRegistrationStatus();
if (!workspaceRegistered) {
return true;
}
Settings.updateValueById('Cloud_Workspace_Id', null);
Settings.updateValueById('Cloud_Workspace_Name', null);
Settings.updateValueById('Cloud_Workspace_Client_Id', null);
Settings.updateValueById('Cloud_Workspace_Client_Secret', null);
Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', null);
Settings.updateValueById('Cloud_Workspace_PublicKey', null);
Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', null);
return true;
}

@ -0,0 +1,22 @@
import { Settings } from '@rocket.chat/models';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
export async function unregisterWorkspace() {
const { workspaceRegistered } = retrieveRegistrationStatus();
if (!workspaceRegistered) {
return true;
}
await Promise.all([
Settings.updateValueById('Cloud_Workspace_Id', null),
Settings.updateValueById('Cloud_Workspace_Name', null),
Settings.updateValueById('Cloud_Workspace_Client_Id', null),
Settings.updateValueById('Cloud_Workspace_Client_Secret', null),
Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', null),
Settings.updateValueById('Cloud_Workspace_PublicKey', null),
Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', null),
]);
return true;
}

@ -46,7 +46,7 @@ Meteor.startup(function () {
try {
SystemLogger.info('REG_TOKEN Provided. Attempting to register');
if (!connectWorkspace(process.env.REG_TOKEN)) {
if (!Promise.await(connectWorkspace(process.env.REG_TOKEN))) {
throw new Error("Couldn't register with token. Please make sure token is valid or hasn't already been used");
}

@ -1,7 +1,8 @@
import { Meteor } from 'meteor/meteor';
import { Settings } from '@rocket.chat/models';
import { settings } from '../../../settings/server';
import { Users, Rooms, Settings } from '../../../models/server';
import { Users, Rooms } from '../../../models/server';
import { sendMessage } from '../../../lib';
class ErrorHandler {

@ -12,12 +12,11 @@ import { Match } from 'meteor/check';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import filesize from 'filesize';
import { AppsEngineException } from '@rocket.chat/apps-engine/definition/exceptions';
import { Avatars, UserDataFiles, Uploads } from '@rocket.chat/models';
import { Avatars, UserDataFiles, Uploads, Settings } from '@rocket.chat/models';
import { settings } from '../../../settings/server';
import Users from '../../../models/server/models/Users';
import Rooms from '../../../models/server/models/Rooms';
import Settings from '../../../models/server/models/Settings';
import { mime } from '../../../utils/lib/mimeTypes';
import { hasPermission } from '../../../authorization/server/functions/hasPermission';
import { canAccessRoom } from '../../../authorization/server/functions/canAccessRoom';
@ -32,11 +31,11 @@ import { roomCoordinator } from '../../../../server/lib/rooms/roomCoordinator';
const cookie = new Cookies();
let maxFileSize = 0;
settings.watch('FileUpload_MaxFileSize', function (value) {
settings.watch('FileUpload_MaxFileSize', async function (value) {
try {
maxFileSize = parseInt(value);
} catch (e) {
maxFileSize = Settings.findOneById('FileUpload_MaxFileSize').packageValue;
maxFileSize = await Settings.findOneById('FileUpload_MaxFileSize').packageValue;
}
});

@ -1,7 +1,8 @@
import { Settings } from '@rocket.chat/models';
import { Random } from 'meteor/random';
import { Base, ProgressStep, ImporterWebsocket } from '../../importer/server';
import { Users, Settings as SettingsRaw } from '../../models/server';
import { Users } from '../../models/server';
export class CsvImporter extends Base {
constructor(info, importRecord) {
@ -121,7 +122,7 @@ export class CsvImporter extends Base {
});
}
SettingsRaw.incrementValueById('CSV_Importer_Count', usersCount);
Promise.await(Settings.incrementValueById('CSV_Importer_Count', usersCount));
super.updateRecord({ 'count.users': usersCount });
return increaseProgressCount();
}

@ -3,9 +3,9 @@ import path from 'path';
import fs from 'fs';
import { Meteor } from 'meteor/meteor';
import { Settings } from '@rocket.chat/models';
import { Base, ProgressStep } from '../../importer/server';
import { Settings as SettingsRaw } from '../../models/server';
export class HipChatEnterpriseImporter extends Base {
constructor(info, importRecord) {
@ -53,7 +53,7 @@ export class HipChatEnterpriseImporter extends Base {
this.converter.addUser(newUser);
}
SettingsRaw.incrementValueById('Hipchat_Enterprise_Importer_Count', count);
await Settings.incrementValueById('Hipchat_Enterprise_Importer_Count', count);
super.updateRecord({ 'count.users': count });
super.addCountToTotal(count);
}

@ -1,10 +1,11 @@
import { Meteor } from 'meteor/meteor';
import { Accounts } from 'meteor/accounts-base';
import { Random } from 'meteor/random';
import { Settings } from '@rocket.chat/models';
import { RawImports, Base, ProgressStep, Selection, SelectionUser } from '../../importer/server';
import { RocketChatFile } from '../../file';
import { Users, Settings as SettingsRaw } from '../../models/server';
import { Users } from '../../models/server';
export class SlackUsersImporter extends Base {
constructor(info, importRecord) {
@ -166,7 +167,7 @@ export class SlackUsersImporter extends Base {
});
}
SettingsRaw.incrementValueById('Slack_Users_Importer_Count', this.users.users.length);
Settings.incrementValueById('Slack_Users_Importer_Count', this.users.users.length);
super.updateProgress(ProgressStep.FINISHING);
super.updateProgress(ProgressStep.DONE);
} catch (e) {

@ -1,7 +1,8 @@
import _ from 'underscore';
import { Settings } from '@rocket.chat/models';
import { Base, ProgressStep, ImporterWebsocket } from '../../importer/server';
import { Messages, ImportData, Settings as SettingsRaw } from '../../models/server';
import { Messages, ImportData } from '../../models/server';
import { settings } from '../../settings/server';
import { MentionsParser } from '../../mentions/lib/MentionsParser';
import { getUserAvatarURL } from '../../utils/lib/getUserAvatarURL';
@ -155,7 +156,7 @@ export class SlackImporter extends Base {
}
this.converter.addUser(newUser);
SettingsRaw.incrementValueById('Slack_Importer_Count');
Promise.all(Settings.incrementValueById('Slack_Importer_Count'));
}
}

@ -2,6 +2,7 @@ import http from 'http';
import fs from 'fs';
import https from 'https';
import { Settings } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import AdmZip from 'adm-zip';
import getFileType from 'file-type';
@ -11,7 +12,7 @@ import { ImporterWebsocket } from './ImporterWebsocket';
import { ProgressStep } from '../../lib/ImporterProgressStep';
import { ImporterInfo } from '../../lib/ImporterInfo';
import { RawImports } from '../models/RawImports';
import { Settings, Imports, ImportData } from '../../../models/server';
import { Imports, ImportData } from '../../../models/server';
import { Logger } from '../../../logger';
import { ImportDataConverter } from './ImportDataConverter';
import { t } from '../../../utils/server';
@ -250,29 +251,29 @@ export class Base {
switch (step) {
case ProgressStep.IMPORTING_STARTED:
this.oldSettings.Accounts_AllowedDomainsList = Settings.findOneById('Accounts_AllowedDomainsList').value;
Settings.updateValueById('Accounts_AllowedDomainsList', '');
this.oldSettings.Accounts_AllowedDomainsList = Promise.await(Settings.findOneById('Accounts_AllowedDomainsList')).value;
Promise.await(Settings.updateValueById('Accounts_AllowedDomainsList', ''));
this.oldSettings.Accounts_AllowUsernameChange = Settings.findOneById('Accounts_AllowUsernameChange').value;
Settings.updateValueById('Accounts_AllowUsernameChange', true);
this.oldSettings.Accounts_AllowUsernameChange = Promise.await(Settings.findOneById('Accounts_AllowUsernameChange')).value;
Promise.await(Settings.updateValueById('Accounts_AllowUsernameChange', true));
this.oldSettings.FileUpload_MaxFileSize = Settings.findOneById('FileUpload_MaxFileSize').value;
Settings.updateValueById('FileUpload_MaxFileSize', -1);
this.oldSettings.FileUpload_MaxFileSize = Promise.await(Settings.findOneById('FileUpload_MaxFileSize')).value;
Promise.await(Settings.updateValueById('FileUpload_MaxFileSize', -1));
this.oldSettings.FileUpload_MediaTypeWhiteList = Settings.findOneById('FileUpload_MediaTypeWhiteList').value;
Settings.updateValueById('FileUpload_MediaTypeWhiteList', '*');
this.oldSettings.FileUpload_MediaTypeWhiteList = Promise.await(Settings.findOneById('FileUpload_MediaTypeWhiteList')).value;
Promise.await(Settings.updateValueById('FileUpload_MediaTypeWhiteList', '*'));
this.oldSettings.FileUpload_MediaTypeBlackList = Settings.findOneById('FileUpload_MediaTypeBlackList').value;
Settings.updateValueById('FileUpload_MediaTypeBlackList', '');
this.oldSettings.FileUpload_MediaTypeBlackList = Promise.await(Settings.findOneById('FileUpload_MediaTypeBlackList')).value;
Promise.await(Settings.updateValueById('FileUpload_MediaTypeBlackList', ''));
break;
case ProgressStep.DONE:
case ProgressStep.ERROR:
case ProgressStep.CANCELLED:
Settings.updateValueById('Accounts_AllowedDomainsList', this.oldSettings.Accounts_AllowedDomainsList);
Settings.updateValueById('Accounts_AllowUsernameChange', this.oldSettings.Accounts_AllowUsernameChange);
Settings.updateValueById('FileUpload_MaxFileSize', this.oldSettings.FileUpload_MaxFileSize);
Settings.updateValueById('FileUpload_MediaTypeWhiteList', this.oldSettings.FileUpload_MediaTypeWhiteList);
Settings.updateValueById('FileUpload_MediaTypeBlackList', this.oldSettings.FileUpload_MediaTypeBlackList);
Promise.await(Settings.updateValueById('Accounts_AllowedDomainsList', this.oldSettings.Accounts_AllowedDomainsList));
Promise.await(Settings.updateValueById('Accounts_AllowUsernameChange', this.oldSettings.Accounts_AllowUsernameChange));
Promise.await(Settings.updateValueById('FileUpload_MaxFileSize', this.oldSettings.FileUpload_MaxFileSize));
Promise.await(Settings.updateValueById('FileUpload_MediaTypeWhiteList', this.oldSettings.FileUpload_MediaTypeWhiteList));
Promise.await(Settings.updateValueById('FileUpload_MediaTypeBlackList', this.oldSettings.FileUpload_MediaTypeBlackList));
break;
}

@ -2,12 +2,12 @@ import { Meteor } from 'meteor/meteor';
import Queue from 'queue-fifo';
import moment from 'moment';
import _ from 'underscore';
import { Settings } from '@rocket.chat/models';
import * as peerCommandHandlers from './peerHandlers';
import * as localCommandHandlers from './localHandlers';
import { callbacks } from '../../../../lib/callbacks';
import * as servers from '../servers';
import { Settings } from '../../../models/server';
import { Logger } from '../../../logger/server';
const logger = new Logger('IRC Bridge');
@ -57,7 +57,7 @@ class Bridge {
removed = false;
this.loggedInUsers = [];
const lastPing = Settings.findOneById('IRC_Bridge_Last_Ping');
const lastPing = Promise.await(Settings.findOneById('IRC_Bridge_Last_Ping'));
if (lastPing) {
if (Math.abs(moment(lastPing.value).diff()) < 1000 * 30) {
this.log('Not trying to connect.');

@ -1,27 +1,33 @@
import { Settings } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import { Settings } from '../../../models/server';
import { settings } from '../../../settings/server';
import Bridge from '../irc-bridge';
Meteor.methods({
resetIrcConnection() {
const ircEnabled = Boolean(settings.get('IRC_Enabled'));
Settings.upsert(
Settings.updateOne(
{ _id: 'IRC_Bridge_Last_Ping' },
{
$set: {
value: new Date(0),
},
},
{
upsert: true,
},
);
Settings.upsert(
Settings.updateOne(
{ _id: 'IRC_Bridge_Reset_Time' },
{
$set: {
value: new Date(),
},
},
{
upsert: true,
},
);
if (!ircEnabled) {
@ -47,7 +53,7 @@ Meteor.methods({
peer: settings.get('IRC_Peer_Password'),
},
};
// TODO: is this the best way to do this? is this really necessary?
Meteor.ircBridge = new Bridge(config);
Meteor.ircBridge.init();
}),
@ -60,3 +66,10 @@ Meteor.methods({
};
},
});
declare module 'meteor/meteor' {
// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace Meteor {
export let ircBridge: Bridge;
}
}

@ -1,10 +1,10 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { Settings } from '@rocket.chat/models';
import * as Mailer from '../../../mailer';
import { hasPermission } from '../../../authorization';
import { hasPermission } from '../../../authorization/server';
import { settings } from '../../../settings/server';
import { Settings as SettingsRaw } from '../../../models/server';
let html = '';
Meteor.startup(() => {
@ -14,14 +14,15 @@ Meteor.startup(() => {
});
Meteor.methods({
sendInvitationEmail(emails) {
async sendInvitationEmail(emails) {
check(emails, [String]);
if (!Meteor.userId()) {
const uid = Meteor.userId();
if (!uid) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'sendInvitationEmail',
});
}
if (!hasPermission(Meteor.userId(), 'bulk-register-user')) {
if (!hasPermission(uid, 'bulk-register-user')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'sendInvitationEmail',
});
@ -34,7 +35,13 @@ Meteor.methods({
});
}
const subject = settings.get('Invitation_Subject');
const subject = settings.get<string>('Invitation_Subject');
if (!subject) {
throw new Meteor.Error('error-email-send-failed', 'No subject', {
method: 'sendInvitationEmail',
});
}
return validEmails.filter((email) => {
try {
@ -48,7 +55,7 @@ Meteor.methods({
},
});
SettingsRaw.incrementValueById('Invitation_Email_Count');
Settings.incrementValueById('Invitation_Email_Count');
return mailerResult;
} catch ({ message }) {
throw new Meteor.Error('error-email-send-failed', `Error trying to send email: ${message}`, {

@ -1,21 +1,21 @@
import { Meteor } from 'meteor/meteor';
import filesize from 'filesize';
import { LivechatVisitors } from '@rocket.chat/models';
import { LivechatVisitors, Settings } from '@rocket.chat/models';
import { settings } from '../../../../settings/server';
import { Settings, LivechatRooms } from '../../../../models/server';
import { LivechatRooms } from '../../../../models/server';
import { fileUploadIsValidContentType } from '../../../../utils/server';
import { FileUpload } from '../../../../file-upload';
import { FileUpload } from '../../../../file-upload/server';
import { API } from '../../../../api/server';
import { getUploadFormData } from '../../../../api/server/lib/getUploadFormData';
let maxFileSize;
settings.watch('FileUpload_MaxFileSize', function (value) {
settings.watch('FileUpload_MaxFileSize', async function (value) {
try {
maxFileSize = parseInt(value);
} catch (e) {
maxFileSize = Settings.findOneById('FileUpload_MaxFileSize').packageValue;
maxFileSize = await Settings.findOneById('FileUpload_MaxFileSize').packageValue;
}
});

@ -1,8 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { Match, check } from 'meteor/check';
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import { Settings } from '@rocket.chat/models';
import { Messages, Rooms, Settings } from '../../../../models';
import { Messages, Rooms } from '../../../../models';
import { settings as rcSettings } from '../../../../settings/server';
import { API } from '../../../../api/server';
import { settings } from '../lib/livechat';
@ -16,7 +17,7 @@ API.v1.addRoute(
'livechat/webrtc.call',
{ authRequired: true },
{
get() {
async get() {
try {
check(this.queryParams, {
rid: Match.Maybe(String),
@ -40,7 +41,7 @@ API.v1.addRoute(
throw new Meteor.Error('webRTC calling not enabled');
}
const config = Promise.await(settings());
const config = await settings();
if (!config.theme || !config.theme.actionLinks || !config.theme.actionLinks.webrtc) {
throw new Meteor.Error('invalid-livechat-config');
}
@ -48,19 +49,17 @@ API.v1.addRoute(
let { callStatus } = room;
if (!callStatus || callStatus === 'ended' || callStatus === 'declined') {
Settings.incrementValueById('WebRTC_Calls_Count');
await Settings.incrementValueById('WebRTC_Calls_Count');
callStatus = 'ringing';
Promise.await(Rooms.setCallStatusAndCallStartTime(room._id, callStatus));
Promise.await(
Messages.createWithTypeRoomIdMessageAndUser(
'livechat_webrtc_video_call',
room._id,
TAPi18n.__('Join_my_room_to_start_the_video_call'),
this.user,
{
actionLinks: config.theme.actionLinks.webrtc,
},
),
await Rooms.setCallStatusAndCallStartTime(room._id, callStatus);
await Messages.createWithTypeRoomIdMessageAndUser(
'livechat_webrtc_video_call',
room._id,
TAPi18n.__('Join_my_room_to_start_the_video_call'),
this.user,
{
actionLinks: config.theme.actionLinks.webrtc,
},
);
}
const videoCall = {

@ -9,7 +9,7 @@ import _ from 'underscore';
import s from 'underscore.string';
import moment from 'moment-timezone';
import UAParser from 'ua-parser-js';
import { Users as UsersRaw, LivechatVisitors } from '@rocket.chat/models';
import { Users as UsersRaw, LivechatVisitors, Settings } from '@rocket.chat/models';
import { QueueManager } from './QueueManager';
import { RoutingManager } from './RoutingManager';
@ -22,7 +22,6 @@ import {
LivechatRooms,
Messages,
Subscriptions,
Settings,
Rooms,
LivechatDepartmentAgents,
LivechatDepartment,
@ -538,39 +537,41 @@ export const Livechat = {
getInitSettings() {
const rcSettings = {};
Settings.findNotHiddenPublic([
'Livechat_title',
'Livechat_title_color',
'Livechat_enable_message_character_limit',
'Livechat_message_character_limit',
'Message_MaxAllowedSize',
'Livechat_enabled',
'Livechat_registration_form',
'Livechat_allow_switching_departments',
'Livechat_offline_title',
'Livechat_offline_title_color',
'Livechat_offline_message',
'Livechat_offline_success_message',
'Livechat_offline_form_unavailable',
'Livechat_display_offline_form',
'Omnichannel_call_provider',
'Language',
'Livechat_enable_transcript',
'Livechat_transcript_message',
'Livechat_fileupload_enabled',
'FileUpload_Enabled',
'Livechat_conversation_finished_message',
'Livechat_conversation_finished_text',
'Livechat_name_field_registration_form',
'Livechat_email_field_registration_form',
'Livechat_registration_form_message',
'Livechat_force_accept_data_processing_consent',
'Livechat_data_processing_consent_text',
'Livechat_show_agent_info',
'Livechat_clear_local_storage_when_chat_ended',
]).forEach((setting) => {
rcSettings[setting._id] = setting.value;
});
Promise.await(
Settings.findNotHiddenPublic([
'Livechat_title',
'Livechat_title_color',
'Livechat_enable_message_character_limit',
'Livechat_message_character_limit',
'Message_MaxAllowedSize',
'Livechat_enabled',
'Livechat_registration_form',
'Livechat_allow_switching_departments',
'Livechat_offline_title',
'Livechat_offline_title_color',
'Livechat_offline_message',
'Livechat_offline_success_message',
'Livechat_offline_form_unavailable',
'Livechat_display_offline_form',
'Omnichannel_call_provider',
'Language',
'Livechat_enable_transcript',
'Livechat_transcript_message',
'Livechat_fileupload_enabled',
'FileUpload_Enabled',
'Livechat_conversation_finished_message',
'Livechat_conversation_finished_text',
'Livechat_name_field_registration_form',
'Livechat_email_field_registration_form',
'Livechat_registration_form_message',
'Livechat_force_accept_data_processing_consent',
'Livechat_data_processing_consent_text',
'Livechat_show_agent_info',
'Livechat_clear_local_storage_when_chat_ended',
]).forEach((setting) => {
rcSettings[setting._id] = setting.value;
}),
);
rcSettings.Livechat_history_monitor_type = settings.get('Livechat_history_monitor_type');

@ -1,10 +1,10 @@
import { Meteor } from 'meteor/meteor';
import { Settings } from '@rocket.chat/models';
import { hasPermission } from '../../../authorization';
import { SystemLogger } from '../../../../server/lib/logger/system';
import { settings } from '../../../settings/server';
import OmniChannel from '../lib/OmniChannel';
import { Settings } from '../../../models/server';
Meteor.methods({
'livechat:facebook'(options) {

@ -1,11 +1,12 @@
import { Meteor } from 'meteor/meteor';
import { Settings } from '@rocket.chat/models';
import { hasPermission } from '../../../authorization';
import { Settings } from '../../../models/server';
import { hasPermission } from '../../../authorization/server';
Meteor.methods({
'livechat:saveAppearance'(settings) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'view-livechat-manager')) {
async 'livechat:saveAppearance'(settings: { _id: string; value: any }[]) {
const uid = Meteor.userId();
if (!uid || !hasPermission(uid, 'view-livechat-manager')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'livechat:saveAppearance',
});
@ -39,8 +40,10 @@ Meteor.methods({
throw new Meteor.Error('invalid-setting');
}
settings.forEach((setting) => {
Settings.updateValueById(setting._id, setting.value);
});
await Promise.all(
settings.map((setting) => {
return Settings.updateValueById(setting._id, setting.value);
}),
);
},
});

@ -1,55 +0,0 @@
import { Meteor } from 'meteor/meteor';
import s from 'underscore.string';
import { hasPermission } from '../../../authorization';
import { Settings } from '../../../models/server';
Meteor.methods({
'livechat:saveIntegration'(values) {
if (!Meteor.userId() || !hasPermission(Meteor.userId(), 'view-livechat-manager')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'livechat:saveIntegration',
});
}
if (typeof values.Livechat_webhookUrl !== 'undefined') {
Settings.updateValueById('Livechat_webhookUrl', s.trim(values.Livechat_webhookUrl));
}
if (typeof values.Livechat_secret_token !== 'undefined') {
Settings.updateValueById('Livechat_secret_token', s.trim(values.Livechat_secret_token));
}
if (typeof values.Livechat_webhook_on_start !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_start', !!values.Livechat_webhook_on_start);
}
if (typeof values.Livechat_webhook_on_close !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_close', !!values.Livechat_webhook_on_close);
}
if (typeof values.Livechat_webhook_on_chat_taken !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_chat_taken', !!values.Livechat_webhook_on_chat_taken);
}
if (typeof values.Livechat_webhook_on_chat_queued !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_chat_queued', !!values.Livechat_webhook_on_chat_queued);
}
if (typeof values.Livechat_webhook_on_forward !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_forward', !!values.Livechat_webhook_on_forward);
}
if (typeof values.Livechat_webhook_on_offline_msg !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_offline_msg', !!values.Livechat_webhook_on_offline_msg);
}
if (typeof values.Livechat_webhook_on_visitor_message !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_visitor_message', !!values.Livechat_webhook_on_visitor_message);
}
if (typeof values.Livechat_webhook_on_agent_message !== 'undefined') {
Settings.updateValueById('Livechat_webhook_on_agent_message', !!values.Livechat_webhook_on_agent_message);
}
},
});

@ -0,0 +1,56 @@
import { Settings } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import s from 'underscore.string';
import { hasPermission } from '../../../authorization/server';
Meteor.methods({
async 'livechat:saveIntegration'(values) {
const uid = Meteor.userId();
if (!uid || !hasPermission(uid, 'view-livechat-manager')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed', {
method: 'livechat:saveIntegration',
});
}
if (typeof values.Livechat_webhookUrl !== 'undefined') {
await Settings.updateValueById('Livechat_webhookUrl', s.trim(values.Livechat_webhookUrl));
}
if (typeof values.Livechat_secret_token !== 'undefined') {
await Settings.updateValueById('Livechat_secret_token', s.trim(values.Livechat_secret_token));
}
if (typeof values.Livechat_webhook_on_start !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_start', !!values.Livechat_webhook_on_start);
}
if (typeof values.Livechat_webhook_on_close !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_close', !!values.Livechat_webhook_on_close);
}
if (typeof values.Livechat_webhook_on_chat_taken !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_chat_taken', !!values.Livechat_webhook_on_chat_taken);
}
if (typeof values.Livechat_webhook_on_chat_queued !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_chat_queued', !!values.Livechat_webhook_on_chat_queued);
}
if (typeof values.Livechat_webhook_on_forward !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_forward', !!values.Livechat_webhook_on_forward);
}
if (typeof values.Livechat_webhook_on_offline_msg !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_offline_msg', !!values.Livechat_webhook_on_offline_msg);
}
if (typeof values.Livechat_webhook_on_visitor_message !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_visitor_message', !!values.Livechat_webhook_on_visitor_message);
}
if (typeof values.Livechat_webhook_on_agent_message !== 'undefined') {
await Settings.updateValueById('Livechat_webhook_on_agent_message', !!values.Livechat_webhook_on_agent_message);
}
},
});

@ -7,9 +7,9 @@ import juice from 'juice';
import stripHtml from 'string-strip-html';
import { escapeHTML } from '@rocket.chat/string-helpers';
import type { ISetting } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
import { settings } from '../../settings/server';
import { Settings as SettingsRaw } from '../../models/server';
import { replaceVariables } from './replaceVariables';
import { Apps } from '../../apps/server';
import { validateEmail } from '../../../lib/emailValidator';
@ -165,7 +165,7 @@ export const sendNoWrap = ({
html = undefined;
}
SettingsRaw.incrementValueById('Triggered_Emails_Count');
Settings.incrementValueById('Triggered_Emails_Count');
const email = { to, from, replyTo, subject, html, text, headers };

@ -2,7 +2,6 @@ import { Base } from './models/_Base';
import { BaseDb } from './models/_BaseDb';
import Messages from './models/Messages';
import Rooms from './models/Rooms';
import Settings from './models/Settings';
import Subscriptions from './models/Subscriptions';
import Users from './models/Users';
import Imports from './models/Imports';
@ -25,7 +24,6 @@ export {
BaseDb,
Messages,
Rooms,
Settings,
Subscriptions,
Users,
Imports,

@ -1,280 +0,0 @@
import { Base } from './_Base';
export class Settings extends Base {
constructor(...args) {
super(...args);
this.tryEnsureIndex({ blocked: 1 }, { sparse: 1 });
this.tryEnsureIndex({ hidden: 1 }, { sparse: 1 });
}
// FIND
findById(_id) {
const query = { _id };
return this.find(query);
}
findOneNotHiddenById(_id) {
const query = {
_id,
hidden: { $ne: true },
};
return this.findOne(query);
}
findByIds(_id = []) {
_id = [].concat(_id);
const query = {
_id: {
$in: _id,
},
};
return this.find(query);
}
findPublic(options) {
const query = { public: true };
return this.find(query, options);
}
findNotHiddenPublic(ids = []) {
const filter = {
hidden: { $ne: true },
public: true,
};
if (ids.length > 0) {
filter._id = { $in: ids };
}
return this.find(filter, {
fields: {
_id: 1,
value: 1,
editor: 1,
enterprise: 1,
invalidValue: 1,
modules: 1,
requiredOnWizard: 1,
},
});
}
findNotHiddenPublicUpdatedAfter(updatedAt) {
const filter = {
hidden: { $ne: true },
public: true,
_updatedAt: {
$gt: updatedAt,
},
};
return this.find(filter, {
fields: {
_id: 1,
value: 1,
editor: 1,
enterprise: 1,
invalidValue: 1,
modules: 1,
requiredOnWizard: 1,
},
});
}
findNotHiddenPrivate() {
return this.find({
hidden: { $ne: true },
public: { $ne: true },
});
}
findNotHidden({ updatedAfter, ...options } = {}) {
const query = {
hidden: { $ne: true },
};
if (updatedAfter) {
query._updatedAt = { $gt: updatedAfter };
}
return this.find(query, options);
}
findNotHiddenUpdatedAfter(updatedAt) {
return this.find({
hidden: { $ne: true },
_updatedAt: {
$gt: updatedAt,
},
});
}
findSetupWizardSettings() {
return this.find({ wizard: { $exists: true, $ne: null } });
}
findEnterpriseSettings() {
return this.find({ enterprise: true });
}
// UPDATE
updateValueById(_id, value) {
const query = {
blocked: { $ne: true },
value: { $ne: value },
_id,
};
const update = {
$set: {
value,
},
};
return this.update(query, update);
}
incrementValueById(_id, value = 1) {
const query = {
blocked: { $ne: true },
_id,
};
const update = {
$inc: {
value,
},
};
return this.update(query, update);
}
updateValueAndEditorById(_id, value, editor) {
const query = {
blocked: { $ne: true },
value: { $ne: value },
_id,
};
const update = {
$set: {
value,
editor,
},
};
return this.update(query, update);
}
updateValueNotHiddenById(_id, value) {
const query = {
_id,
hidden: { $ne: true },
blocked: { $ne: true },
};
const update = {
$set: {
value,
},
};
return this.update(query, update);
}
updateOptionsById(_id, options) {
const query = {
blocked: { $ne: true },
_id,
};
const update = { $set: options };
return this.update(query, update);
}
addOptionValueById(_id, option = {}) {
const query = {
blocked: { $ne: true },
_id,
};
const { key, i18nLabel } = option;
const update = {
$addToSet: {
values: {
key,
i18nLabel,
},
},
};
return this.update(query, update);
}
removeOptionValueByIdAndKey(_id, key) {
const query = {
blocked: { $ne: true },
_id,
};
const update = {
$pull: {
values: { key },
},
};
return this.update(query, update);
}
// INSERT
createWithIdAndValue(_id, value) {
const record = {
_id,
value,
_createdAt: new Date(),
};
return this.insert(record);
}
// REMOVE
removeById(_id) {
const query = {
blocked: { $ne: true },
_id,
};
return this.remove(query);
}
// RENAME SETTING
renameSetting(oldId, newId) {
const oldSetting = this.findById(oldId).fetch()[0];
if (oldSetting) {
this.removeById(oldSetting._id);
// there has been some problem with upsert() when changing the complete doc, so decide explicitly for insert or update
let newSetting = this.findById(newId).fetch()[0];
if (newSetting) {
this.updateValueById(newId, oldSetting.value);
} else {
newSetting = oldSetting;
newSetting._id = newId;
delete newSetting.$loki;
this.insert(newSetting);
}
}
}
insert(record, ...args) {
return super.insert({ createdAt: new Date(), ...record }, ...args);
}
}
export default new Settings('settings', true);

@ -13,7 +13,10 @@ type SettingsConfig = {
type OverCustomSettingsConfig = Partial<SettingsConfig>;
export interface ICachedSettings {
initilized(): void;
/*
* @description: The settings object as ready
*/
initialized(): void;
has(_id: ISetting['_id']): boolean;
@ -89,13 +92,13 @@ export class CachedSettings
/**
* The settings object as ready
*/
initilized(): void {
initialized(): void {
if (this.ready) {
return;
}
this.ready = true;
this.emit('ready');
SystemLogger.debug('Settings initalized');
SystemLogger.debug('Settings initialized');
}
/**

@ -1,8 +1,9 @@
import { Emitter } from '@rocket.chat/emitter';
import { isEqual } from 'underscore';
import { ISetting, ISettingGroup, isSettingEnterprise, SettingValue } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
import type { ISettingsModel } from '@rocket.chat/model-typings';
import type SettingsModel from '../../models/server/models/Settings';
import { SystemLogger } from '../../../server/lib/logger/system';
import { overwriteSetting } from './functions/overwriteSetting';
import { overrideSetting } from './functions/overrideSetting';
@ -83,13 +84,13 @@ const compareSettings = compareSettingsIgnoringKeys([
]);
export class SettingsRegistry {
private model: typeof SettingsModel;
private model: ISettingsModel;
private store: ICachedSettings;
private _sorter: { [key: string]: number } = {};
constructor({ store, model }: { store: ICachedSettings; model: typeof SettingsModel }) {
constructor({ store, model }: { store: ICachedSettings; model: typeof Settings }) {
this.store = store;
this.model = model;
}
@ -97,7 +98,7 @@ export class SettingsRegistry {
/*
* Add a setting
*/
add(_id: string, value: SettingValue, { sorter, section, group, ...options }: ISettingAddOptions = {}): void {
async add(_id: string, value: SettingValue, { sorter, section, group, ...options }: ISettingAddOptions = {}): Promise<void> {
if (!_id || value == null) {
throw new Error('Invalid arguments');
}
@ -156,7 +157,7 @@ export class SettingsRegistry {
const overwrittenKeys = Object.keys(settingFromCodeOverwritten);
const removedKeys = Object.keys(settingStored).filter((key) => !['_updatedAt'].includes(key) && !overwrittenKeys.includes(key));
this.model.upsert(
await this.model.updateOne(
{ _id },
{
$set: { ...settingOverwrittenProps },
@ -164,6 +165,7 @@ export class SettingsRegistry {
$unset: removedKeys.reduce((unset, key) => ({ ...unset, [key]: 1 }), {}),
}),
},
{ upsert: true },
);
return;
@ -171,7 +173,7 @@ export class SettingsRegistry {
if (settingStored && isOverwritten) {
if (settingStored.value !== settingFromCodeOverwritten.value) {
this.model.upsert({ _id }, settingProps);
await this.model.updateOne({ _id }, settingProps, { upsert: true });
}
return;
}
@ -189,7 +191,7 @@ export class SettingsRegistry {
const setting = isOverwritten ? settingFromCodeOverwritten : settingOverwrittenDefault;
this.model.insert(setting); // no need to emit unless we remove the oplog
await this.model.insertOne(setting); // no need to emit unless we remove the oplog
this.store.set(setting);
}
@ -197,10 +199,10 @@ export class SettingsRegistry {
/*
* Add a setting group
*/
addGroup(_id: string, cb: addGroupCallback): void;
async addGroup(_id: string, cb: addGroupCallback): Promise<void>;
// eslint-disable-next-line no-dupe-class-members
addGroup(_id: string, groupOptions: ISettingAddGroupOptions | addGroupCallback = {}, cb?: addGroupCallback): void {
async addGroup(_id: string, groupOptions: ISettingAddGroupOptions | addGroupCallback = {}, cb?: addGroupCallback): Promise<void> {
if (!_id || (groupOptions instanceof Function && cb)) {
throw new Error('Invalid arguments');
}
@ -214,7 +216,7 @@ export class SettingsRegistry {
if (!this.store.has(_id)) {
options.ts = new Date();
this.model.insert(options);
await this.model.insertOne(options as ISetting);
this.store.set(options as ISetting);
}

@ -34,14 +34,14 @@ class SettingsClass {
return [...this.data.values()].find((data) => Object.entries(query).every(([key, value]) => this.checkQueryMatch(key, data, value)));
}
insert(doc: any): void {
insertOne(doc: any): void {
this.data.set(doc._id, doc);
// eslint-disable-next-line @typescript-eslint/no-var-requires
this.settings.set(doc);
this.insertCalls++;
}
upsert(query: any, update: any): void {
updateOne(query: any, update: any): void {
const existent = this.findOne(query);
const data = { ...existent, ...query, ...update, ...update.$set };
@ -71,4 +71,4 @@ class SettingsClass {
export const Settings = new SettingsClass();
mock('../../../models/server/models/Settings', Settings);
mock('@rocket.chat/models', { Settings });

@ -1,13 +1,23 @@
import SettingsModel from '../../models/server/models/Settings';
import { Settings } from '@rocket.chat/models';
import { SettingsRegistry } from './SettingsRegistry';
import { initializeSettings } from './startup';
import { settings } from './cached';
import './applyMiddlewares';
import { use } from './Middleware';
export { SettingsEvents } from './SettingsRegistry';
export { settings };
export const settingsRegistry = new SettingsRegistry({ store: settings, model: SettingsModel });
export const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings });
settingsRegistry.add = use(settingsRegistry.add, (context, next) => {
return Promise.await(next(...context)) as any;
});
settingsRegistry.addGroup = use(settingsRegistry.addGroup, (context, next) => {
return Promise.await(next(...context)) as any;
});
initializeSettings({ SettingsModel, settings });
Promise.await(initializeSettings({ model: Settings, settings }));

@ -1,31 +0,0 @@
import Settings from '../../models/server/models/Settings';
const cache = new Map();
export const setValue = (_id, value) => cache.set(_id, value);
const setFromDB = async (_id) => {
const setting = Settings.findOneById(_id, { fields: { value: 1 } });
if (!setting) {
return;
}
setValue(_id, setting.value);
return setting.value;
};
export const getValue = async (_id) => {
if (!cache.has(_id)) {
return setFromDB(_id);
}
return cache.get(_id);
};
export const updateValue = (id, fields) => {
if (typeof fields.value === 'undefined') {
return;
}
setValue(id, fields.value);
};

@ -0,0 +1,32 @@
import { SettingValue } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
const cache = new Map();
export const setValue = (_id: string, value: SettingValue) => cache.set(_id, value);
const setFromDB = async (_id: string) => {
const setting = await Settings.findOneById(_id, { projection: { value: 1 } });
if (!setting) {
return;
}
setValue(_id, setting.value);
return setting.value;
};
export const getValue = async (_id: string) => {
if (!cache.has(_id)) {
return setFromDB(_id);
}
return cache.get(_id);
};
export const updateValue = <T extends { value: SettingValue }>(id: string, fields: T) => {
if (typeof fields.value === 'undefined') {
return;
}
setValue(id, fields.value);
};

@ -1,13 +1,13 @@
import type { ISetting } from '@rocket.chat/core-typings';
import type { Settings } from '@rocket.chat/models';
import { Settings } from '../../models/server/models/Settings';
import { ICachedSettings } from './CachedSettings';
// eslint-disable-next-line @typescript-eslint/naming-convention
export function initializeSettings({ SettingsModel, settings }: { SettingsModel: Settings; settings: ICachedSettings }): void {
SettingsModel.find().forEach((record: ISetting) => {
export async function initializeSettings({ model, settings }: { model: typeof Settings; settings: ICachedSettings }): Promise<void> {
await model.find().forEach((record: ISetting) => {
settings.set(record);
});
settings.initilized();
settings.initialized();
}

@ -1,4 +1,5 @@
import { Settings } from '../../../models/server';
import { Settings } from '@rocket.chat/models';
import telemetryEvent from '../lib/telemetryEvents';
type updateCounterDataType = { settingsId: string };

@ -21,9 +21,10 @@ import {
Messages as MessagesRaw,
Roles as RolesRaw,
InstanceStatus,
Settings,
} from '@rocket.chat/models';
import { Settings, Users, Rooms, Subscriptions, Messages } from '../../../models/server';
import { Users, Rooms, Subscriptions, Messages } from '../../../models/server';
import { settings } from '../../../settings/server';
import { Info, getMongoInfo } from '../../../utils/server';
import { getControl } from '../../../../server/lib/migrations';
@ -67,18 +68,21 @@ export const statistics = {
// Setup Wizard
statistics.wizard = {};
wizardFields.forEach((field) => {
const record = Settings.findOne(field);
if (record) {
const wizardField = field.replace(/_/g, '').replace(field[0], field[0].toLowerCase());
statistics.wizard[wizardField] = record.value;
}
});
await Promise.all(
wizardFields.map(async (field) => {
const record = await Settings.findOne(field);
if (record) {
const wizardField = field.replace(/_/g, '').replace(field[0], field[0].toLowerCase());
statistics.wizard[wizardField] = record.value;
}
}),
);
// Version
const uniqueID = await Settings.findOne('uniqueID');
statistics.uniqueId = settings.get('uniqueID');
if (Settings.findOne('uniqueID')) {
statistics.installedAt = Settings.findOne('uniqueID').createdAt;
if (uniqueID) {
statistics.installedAt = String(uniqueID.createdAt);
}
if (Info) {
@ -453,6 +457,8 @@ export const statistics = {
statsPms.push(Analytics.resetSeatRequestCount());
// TODO: Is that the best way to do this? maybe we should use a promise.all()
statistics.dashboardCount = settings.get('Engagement_Dashboard_Load_Count');
statistics.messageAuditApply = settings.get('Message_Auditing_Apply_Count');
statistics.messageAuditLoad = settings.get('Message_Auditing_Panel_Load_Count');
@ -483,22 +489,22 @@ export const statistics = {
statistics.matrixBridgeEnabled = settings.get('Federation_Matrix_enabled');
statistics.uncaughtExceptionsCount = settings.get('Uncaught_Exceptions_Count');
const defaultHomeTitle = Settings.findOneById('Layout_Home_Title').packageValue;
const defaultHomeTitle = (await Settings.findOneById('Layout_Home_Title'))?.packageValue;
statistics.homeTitleChanged = settings.get('Layout_Home_Title') !== defaultHomeTitle;
const defaultHomeBody = Settings.findOneById('Layout_Home_Body').packageValue;
const defaultHomeBody = (await Settings.findOneById('Layout_Home_Body'))?.packageValue;
statistics.homeBodyChanged = settings.get('Layout_Home_Body') !== defaultHomeBody;
const defaultCustomCSS = Settings.findOneById('theme-custom-css').packageValue;
const defaultCustomCSS = (await Settings.findOneById('theme-custom-css'))?.packageValue;
statistics.customCSSChanged = settings.get('theme-custom-css') !== defaultCustomCSS;
const defaultOnLogoutCustomScript = Settings.findOneById('Custom_Script_On_Logout').packageValue;
const defaultOnLogoutCustomScript = (await Settings.findOneById('Custom_Script_On_Logout'))?.packageValue;
statistics.onLogoutCustomScriptChanged = settings.get('Custom_Script_On_Logout') !== defaultOnLogoutCustomScript;
const defaultLoggedOutCustomScript = Settings.findOneById('Custom_Script_Logged_Out').packageValue;
const defaultLoggedOutCustomScript = (await Settings.findOneById('Custom_Script_Logged_Out'))?.packageValue;
statistics.loggedOutCustomScriptChanged = settings.get('Custom_Script_Logged_Out') !== defaultLoggedOutCustomScript;
const defaultLoggedInCustomScript = Settings.findOneById('Custom_Script_Logged_In').packageValue;
const defaultLoggedInCustomScript = (await Settings.findOneById('Custom_Script_Logged_In'))?.packageValue;
statistics.loggedInCustomScriptChanged = settings.get('Custom_Script_Logged_In') !== defaultLoggedInCustomScript;
await Promise.all(statsPms).catch(log);

@ -5,11 +5,11 @@ import less from 'less';
import Autoprefixer from 'less-plugin-autoprefixer';
import { WebApp } from 'meteor/webapp';
import { Meteor } from 'meteor/meteor';
import { Settings } from '@rocket.chat/models';
import { settings, settingsRegistry } from '../../settings/server';
import { Logger } from '../../logger';
import { addStyle } from '../../ui-master/server/inject';
import { Settings } from '../../models/server';
const logger = new Logger('rocketchat:theme');

@ -2,11 +2,12 @@ import { Meteor } from 'meteor/meteor';
import { Inject } from 'meteor/meteorhacks:inject-initial';
import { Tracker } from 'meteor/tracker';
import _ from 'underscore';
import { Settings } from '@rocket.chat/models';
import { escapeHTML } from '@rocket.chat/string-helpers';
import { Settings } from '../../models/server';
import { settings } from '../../settings/server';
import { applyHeadInjections, headInjections, injectIntoBody, injectIntoHead } from './inject';
import './scripts';
export * from './inject';
@ -124,16 +125,11 @@ Meteor.startup(() => {
});
const renderDynamicCssList = _.debounce(
Meteor.bindEnvironment(() => {
Meteor.bindEnvironment(async () => {
// const variables = RocketChat.models.Settings.findOne({_id:'theme-custom-variables'}, {fields: { value: 1}});
const colors = Settings.find({ _id: /theme-color-rc/i }, { fields: { value: 1, editor: 1 } })
.fetch()
.filter((color) => color && color.value);
if (!colors) {
return;
}
const colors = await Settings.find({ _id: /theme-color-rc/i }, { projection: { value: 1, editor: 1 } }).toArray();
const css = colors
.filter((color) => color && color.value)
.map(({ _id, value, editor }) => {
if (editor === 'expression') {
return `--${_id.replace('theme-color-', '')}: var(--${value});`;

@ -1,93 +0,0 @@
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import semver from 'semver';
import getNewUpdates from './getNewUpdates';
import { settings } from '../../../settings/server';
import { Info } from '../../../utils';
import { Users, Settings } from '../../../models/server';
import logger from '../logger';
import { sendMessagesToAdmins } from '../../../../server/lib/sendMessagesToAdmins';
// import getNewUpdates from '../sampleUpdateData';
export default () => {
logger.info('Checking for version updates');
const { versions, alerts } = getNewUpdates();
const update = {
exists: false,
lastestVersion: null,
security: false,
};
const lastCheckedVersion = settings.get('Update_LatestAvailableVersion');
versions.forEach((version) => {
if (semver.lte(version.version, lastCheckedVersion)) {
return;
}
if (semver.lte(version.version, Info.version)) {
return;
}
update.exists = true;
update.lastestVersion = version;
if (version.security === true) {
update.security = true;
}
});
if (update.exists) {
Settings.updateValueById('Update_LatestAvailableVersion', update.lastestVersion.version);
Promise.await(
sendMessagesToAdmins({
msgs: ({ adminUser }) => [
{
msg: `*${TAPi18n.__('Update_your_RocketChat', adminUser.language)}*\n${TAPi18n.__(
'New_version_available_(s)',
update.lastestVersion.version,
adminUser.language,
)}\n${update.lastestVersion.infoUrl}`,
},
],
banners: [
{
id: `versionUpdate-${update.lastestVersion.version}`.replace(/\./g, '_'),
priority: 10,
title: 'Update_your_RocketChat',
text: 'New_version_available_(s)',
textArguments: [update.lastestVersion.version],
link: update.lastestVersion.infoUrl,
},
],
}),
);
}
if (alerts && alerts.length) {
Promise.await(
sendMessagesToAdmins({
msgs: ({ adminUser }) =>
alerts
.filter((alert) => !Users.bannerExistsById(adminUser._id, `alert-${alert.id}`))
.map((alert) => ({
msg: `*${TAPi18n.__('Rocket_Chat_Alert', adminUser.language)}:*\n\n*${TAPi18n.__(
alert.title,
adminUser.language,
)}*\n${TAPi18n.__(alert.text, ...(alert.textArguments || []), adminUser.language)}\n${alert.infoUrl}`,
})),
banners: alerts.map((alert) => ({
id: `alert-${alert.id}`.replace(/\./g, '_'),
priority: 10,
title: alert.title,
text: alert.text,
textArguments: alert.textArguments,
modifiers: alert.modifiers,
link: alert.infoUrl,
})),
}),
);
}
};

@ -0,0 +1,90 @@
import { TAPi18n } from 'meteor/rocketchat:tap-i18n';
import semver from 'semver';
import { Settings } from '@rocket.chat/models';
import { getNewUpdates } from './getNewUpdates';
import { settings } from '../../../settings/server';
import { Info } from '../../../utils/server';
import { Users } from '../../../models/server';
import logger from '../logger';
import { sendMessagesToAdmins } from '../../../../server/lib/sendMessagesToAdmins';
// import getNewUpdates from '../sampleUpdateData';
export const checkVersionUpdate = async () => {
logger.info('Checking for version updates');
const { versions, alerts } = await getNewUpdates();
const lastCheckedVersion = settings.get<string>('Update_LatestAvailableVersion');
for await (const version of versions) {
if (!lastCheckedVersion) {
break;
}
if (semver.lte(version.version, lastCheckedVersion)) {
continue;
}
if (semver.lte(version.version, Info.version)) {
continue;
}
await Settings.updateValueById('Update_LatestAvailableVersion', version.version);
await sendMessagesToAdmins({
msgs: ({ adminUser }) => [
{
msg: `*${TAPi18n.__('Update_your_RocketChat', { ...(adminUser.language && { lng: adminUser.language }) })}*\n${TAPi18n.__(
'New_version_available_(s)',
{
postProcess: 'sprintf',
sprintf: [version.version],
},
)}\n${version.infoUrl}`,
},
],
banners: [
{
id: `versionUpdate-${version.version}`.replace(/\./g, '_'),
priority: 10,
title: 'Update_your_RocketChat',
text: 'New_version_available_(s)',
textArguments: [version.version],
link: version.infoUrl,
modifiers: [],
},
],
});
break;
}
if (alerts && alerts.length) {
await sendMessagesToAdmins({
msgs: ({ adminUser }) =>
alerts
.filter((alert) => !Users.bannerExistsById(adminUser._id, `alert-${alert.id}`))
.map((alert) => ({
msg: `*${TAPi18n.__('Rocket_Chat_Alert', { ...(adminUser.language && { lng: adminUser.language }) })}:*\n\n*${TAPi18n.__(
alert.title,
{ ...(adminUser.language && { lng: adminUser.language }) },
)}*\n${TAPi18n.__(alert.text, {
...(adminUser.language && { lng: adminUser.language }),
...(Array.isArray(alert.textArguments) && {
postProcess: 'sprintf',
sprintf: alert.textArguments,
}),
...((!Array.isArray(alert.textArguments) && alert.textArguments) || {}), // bien dormido
})}\n${alert.infoUrl}`,
})),
banners: alerts.map((alert) => ({
id: `alert-${alert.id}`.replace(/\./g, '_'),
priority: 10,
title: alert.title,
text: alert.text,
textArguments: alert.textArguments,
modifiers: alert.modifiers,
link: alert.infoUrl,
})),
});
}
};

@ -1,72 +0,0 @@
import os from 'os';
import { HTTP } from 'meteor/http';
import { check, Match } from 'meteor/check';
import { Settings } from '../../../models/server';
import { Info } from '../../../utils';
import { getWorkspaceAccessToken } from '../../../cloud/server';
export default () => {
try {
const uniqueID = Settings.findOne('uniqueID');
const params = {
uniqueId: uniqueID.value,
installedAt: uniqueID.createdAt.toJSON(),
version: Info.version,
osType: os.type(),
osPlatform: os.platform(),
osArch: os.arch(),
osRelease: os.release(),
nodeVersion: process.version,
deployMethod: process.env.DEPLOY_METHOD || 'tar',
deployPlatform: process.env.DEPLOY_PLATFORM || 'selfinstall',
};
const headers = {};
const token = getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
const { data } = HTTP.get('https://releases.rocket.chat/updates/check', {
params,
headers,
});
check(
data,
Match.ObjectIncluding({
versions: [
Match.ObjectIncluding({
version: Match.Optional(String),
security: Match.Optional(Boolean),
infoUrl: Match.Optional(String),
}),
],
alerts: Match.Optional([
Match.ObjectIncluding({
id: Match.Optional(String),
title: Match.Optional(String),
text: Match.Optional(String),
textArguments: Match.Optional([Match.Any]),
modifiers: Match.Optional([String]),
infoUrl: Match.Optional(String),
}),
]),
}),
);
return data;
} catch (error) {
// There's no need to log this error
// as it's pointless and the user
// can't do anything about it anyways
return {
versions: [],
alerts: [],
};
}
};

@ -0,0 +1,93 @@
import os from 'os';
import { Settings } from '@rocket.chat/models';
import { HTTP } from 'meteor/http';
import { check, Match } from 'meteor/check';
import { Info } from '../../../utils/server';
import { getWorkspaceAccessToken } from '../../../cloud/server';
export const getNewUpdates = async () => {
try {
const uniqueID = await Settings.findOne('uniqueID');
if (!uniqueID) {
throw new Error('uniqueID not found');
}
const params = {
uniqueId: String(uniqueID.value),
installedAt: uniqueID.createdAt.toJSON(),
version: Info.version,
osType: os.type(),
osPlatform: os.platform(),
osArch: os.arch(),
osRelease: os.release(),
nodeVersion: process.version,
deployMethod: process.env.DEPLOY_METHOD || 'tar',
deployPlatform: process.env.DEPLOY_PLATFORM || 'selfinstall',
};
const token = await getWorkspaceAccessToken();
const headers = {
...(token && { Authorization: `Bearer ${token}` }),
};
const { data } = HTTP.get('https://releases.rocket.chat/updates/check', {
params,
headers,
});
check(
data,
Match.ObjectIncluding({
versions: [
Match.ObjectIncluding({
version: String,
security: Match.Optional(Boolean),
infoUrl: String,
}),
],
alerts: [
Match.Optional([
Match.ObjectIncluding({
id: String,
title: String,
text: String,
textArguments: [Match.Any],
modifiers: [String],
infoUrl: String,
}),
]),
],
}),
);
return data as {
versions: {
version: string;
security: boolean;
infoUrl: string;
}[];
alerts: {
id: string;
priority: number;
title: string;
text: string;
textArguments?: string[];
modifiers: string[];
infoUrl: string;
}[];
};
} catch (error) {
// There's no need to log this error
// as it's pointless and the user
// can't do anything about it anyways
return {
versions: [],
alerts: [],
};
}
};

@ -2,7 +2,7 @@ import { Meteor } from 'meteor/meteor';
import { SyncedCron } from 'meteor/littledata:synced-cron';
import { settings } from '../../settings/server';
import checkVersionUpdate from './functions/checkVersionUpdate';
import { checkVersionUpdate } from './functions/checkVersionUpdate';
import './methods/banner_dismiss';
import './addSettings';
@ -17,7 +17,7 @@ const addVersionCheckJob = Meteor.bindEnvironment(() => {
name: jobName,
schedule: (parser: { text: (time: string) => string }) => parser.text('at 2:00 am'),
job() {
checkVersionUpdate();
Promise.await(checkVersionUpdate());
},
});
});
@ -25,7 +25,7 @@ const addVersionCheckJob = Meteor.bindEnvironment(() => {
Meteor.startup(() => {
Meteor.defer(() => {
if (settings.get('Register_Server') && settings.get('Update_EnableChecker')) {
checkVersionUpdate();
Promise.await(checkVersionUpdate());
}
});
});

@ -9,7 +9,14 @@ declare module 'meteor/rocketchat:tap-i18n' {
lng?: string;
} & {
[replacements: string]: boolean | number | string | string[];
},
} & (
| {
postProcess: 'sprintf';
sprintf: (boolean | number | string)[];
}
| {}
),
lang?: string,
): string;
function getLanguages(): {
[language: string]: {

@ -1,5 +1,3 @@
import { Meteor } from 'meteor/meteor';
import { onLicense } from '../../license/server';
onLicense('canned-responses', () => {
@ -11,7 +9,5 @@ onLicense('canned-responses', () => {
require('./methods/saveCannedResponse');
require('./methods/removeCannedResponse');
Meteor.startup(function () {
createSettings();
});
createSettings();
});

@ -1,15 +1,16 @@
import type { ISetting } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
import { Settings, Users } from '../../../../app/models/server';
import { Users } from '../../../../app/models/server';
type WizardSettings = Array<ISetting>;
const url = 'https://go.rocket.chat/i/seats-cap-upgrade';
export const getSeatsRequestLink = (): string => {
const workspaceId: ISetting | undefined = Settings.findOneById('Cloud_Workspace_Id');
export const getSeatsRequestLink = async (): Promise<string> => {
const workspaceId = await Settings.findOneById('Cloud_Workspace_Id');
const activeUsers = Users.getActiveLocalUserCount();
const wizardSettings: WizardSettings = Settings.findSetupWizardSettings().fetch();
const wizardSettings: WizardSettings = await Settings.findSetupWizardSettings().toArray();
const newUrl = new URL(url);

@ -1,7 +1,7 @@
import { Settings } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import { settings, settingsRegistry } from '../../../../app/settings/server';
import { Settings } from '../../../../app/models/server';
import { addLicense } from './license';
Meteor.startup(function () {

@ -1,10 +1,11 @@
import { Settings } from '@rocket.chat/models';
import { settingsRegistry } from '../../../../app/settings/server';
import { Settings } from '../../../../app/models/server';
const omnichannelEnabledQuery = { _id: 'Livechat_enabled', value: true };
const businessHoursEnabled = { _id: 'Livechat_enable_business_hours', value: true };
export const createSettings = (): void => {
export const createSettings = async (): Promise<void> => {
settingsRegistry.add('Livechat_abandoned_rooms_action', 'none', {
type: 'select',
group: 'Omnichannel',
@ -206,11 +207,11 @@ export const createSettings = (): void => {
enableQuery: omnichannelEnabledQuery,
});
Settings.addOptionValueById('Livechat_Routing_Method', {
await Settings.addOptionValueById('Livechat_Routing_Method', {
key: 'Load_Balancing',
i18nLabel: 'Load_Balancing',
});
Settings.addOptionValueById('Livechat_Routing_Method', {
await Settings.addOptionValueById('Livechat_Routing_Method', {
key: 'Load_Rotation',
i18nLabel: 'Load_Rotation',
});

@ -1,8 +1,8 @@
import { Meteor } from 'meteor/meteor';
import { ISetting, SettingValue } from '@rocket.chat/core-typings';
import { Settings } from '@rocket.chat/models';
import { isEnterprise, hasLicense, onValidateLicenses } from '../../license/server/license';
import SettingsModel from '../../../../app/models/server/models/Settings';
import { use } from '../../../../app/settings/server/Middleware';
import { settings, SettingsEvents } from '../../../../app/settings/server';
@ -50,7 +50,7 @@ SettingsEvents.on('fetch-settings', (settings: Array<ISetting>): void => {
});
function updateSettings(): void {
const enterpriseSettings = SettingsModel.findEnterpriseSettings();
const enterpriseSettings = Promise.await(Settings.findEnterpriseSettings());
enterpriseSettings.forEach((record: ISetting) => settings.set(record));
}

@ -1,7 +1,8 @@
import { check } from 'meteor/check';
import { Settings } from '@rocket.chat/models';
import { getLicenses, validateFormat, flatModules, getMaxActiveUsers, isEnterprise } from '../../app/license/server/license';
import { Settings, Users } from '../../../app/models/server';
import { Users } from '../../../app/models/server';
import { API } from '../../../app/api/server/api';
import { hasPermission } from '../../../app/authorization/server';
import { ILicense } from '../../app/license/definitions/ILicense';
@ -35,7 +36,7 @@ API.v1.addRoute(
'licenses.add',
{ authRequired: true },
{
post() {
async post() {
check(this.bodyParams, {
license: String,
});
@ -49,7 +50,7 @@ API.v1.addRoute(
return API.v1.failure('Invalid license');
}
Settings.updateValueById('Enterprise_License', license);
await Settings.updateValueById('Enterprise_License', license);
return API.v1.success();
},

@ -10,7 +10,7 @@ Meteor.startup(() => {
WebApp.connectHandlers.use(
'/requestSeats/',
Meteor.bindEnvironment((_: IncomingMessage, res: ServerResponse) => {
const url = getSeatsRequestLink();
const url = Promise.await(getSeatsRequestLink());
Analytics.saveSeatRequest();
res.writeHead(302, { Location: url });

@ -1,6 +1,6 @@
import { Meteor } from 'meteor/meteor';
import { Settings } from '@rocket.chat/models';
import { Settings } from '../../../app/models/server';
import { onValidateLicenses, getLicenses } from '../../app/license/server/license';
const handleHadTrial = (): void => {

@ -17,7 +17,7 @@ function updateSetting(id: string, value: SettingValue | null): void {
Settings.updateValueById(id, value);
}
} else {
Settings.updateValueById(id, undefined);
Settings.updateValueById(id, null);
}
}

@ -16,7 +16,7 @@ async function generateStatistics(logger) {
try {
const headers = {};
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;

@ -33,7 +33,7 @@ export async function sendMessagesToAdmins({
}: {
fromId?: string;
checkFrom?: boolean;
msgs?: Partial<IMessage>[] | Function;
msgs?: Partial<IMessage>[] | (({ adminUser }: { adminUser: IUser }) => Partial<IMessage>[]);
banners?: Banner[] | Function;
}): Promise<void> {
const fromUser = checkFrom ? await Users.findOneById(fromId, { projection: { _id: 1 } }) : true;

@ -1,11 +1,11 @@
import { Settings } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import { Settings } from '../../app/models/server';
import { settings } from '../../app/settings/server';
Meteor.methods({
getSetupWizardParameters() {
const setupWizardSettings = Settings.findSetupWizardSettings().fetch();
async getSetupWizardParameters() {
const setupWizardSettings = await Settings.findSetupWizardSettings().toArray();
const serverAlreadyRegistered = !!settings.get('Cloud_Workspace_Client_Id') || process.env.DEPLOY_PLATFORM === 'rocket-cloud';
return {

@ -50,7 +50,10 @@ export class SettingsRaw extends BaseRaw<ISetting> implements ISettingsModel {
return this.find(query);
}
updateValueById<T extends ISetting['value'] = ISetting['value']>(_id: string, value: T): Promise<Document | UpdateResult> {
updateValueById(
_id: string,
value: (ISetting['value'] extends undefined ? never : ISetting['value']) | null,
): Promise<Document | UpdateResult> {
const query = {
blocked: { $ne: true },
value: { $ne: value },
@ -207,4 +210,8 @@ export class SettingsRaw extends BaseRaw<ISetting> implements ISettingsModel {
},
});
}
findEnterpriseSettings(): FindCursor<ISetting> {
return this.find({ enterprise: true });
}
}

@ -18,7 +18,7 @@ type NpsSurveyData = {
};
export const getAndCreateNpsSurvey = Meteor.bindEnvironment(async function getNpsSurvey(npsId: string) {
const token = getWorkspaceAccessToken();
const token = await getWorkspaceAccessToken();
if (!token) {
return false;
}

@ -12,7 +12,7 @@ type NPSResultPayload = {
};
export const sendNpsResults = Meteor.bindEnvironment(function sendNpsResults(npsId: string, data: NPSResultPayload) {
const token = getWorkspaceAccessToken();
const token = Promise.await(getWorkspaceAccessToken());
if (!token) {
return false;
}

@ -1,5 +1,6 @@
import { Settings } from '@rocket.chat/models';
import { addMigration } from '../../lib/migrations';
import { Settings } from '../../../app/models/server';
import { settings } from '../../../app/settings/server';
addMigration({
@ -7,11 +8,12 @@ addMigration({
up() {
const livechatVideoCallEnabled = settings.get('Livechat_videocall_enabled');
if (livechatVideoCallEnabled) {
Settings.upsert(
Settings.updateOne(
{ _id: 'Omnichannel_call_provider' },
{
$set: { value: 'Jitsi' },
},
{ upsert: true },
);
}
Settings.removeById('Livechat_videocall_enabled');
@ -20,11 +22,12 @@ addMigration({
const webRTCEnableDirect = settings.get('WebRTC_Enable_Direct');
const webRTCEnablePrivate = settings.get('WebRTC_Enable_Private');
if (webRTCEnableChannel || webRTCEnableDirect || webRTCEnablePrivate) {
Settings.upsert(
Settings.updateOne(
{ _id: 'WebRTC_Enabled' },
{
$set: { value: true },
},
{ upsert: true },
);
}
},

@ -11,12 +11,12 @@ describe('Settings', () => {
process.env = {};
});
it('should not insert the same setting twice', () => {
it('should not insert the same setting twice', async () => {
const settings = new CachedSettings();
Settings.settings = settings;
settings.initilized();
settings.initialized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting', true, {
type: 'boolean',
@ -44,7 +44,7 @@ describe('Settings', () => {
autocomplete: true,
});
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting', true, {
type: 'boolean',
@ -58,7 +58,7 @@ describe('Settings', () => {
expect(Settings.findOne({ _id: 'my_setting' }).value).to.be.equal(true);
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting2', false, {
type: 'boolean',
@ -74,15 +74,15 @@ describe('Settings', () => {
expect(Settings.findOne({ _id: 'my_setting2' }).value).to.be.equal(false);
});
it('should respect override via environment as int', () => {
it('should respect override via environment as int', async () => {
const settings = new CachedSettings();
Settings.settings = settings;
settings.initilized();
settings.initialized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
process.env.OVERWRITE_SETTING_my_setting = '1';
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting', 0, {
type: 'int',
@ -114,7 +114,7 @@ describe('Settings', () => {
process.env.OVERWRITE_SETTING_my_setting = '2';
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting', 0, {
type: 'int',
@ -132,14 +132,14 @@ describe('Settings', () => {
});
});
it('should respect override via environment as boolean', () => {
it('should respect override via environment as boolean', async () => {
process.env.OVERWRITE_SETTING_my_setting_bool = 'true';
const settings = new CachedSettings();
Settings.settings = settings;
settings.initilized();
settings.initialized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting_bool', false, {
type: 'boolean',
@ -171,7 +171,7 @@ describe('Settings', () => {
process.env.OVERWRITE_SETTING_my_setting_bool = 'false';
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting_bool', true, {
type: 'boolean',
@ -189,14 +189,14 @@ describe('Settings', () => {
});
});
it('should respect override via environment as string', () => {
it('should respect override via environment as string', async () => {
process.env.OVERWRITE_SETTING_my_setting_str = 'hey';
const settings = new CachedSettings();
Settings.settings = settings;
settings.initilized();
settings.initialized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting_str', '', {
type: 'string',
@ -228,7 +228,7 @@ describe('Settings', () => {
process.env.OVERWRITE_SETTING_my_setting_str = 'hey ho';
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting_str', 'hey', {
type: 'string',
@ -247,14 +247,14 @@ describe('Settings', () => {
});
});
it('should respect initial value via environment', () => {
it('should respect initial value via environment', async () => {
process.env.my_setting = '1';
const settings = new CachedSettings();
Settings.settings = settings;
settings.initilized();
settings.initialized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting', 0, {
type: 'int',
@ -284,7 +284,7 @@ describe('Settings', () => {
expect(Settings.upsertCalls).to.be.equal(0);
expect(Settings.findOne({ _id: 'my_setting' })).to.include(expectedSetting);
settingsRegistry.addGroup('group', function () {
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('my_setting', 0, {
type: 'int',
@ -298,33 +298,35 @@ describe('Settings', () => {
expect(Settings.findOne({ _id: 'my_setting' })).to.include({ ...expectedSetting });
});
it('should call `settings.get` callback on setting added', (done) => {
const settings = new CachedSettings();
Settings.settings = settings;
settings.initilized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
const spiedCallback1 = spy();
const spiedCallback2 = spy();
settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('setting_callback', 'value1', {
type: 'string',
it('should call `settings.get` callback on setting added', async () => {
return new Promise(async (resolve) => {
const settings = new CachedSettings();
Settings.settings = settings;
settings.initialized();
const settingsRegistry = new SettingsRegistry({ store: settings, model: Settings as any });
const spiedCallback1 = spy();
const spiedCallback2 = spy();
await settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('setting_callback', 'value1', {
type: 'string',
});
});
});
});
settings.watch('setting_callback', spiedCallback1, { debounce: 10 });
settings.watchByRegex(/setting_callback/, spiedCallback2, { debounce: 10 });
settings.watch('setting_callback', spiedCallback1, { debounce: 10 });
settings.watchByRegex(/setting_callback/, spiedCallback2, { debounce: 10 });
setTimeout(() => {
expect(spiedCallback1).to.have.been.called.exactly(1);
expect(spiedCallback2).to.have.been.called.exactly(1);
expect(spiedCallback1).to.have.been.called.always.with('value1');
expect(spiedCallback2).to.have.been.called.always.with('setting_callback', 'value1');
done();
}, settings.getConfig({ debounce: 10 }).debounce);
setTimeout(() => {
expect(spiedCallback1).to.have.been.called.exactly(1);
expect(spiedCallback2).to.have.been.called.exactly(1);
expect(spiedCallback1).to.have.been.called.always.with('value1');
expect(spiedCallback2).to.have.been.called.always.with('setting_callback', 'value1');
resolve();
}, settings.getConfig({ debounce: 10 }).debounce);
});
});
it('should call `settings.watch` callback on setting changed registering before initialized', (done) => {
@ -337,7 +339,7 @@ describe('Settings', () => {
settings.watch('setting_callback', spiedCallback1, { debounce: 1 });
settings.watchByRegex(/setting_callback/gi, spiedCallback2, { debounce: 1 });
settings.initilized();
settings.initialized();
settingsRegistry.addGroup('group', function () {
this.section('section', function () {
this.add('setting_callback', 'value2', {

@ -1,45 +0,0 @@
import { expect, spy } from 'chai';
import rewire from 'rewire';
describe('Raw Settings', () => {
let rawModule;
const cache = new Map();
before('rewire deps', () => {
const spied = spy(async (id) => {
if (id === '1') {
return 'some-setting-value';
}
return null;
});
rawModule = rewire('../../../../../app/settings/server/raw');
rawModule.__set__('setFromDB', spied);
rawModule.__set__('cache', cache);
});
it('should get the value from database when it isnt in cache', async () => {
const setting = await rawModule.getValue('1');
expect(setting).to.be.equal('some-setting-value');
});
it('should get the value from cache when its available', async () => {
cache.set('2', 'supeer-setting');
const setting = await rawModule.getValue('2');
expect(setting).to.be.equal('supeer-setting');
});
it('should update the value in cache', async () => {
await rawModule.updateValue('2', { value: 'not-super-setting' });
expect(cache.get('2')).to.be.equal('not-super-setting');
});
it('should not update the setting if the new value is undefined', async () => {
await rawModule.updateValue('2', {});
expect(cache.get('2')).to.be.equal('not-super-setting');
});
});

@ -12,7 +12,7 @@ export enum SettingEditor {
type AssetValue = { defaultUrl?: string };
export type SettingValueMultiSelect = (string | number)[];
export type SettingValueRoomPick = Array<{ _id: string; name: string }> | string;
export type SettingValue = string | boolean | number | SettingValueMultiSelect | Date | AssetValue | undefined;
export type SettingValue = string | boolean | number | SettingValueMultiSelect | Date | AssetValue | undefined | null;
export interface ISettingSelectOption {
key: string | number;

@ -12,7 +12,10 @@ export interface ISettingsModel extends IBaseModel<ISetting> {
findByIds(_id?: string[] | string): FindCursor<ISetting>;
updateValueById<T extends ISetting['value'] = ISetting['value']>(_id: string, value: T): Promise<Document | UpdateResult>;
updateValueById(
_id: string,
value: (ISetting['value'] extends undefined ? never : ISetting['value']) | null,
): Promise<Document | UpdateResult>;
incrementValueById(_id: ISetting['_id'], value?: number): Promise<Document | UpdateResult>;
@ -42,6 +45,8 @@ export interface ISettingsModel extends IBaseModel<ISetting> {
findSetupWizardSettings(): FindCursor<ISetting>;
findEnterpriseSettings(): FindCursor<ISetting>;
addOptionValueById(_id: ISetting['_id'], option: ISettingSelectOption): Promise<Document | UpdateResult>;
findNotHiddenPublicUpdatedAfter(updatedAt: Date): FindCursor<ISetting>;

Loading…
Cancel
Save