snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
141
apps/meteor/server/bridges/smarsh/functions/generateEml.ts
Normal file
141
apps/meteor/server/bridges/smarsh/functions/generateEml.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { MessageTypes } from '@rocket.chat/message-types';
|
||||
import { Messages, SmarshHistory, Users, Rooms } from '@rocket.chat/models';
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import moment from 'moment-timezone';
|
||||
|
||||
import { sendEmail } from './sendEmail';
|
||||
import { i18n } from '../../../lib/i18n';
|
||||
import { settings } from '../../../settings';
|
||||
|
||||
const start =
|
||||
'<table style="width: 100%; border: 1px solid; border-collapse: collapse; table-layout: fixed; margin-top: 10px; font-size: 12px; word-break: break-word;"><tbody>';
|
||||
const end = '</tbody></table>';
|
||||
const opentr = '<tr style="border: 1px solid;">';
|
||||
const closetr = '</tr>';
|
||||
const open20td = '<td style="border: 1px solid; text-align: center; width: 20%;">';
|
||||
const open60td = '<td style="border: 1px solid; text-align: left; width: 60%; padding: 0 5px;">';
|
||||
const closetd = '</td>';
|
||||
|
||||
function _getLink(attachment: { title_link: string }): string {
|
||||
const url = attachment.title_link.replace(/ /g, '%20');
|
||||
|
||||
if (url.match(/^(https?:)?\/\//i)) {
|
||||
return url;
|
||||
}
|
||||
return Meteor.absoluteUrl().replace(/\/$/, '') + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX + url;
|
||||
}
|
||||
|
||||
export const generateEml = async (): Promise<void> => {
|
||||
setImmediate(async () => {
|
||||
const smarshMissingEmail = settings.get('Smarsh_MissingEmail_Email');
|
||||
const timeZone = settings.get<string>('Smarsh_Timezone');
|
||||
|
||||
// TODO: revisit with more time => This appears to be a super expensive operation, going through all rooms
|
||||
for await (const room of Rooms.find()) {
|
||||
const smarshHistory = await SmarshHistory.findOne({ _id: room._id });
|
||||
const query: Record<string, any> = { rid: room._id };
|
||||
|
||||
if (smarshHistory) {
|
||||
query.ts = { $gt: smarshHistory.lastRan };
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
const rows: string[] = [];
|
||||
const data: {
|
||||
users: string[];
|
||||
msgs: number;
|
||||
files: string[];
|
||||
time: number;
|
||||
room: string;
|
||||
} = {
|
||||
users: [],
|
||||
msgs: 0,
|
||||
files: [],
|
||||
time: smarshHistory ? moment(date).diff(moment(smarshHistory.lastRan), 'minutes') : moment(date).diff(moment(room.ts), 'minutes'),
|
||||
room: room.name ? `#${room.name}` : `Direct Message Between: ${room?.usernames?.join(' & ')}`,
|
||||
};
|
||||
|
||||
const cursor = Messages.find(query);
|
||||
|
||||
for await (const message of cursor) {
|
||||
rows.push(opentr);
|
||||
|
||||
// The timestamp
|
||||
rows.push(open20td);
|
||||
rows.push(moment(message.ts).tz(timeZone).format('YYYY-MM-DD HH-mm-ss z'));
|
||||
rows.push(closetd);
|
||||
|
||||
// The sender
|
||||
rows.push(open20td);
|
||||
const sender = await Users.findOne({ _id: message.u._id });
|
||||
if (!sender) {
|
||||
return;
|
||||
}
|
||||
if (data.users.indexOf(sender?._id) === -1) {
|
||||
data.users.push(sender._id);
|
||||
}
|
||||
|
||||
// Get the user's email, can be nothing if it is an unconfigured bot account (like rocket.cat)
|
||||
if (sender.emails?.[0]?.address) {
|
||||
rows.push(`${sender.name} <${sender.emails[0].address}>`);
|
||||
} else {
|
||||
rows.push(`${sender.name} <${smarshMissingEmail}>`);
|
||||
}
|
||||
rows.push(closetd);
|
||||
|
||||
// The message
|
||||
rows.push(open60td);
|
||||
data.msgs++;
|
||||
if (message.t) {
|
||||
const messageType = MessageTypes.getType(message);
|
||||
if (messageType) {
|
||||
rows.push(messageType.text(i18n.getFixedT('en'), message));
|
||||
} else {
|
||||
rows.push(`${message.msg} (${message.t})`);
|
||||
}
|
||||
} else if (message.file) {
|
||||
data.files.push(message.file._id);
|
||||
rows.push(`${message?.attachments?.[0].title} (${_getLink({ title_link: message?.attachments?.[0].title_link || '' })})})`);
|
||||
} else if (message.attachments) {
|
||||
const attaches: string[] = [];
|
||||
message.attachments.forEach((a) => {
|
||||
if ('image_url' in a && a.image_url !== undefined) {
|
||||
attaches.push(a.image_url);
|
||||
}
|
||||
// TODO: Verify other type of attachments which need to be handled that aren't file uploads and image urls
|
||||
// } else {
|
||||
// console.log(a);
|
||||
// }
|
||||
});
|
||||
|
||||
rows.push(`${message.msg} (${attaches.join(', ')})`);
|
||||
} else {
|
||||
rows.push(message.msg);
|
||||
}
|
||||
rows.push(closetd);
|
||||
|
||||
rows.push(closetr);
|
||||
}
|
||||
|
||||
if (rows.length !== 0) {
|
||||
const result = start + rows.join('') + end;
|
||||
|
||||
await SmarshHistory.updateOne(
|
||||
{ _id: room._id },
|
||||
{
|
||||
_id: room._id,
|
||||
lastRan: date,
|
||||
lastResult: result,
|
||||
},
|
||||
{ upsert: true },
|
||||
);
|
||||
|
||||
await sendEmail({
|
||||
body: result,
|
||||
subject: `Rocket.Chat, ${data.users.length} Users, ${data.msgs} Messages, ${data.files.length} Files, ${data.time} Minutes, in ${data.room}`,
|
||||
files: data.files,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
33
apps/meteor/server/bridges/smarsh/functions/sendEmail.ts
Normal file
33
apps/meteor/server/bridges/smarsh/functions/sendEmail.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
// Expects the following details:
|
||||
// {
|
||||
// body: '<table>',
|
||||
// subject: 'Rocket.Chat, 17 Users, 24 Messages, 1 File, 799504 Minutes, in #random',
|
||||
// files: ['i3nc9l3mn']
|
||||
// }
|
||||
import { Uploads } from '@rocket.chat/models';
|
||||
|
||||
import * as Mailer from '../../../lib/notifications/email/api';
|
||||
import { settings } from '../../../settings';
|
||||
import { UploadFS } from '../../../ufs';
|
||||
|
||||
export const sendEmail = async (data: { files: string[]; subject: string; body: string }) => {
|
||||
const attachments = [];
|
||||
|
||||
for await (const fileId of data.files) {
|
||||
const file = await Uploads.findOneById(fileId);
|
||||
if (file?.store === 'rocketchat_uploads' || file?.store === 'fileSystem') {
|
||||
const rs = await UploadFS.getStore(file.store).getReadStream(fileId, file);
|
||||
attachments.push({
|
||||
filename: file.name,
|
||||
streamSource: rs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await Mailer.sendNoWrap({
|
||||
to: settings.get('Smarsh_Email'),
|
||||
from: settings.get('From_Email'),
|
||||
subject: data.subject,
|
||||
html: data.body,
|
||||
});
|
||||
};
|
||||
3
apps/meteor/server/bridges/smarsh/index.ts
Normal file
3
apps/meteor/server/bridges/smarsh/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import './functions/sendEmail';
|
||||
import './functions/generateEml';
|
||||
import './startup';
|
||||
21
apps/meteor/server/bridges/smarsh/startup.ts
Normal file
21
apps/meteor/server/bridges/smarsh/startup.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { cronJobs } from '@rocket.chat/cron';
|
||||
|
||||
import { generateEml } from './functions/generateEml';
|
||||
import { settings } from '../../settings';
|
||||
import { smarshIntervalValuesToCronMap } from '../../settings/smarsh';
|
||||
|
||||
const smarshJobName = 'Smarsh EML Connector';
|
||||
|
||||
settings.watchMultiple(
|
||||
['Smarsh_Enabled', 'Smarsh_Email', 'From_Email', 'Smarsh_Interval'],
|
||||
async function __addSmarshSyncedCronJobDebounced() {
|
||||
if (await cronJobs.has(smarshJobName)) {
|
||||
await cronJobs.remove(smarshJobName);
|
||||
}
|
||||
|
||||
if (settings.get('Smarsh_Enabled') && settings.get('Smarsh_Email') !== '' && settings.get('From_Email') !== '') {
|
||||
const cronInterval = smarshIntervalValuesToCronMap[settings.get<string>('Smarsh_Interval')];
|
||||
await cronJobs.add(smarshJobName, cronInterval, async () => generateEml());
|
||||
}
|
||||
},
|
||||
);
|
||||
Reference in New Issue
Block a user