Skip to content

Commit

Permalink
Merge branch 'develop' into feat/setup-wizard-back-step
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagoevanp authored Oct 9, 2023
2 parents 6e3a56c + 76c7b95 commit c6d39cb
Show file tree
Hide file tree
Showing 11 changed files with 98 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/wicked-humans-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Improve cache of static files
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export async function buildWorkspaceRegistrationData<T extends string | undefine
setupComplete: setupWizardState === 'completed',
connectionDisable: !registerServer,
npsEnabled,
MAC: stats.omnichannelContactsBySource.contactsCount,
MAC: stats.omnichannelContactsBySource?.contactsCount ?? 0,
// activeContactsBillingMonth: stats.omnichannelContactsBySource.contactsCount,
// activeContactsYesterday: stats.uniqueContactsOfYesterday.contactsCount,
};
Expand Down
41 changes: 41 additions & 0 deletions apps/meteor/app/cors/server/cors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { createHash } from 'crypto';
import type http from 'http';
import type { UrlWithParsedQuery } from 'url';
import url from 'url';

import { Logger } from '@rocket.chat/logger';
Expand Down Expand Up @@ -77,6 +79,19 @@ WebApp.rawConnectHandlers.use((_req: http.IncomingMessage, res: http.ServerRespo
});

const _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware;
declare module 'meteor/webapp' {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace WebApp {
function categorizeRequest(
req: http.IncomingMessage,
): { arch: string; path: string; url: UrlWithParsedQuery } & Record<string, unknown>;
}
}

// These routes already handle cache control on their own
const cacheControlledRoutes: Array<RegExp> = ['/assets', '/custom-sounds', '/emoji-custom', '/avatar', '/file-upload'].map(
(route) => new RegExp(`^${route}`, 'i'),
);

// @ts-expect-error - accessing internal property of webapp
WebAppInternals.staticFilesMiddleware = function (
Expand All @@ -86,6 +101,32 @@ WebAppInternals.staticFilesMiddleware = function (
next: NextFunction,
) {
res.setHeader('Access-Control-Allow-Origin', '*');
const { arch, path, url } = WebApp.categorizeRequest(req);

if (Meteor.isProduction && !cacheControlledRoutes.some((regexp) => regexp.test(path))) {
res.setHeader('Cache-Control', 'public, max-age=31536000');
}

// Prevent meteor_runtime_config.js to load from a different expected hash possibly causing
// a cache of the file for the wrong hash and start a client loop due to the mismatch
// of the hashes of ui versions which would be checked against a websocket response
if (path === '/meteor_runtime_config.js') {
const program = WebApp.clientPrograms[arch] as (typeof WebApp.clientPrograms)[string] & {
meteorRuntimeConfigHash?: string;
meteorRuntimeConfig: string;
};

if (!program?.meteorRuntimeConfigHash) {
program.meteorRuntimeConfigHash = createHash('sha1')
.update(JSON.stringify(encodeURIComponent(program.meteorRuntimeConfig)))
.digest('hex');
}

if (program.meteorRuntimeConfigHash !== url.query.hash) {
res.writeHead(404);
return res.end();
}
}
return _staticFilesMiddleware(staticFiles, req, res, next);
};

Expand Down
29 changes: 15 additions & 14 deletions apps/meteor/app/custom-sounds/client/lib/CustomSounds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ import { getURL } from '../../../utils/client';
import { sdk } from '../../../utils/client/lib/SDKClient';

const getCustomSoundId = (soundId: ICustomSound['_id']) => `custom-sound-${soundId}`;
const getAssetUrl = (asset: string, params?: Record<string, any>) => getURL(asset, params, undefined, true);

const defaultSounds = [
{ _id: 'chime', name: 'Chime', extension: 'mp3', src: getURL('sounds/chime.mp3') },
{ _id: 'door', name: 'Door', extension: 'mp3', src: getURL('sounds/door.mp3') },
{ _id: 'beep', name: 'Beep', extension: 'mp3', src: getURL('sounds/beep.mp3') },
{ _id: 'chelle', name: 'Chelle', extension: 'mp3', src: getURL('sounds/chelle.mp3') },
{ _id: 'ding', name: 'Ding', extension: 'mp3', src: getURL('sounds/ding.mp3') },
{ _id: 'droplet', name: 'Droplet', extension: 'mp3', src: getURL('sounds/droplet.mp3') },
{ _id: 'highbell', name: 'Highbell', extension: 'mp3', src: getURL('sounds/highbell.mp3') },
{ _id: 'seasons', name: 'Seasons', extension: 'mp3', src: getURL('sounds/seasons.mp3') },
{ _id: 'telephone', name: 'Telephone', extension: 'mp3', src: getURL('sounds/telephone.mp3') },
{ _id: 'outbound-call-ringing', name: 'Outbound Call Ringing', extension: 'mp3', src: getURL('sounds/outbound-call-ringing.mp3') },
{ _id: 'call-ended', name: 'Call Ended', extension: 'mp3', src: getURL('sounds/call-ended.mp3') },
{ _id: 'dialtone', name: 'Dialtone', extension: 'mp3', src: getURL('sounds/dialtone.mp3') },
{ _id: 'ringtone', name: 'Ringtone', extension: 'mp3', src: getURL('sounds/ringtone.mp3') },
{ _id: 'chime', name: 'Chime', extension: 'mp3', src: getAssetUrl('sounds/chime.mp3') },
{ _id: 'door', name: 'Door', extension: 'mp3', src: getAssetUrl('sounds/door.mp3') },
{ _id: 'beep', name: 'Beep', extension: 'mp3', src: getAssetUrl('sounds/beep.mp3') },
{ _id: 'chelle', name: 'Chelle', extension: 'mp3', src: getAssetUrl('sounds/chelle.mp3') },
{ _id: 'ding', name: 'Ding', extension: 'mp3', src: getAssetUrl('sounds/ding.mp3') },
{ _id: 'droplet', name: 'Droplet', extension: 'mp3', src: getAssetUrl('sounds/droplet.mp3') },
{ _id: 'highbell', name: 'Highbell', extension: 'mp3', src: getAssetUrl('sounds/highbell.mp3') },
{ _id: 'seasons', name: 'Seasons', extension: 'mp3', src: getAssetUrl('sounds/seasons.mp3') },
{ _id: 'telephone', name: 'Telephone', extension: 'mp3', src: getAssetUrl('sounds/telephone.mp3') },
{ _id: 'outbound-call-ringing', name: 'Outbound Call Ringing', extension: 'mp3', src: getAssetUrl('sounds/outbound-call-ringing.mp3') },
{ _id: 'call-ended', name: 'Call Ended', extension: 'mp3', src: getAssetUrl('sounds/call-ended.mp3') },
{ _id: 'dialtone', name: 'Dialtone', extension: 'mp3', src: getAssetUrl('sounds/dialtone.mp3') },
{ _id: 'ringtone', name: 'Ringtone', extension: 'mp3', src: getAssetUrl('sounds/ringtone.mp3') },
];

class CustomSoundsClass {
Expand Down Expand Up @@ -85,7 +86,7 @@ class CustomSoundsClass {
}

getURL(sound: ICustomSound) {
return getURL(`/custom-sounds/${sound._id}.${sound.extension}?_dc=${sound.random || 0}`);
return getAssetUrl(`/custom-sounds/${sound._id}.${sound.extension}`, { _dc: sound.random || 0 });
}

getList() {
Expand Down
24 changes: 17 additions & 7 deletions apps/meteor/app/ui-master/server/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const callback: NextHandleFunction = (req, res, next) => {
return;
}

const injection = headInjections.get(pathname.replace(/^\//, '')) as Injection | undefined;
const injection = headInjections.get(pathname.replace(/^\//, '').split('_')[0]) as Injection | undefined;

if (!injection || typeof injection === 'string') {
next();
Expand Down Expand Up @@ -76,27 +76,37 @@ export const injectIntoHead = (key: string, value: Injection): void => {
};

export const addScript = (key: string, content: string): void => {
if (/_/.test(key)) {
throw new Error('inject.js > addScript - key cannot contain "_" (underscore)');
}

if (!content.trim()) {
injectIntoHead(`${key}.js`, '');
injectIntoHead(key, '');
return;
}
const currentHash = crypto.createHash('sha1').update(content).digest('hex');
injectIntoHead(`${key}.js`, {

injectIntoHead(key, {
type: 'JS',
tag: `<script id="${key}" type="text/javascript" src="${`${getURL(key)}.js?${currentHash}`}"></script>`,
tag: `<script id="${key}" type="text/javascript" src="${`${getURL(key)}_${currentHash}.js`}"></script>`,
content,
});
};

export const addStyle = (key: string, content: string): void => {
if (/_/.test(key)) {
throw new Error('inject.js > addStyle - key cannot contain "_" (underscore)');
}

if (!content.trim()) {
injectIntoHead(`${key}.css`, '');
injectIntoHead(key, '');
return;
}
const currentHash = crypto.createHash('sha1').update(content).digest('hex');
injectIntoHead(`${key}.css`, {

injectIntoHead(key, {
type: 'CSS',
tag: `<link id="${key}" rel="stylesheet" type="text/css" href="${`${getURL(key)}.css?${currentHash}`}">`,
tag: `<link id="${key}" rel="stylesheet" type="text/css" href="${`${getURL(key)}_${currentHash}.css`}">`,
content,
});
};
Expand Down
6 changes: 6 additions & 0 deletions apps/meteor/app/utils/client/getURL.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { settings } from '../../settings/client';
import { getURLWithoutSettings } from '../lib/getURL';
import { Info } from '../rocketchat.info';

export const getURL = function (
path: string, // eslint-disable-next-line @typescript-eslint/naming-convention
params: Record<string, any> = {},
cloudDeepLinkUrl?: string,
cacheKey?: boolean,
): string {
const cdnPrefix = settings.get('CDN_PREFIX') || '';
const siteUrl = settings.get('Site_Url') || '';

if (cacheKey) {
path += `${path.includes('?') ? '&' : '?'}cacheKey=${Info.version}`;
}

return getURLWithoutSettings(path, params, cdnPrefix, siteUrl, cloudDeepLinkUrl);
};
6 changes: 3 additions & 3 deletions apps/meteor/client/views/admin/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ declare module '@rocket.chat/ui-contexts' {
pattern: '/admin/registration/:page?';
};
'admin-view-logs': {
pathname: '/admin/records';
pattern: '/admin/records';
pathname: '/admin/reports';
pattern: '/admin/reports';
};
'federation-dashboard': {
pathname: '/admin/federation';
Expand Down Expand Up @@ -193,7 +193,7 @@ registerAdminRoute('/registration/:page?', {
component: lazy(() => import('./cloud/CloudRoute')),
});

registerAdminRoute('/records', {
registerAdminRoute('/reports', {
name: 'admin-view-logs',
component: lazy(() => import('./viewLogs/ViewLogsRoute')),
});
Expand Down
4 changes: 2 additions & 2 deletions apps/meteor/client/views/admin/sidebarItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ export const {
permissionGranted: (): boolean => hasPermission('run-import'),
},
{
href: '/admin/records',
i18nLabel: 'Records',
href: '/admin/reports',
i18nLabel: 'Reports',
icon: 'post',
permissionGranted: (): boolean => hasPermission('view-logs'),
},
Expand Down
5 changes: 4 additions & 1 deletion apps/meteor/client/views/admin/viewLogs/AnalyticsReports.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ const AnalyticsReports = () => {
</Box>
<Box fontScale='h4'>{t('How_and_why_we_collect_usage_data')}</Box>
</Box>
<Box fontScale='p1'>{t('Analytics_page_briefing')}</Box>
<Box fontScale='p1' mbe={16}>
{t('Analytics_page_briefing_first_paragraph')}
</Box>
<Box fontScale='p1'>{t('Analytics_page_briefing_second_paragraph')}</Box>
</Box>
<Box display='flex' flexDirection='column' padding={8} flexGrow={1} color='default' bg='neutral' borderRadius={4} overflow='scroll'>
{isSuccess && <pre>{JSON.stringify(data, null, '\t')}</pre>}
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/client/views/admin/viewLogs/ViewLogsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const ViewLogsPage = (): ReactElement => {

return (
<Page>
<Page.Header title={t('Records')} />
<Page.Header title={t('Reports')} />
<Page.Content>
<Tabs mbe={24}>
<Tabs.Item onClick={() => setTab('Logs')} selected={tab === 'Logs'}>
Expand Down
6 changes: 3 additions & 3 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,8 @@
"Analytics_features_users_Description": "Tracks custom events related to actions related to users (password reset times, profile picture change, etc).",
"Analytics_Google": "Google Analytics",
"Analytics_Google_id": "Tracking ID",
"Analytics_page_briefing": "Rocket.Chat collects anonymous usage data to identify how many instances are deployed and to improve the product for all users. We take your privacy seriously, so the usage data is encrypted and stored securely.",
"Analytics_page_briefing_first_paragraph": "Rocket.Chat collects anonymous usage data, such as feature usage and session lengths, to improve the product for everyone.",
"Analytics_page_briefing_second_paragraph": "We protect your privacy by never collecting personal or sensitive data. This section shows what is collected, reinforcing our commitment to transparency and trust.",
"Analyze_practical_usage": "Analyze practical usage statistics about users, messages and channels",
"and": "and",
"And_more": "And {{length}} more",
Expand Down Expand Up @@ -2484,7 +2485,7 @@
"Hospitality_Businness": "Hospitality Business",
"hours": "hours",
"Hours": "Hours",
"How_and_why_we_collect_usage_data": "How and why we collect usage data",
"How_and_why_we_collect_usage_data": "How and why usage data is collected",
"How_friendly_was_the_chat_agent": "How friendly was the chat agent?",
"How_knowledgeable_was_the_chat_agent": "How knowledgeable was the chat agent?",
"How_long_to_wait_after_agent_goes_offline": "How Long to Wait After Agent Goes Offline",
Expand Down Expand Up @@ -4182,7 +4183,6 @@
"Receive_Login_Detection_Emails_Description": "Receive an email each time a new login is detected on your account.",
"Recent_Import_History": "Recent Import History",
"Record": "Record",
"Records": "Records",
"recording": "recording",
"Redirect_URI": "Redirect URI",
"Redirect_URL_does_not_match": "Redirect URL does not match",
Expand Down

0 comments on commit c6d39cb

Please sign in to comment.