Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into feat…
Browse files Browse the repository at this point in the history
…/mentionBot

* 'develop' of github.com:RocketChat/Rocket.Chat:
  feat: add tooltip to badge mentions (#30590)
  chore: improve `Tag` a11y link (#30636)
  refactor: Replace `useForm` in favor of RHF on `AppInstallPage` (#30634)
  fix: Improve FileProxy Handling, set Content-Type (#30427)
  refactor: `EditRoomInfo` to typescript (#28318)
  fix: mobile ringing notification missing call id (#30614)
  fix: Some HTTP requests sent by apps don't have their data parsed into JSON (#30560)
  test: More tests for groups kick (#30536)
  fix: Threads breaking after sending messages too fast (#30622)
  chore: Remove text decoration from room tag (#30606)
  i18n: Language update from LingoHub 🤖 on 2023-10-10Z (#30613)
  fix: File attachments have no content when exporting room messages as file (#30596)
  fix: use setImmediate to handle username update (#30500)
  chore: `AnalyticsReports` visual adequacy (#30617)
  • Loading branch information
gabriellsh committed Oct 16, 2023
2 parents c7e9a78 + bbbbdac commit e7992ff
Show file tree
Hide file tree
Showing 71 changed files with 1,426 additions and 1,027 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-zoos-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

fixed threads breaking when sending messages too fast
5 changes: 5 additions & 0 deletions .changeset/lucky-vans-develop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixed issue with file attachments in rooms' messages export having no content
5 changes: 5 additions & 0 deletions .changeset/old-zoos-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

fix: mobile ringing notification missing call id
5 changes: 5 additions & 0 deletions .changeset/stale-masks-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/server-fetch': patch
---

Fixed an issue where the payload of an HTTP request made by an app wouldn't be correctly encoded in some cases
5 changes: 5 additions & 0 deletions .changeset/tough-apples-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Forward headers when using proxy for file uploads
5 changes: 5 additions & 0 deletions .changeset/wicked-jars-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Handle the username update in the background
11 changes: 7 additions & 4 deletions apps/meteor/app/file-upload/server/config/AmazonS3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ const get: FileUploadClass['get'] = async function (this: FileUploadClass, file,

const copy: FileUploadClass['copy'] = async function (this: FileUploadClass, file, out) {
const fileUrl = await this.store.getRedirectURL(file);
if (fileUrl) {
const request = /^https:/.test(fileUrl) ? https : http;
request.get(fileUrl, (fileRes) => fileRes.pipe(out));
} else {
if (!fileUrl) {
out.end();
return;
}

const request = /^https:/.test(fileUrl) ? https : http;
return new Promise((resolve) => {
request.get(fileUrl, (fileRes) => fileRes.pipe(out).on('finish', () => resolve()));
});
};

const AmazonS3Uploads = new FileUploadClass({
Expand Down
11 changes: 7 additions & 4 deletions apps/meteor/app/file-upload/server/config/GoogleStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ const get: FileUploadClass['get'] = async function (this: FileUploadClass, file,
const copy: FileUploadClass['copy'] = async function (this: FileUploadClass, file, out) {
const fileUrl = await this.store.getRedirectURL(file, false);

if (fileUrl) {
const request = /^https:/.test(fileUrl) ? https : http;
request.get(fileUrl, (fileRes) => fileRes.pipe(out));
} else {
if (!fileUrl) {
out.end();
return;
}

const request = /^https:/.test(fileUrl) ? https : http;
return new Promise((resolve) => {
request.get(fileUrl, (fileRes) => fileRes.pipe(out).on('finish', () => resolve()));
});
};

const GoogleCloudStorageUploads = new FileUploadClass({
Expand Down
4 changes: 3 additions & 1 deletion apps/meteor/app/file-upload/server/config/Webdav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const get: FileUploadClass['get'] = async function (this: FileUploadClass, file,
};

const copy: FileUploadClass['copy'] = async function (this: FileUploadClass, file, out) {
(await this.store.getReadStream(file._id, file)).pipe(out);
return new Promise(async (resolve) => {
(await this.store.getReadStream(file._id, file)).pipe(out).on('finish', () => resolve());
});
};

const WebdavUploads = new FileUploadClass({
Expand Down
27 changes: 26 additions & 1 deletion apps/meteor/app/file-upload/server/lib/FileUpload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,32 @@ export const FileUpload = {
) {
res.setHeader('Content-Disposition', `${forceDownload ? 'attachment' : 'inline'}; filename="${encodeURI(fileName)}"`);

request.get(fileUrl, (fileRes) => fileRes.pipe(res));
request.get(fileUrl, (fileRes) => {
if (fileRes.statusCode !== 200) {
res.setHeader('x-rc-proxyfile-status', String(fileRes.statusCode));
res.setHeader('content-length', 0);
res.writeHead(500);
res.end();
return;
}

// eslint-disable-next-line prettier/prettier
const headersToProxy = [
'age',
'cache-control',
'content-length',
'content-type',
'date',
'expired',
'last-modified',
];

headersToProxy.forEach((header) => {
fileRes.headers[header] && res.setHeader(header, String(fileRes.headers[header]));
});

fileRes.pipe(res);
});
},

generateJWTToFileUrls({ rid, userId, fileId }: { rid: string; userId: string; fileId: string }) {
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/app/lib/server/functions/saveUser.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ export const saveUser = async function (userId, userData) {
_id: userData._id,
username: userData.username,
name: userData.name,
updateUsernameInBackground: true,
}))
) {
throw new Meteor.Error('error-could-not-save-identity', 'Could not save user identity', {
Expand Down
129 changes: 93 additions & 36 deletions apps/meteor/app/lib/server/functions/saveUserIdentity.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { IUser } from '@rocket.chat/core-typings';
import { Messages, VideoConference, LivechatDepartmentAgents, Rooms, Subscriptions, Users } from '@rocket.chat/models';

import { SystemLogger } from '../../../../server/lib/logger/system';
import { FileUpload } from '../../../file-upload/server';
import { _setRealName } from './setRealName';
import { _setUsername } from './setUsername';
Expand All @@ -11,7 +13,17 @@ import { validateName } from './validateName';
* @param {object} changes changes to the user
*/

export async function saveUserIdentity({ _id, name: rawName, username: rawUsername }: { _id: string; name?: string; username?: string }) {
export async function saveUserIdentity({
_id,
name: rawName,
username: rawUsername,
updateUsernameInBackground = false,
}: {
_id: string;
name?: string;
username?: string;
updateUsernameInBackground?: boolean; // TODO: remove this
}) {
if (!_id) {
return false;
}
Expand Down Expand Up @@ -48,46 +60,91 @@ export async function saveUserIdentity({ _id, name: rawName, username: rawUserna

// if coming from old username, update all references
if (previousUsername) {
if (usernameChanged && typeof rawUsername !== 'undefined') {
const fileStore = FileUpload.getStore('Avatars');
const previousFile = await fileStore.model.findOneByName(previousUsername);
const file = await fileStore.model.findOneByName(username);
if (file) {
await fileStore.model.deleteFile(file._id);
}
if (previousFile) {
await fileStore.model.updateFileNameById(previousFile._id, username);
}

await Messages.updateAllUsernamesByUserId(user._id, username);
await Messages.updateUsernameOfEditByUserId(user._id, username);

const cursor = Messages.findByMention(previousUsername);
for await (const msg of cursor) {
const updatedMsg = msg.msg.replace(new RegExp(`@${previousUsername}`, 'ig'), `@${username}`);
await Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg);
}

await Rooms.replaceUsername(previousUsername, username);
await Rooms.replaceMutedUsername(previousUsername, username);
await Rooms.replaceUsernameOfUserByUserId(user._id, username);
await Subscriptions.setUserUsernameByUserId(user._id, username);

await LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username);
const handleUpdateParams = {
username,
previousUsername,
rawUsername,
usernameChanged,
user,
name,
previousName,
rawName,
nameChanged,
};
if (updateUsernameInBackground) {
setImmediate(async () => {
try {
await updateUsernameReferences(handleUpdateParams);
} catch (err) {
SystemLogger.error(err);
}
});
} else {
await updateUsernameReferences(handleUpdateParams);
}
}

return true;
}

// update other references if either the name or username has changed
if (usernameChanged || nameChanged) {
// update name and fname of 1-on-1 direct messages
await Subscriptions.updateDirectNameAndFnameByName(previousUsername, rawUsername && username, rawName && name);
async function updateUsernameReferences({
username,
previousUsername,
rawUsername,
usernameChanged,
user,
name,
previousName,
rawName,
nameChanged,
}: {
username: string;
previousUsername: string;
rawUsername?: string;
usernameChanged: boolean;
user: IUser;
name: string;
previousName: string | undefined;
rawName?: string;
nameChanged: boolean;
}): Promise<void> {
if (usernameChanged && typeof rawUsername !== 'undefined') {
const fileStore = FileUpload.getStore('Avatars');
const previousFile = await fileStore.model.findOneByName(previousUsername);
const file = await fileStore.model.findOneByName(username);
if (file) {
await fileStore.model.deleteFile(file._id);
}
if (previousFile) {
await fileStore.model.updateFileNameById(previousFile._id, username);
}

// update name and fname of group direct messages
await updateGroupDMsName(user);
await Messages.updateAllUsernamesByUserId(user._id, username);
await Messages.updateUsernameOfEditByUserId(user._id, username);

// update name and username of users on video conferences
await VideoConference.updateUserReferences(user._id, username || previousUsername, name || previousName);
const cursor = Messages.findByMention(previousUsername);
for await (const msg of cursor) {
const updatedMsg = msg.msg.replace(new RegExp(`@${previousUsername}`, 'ig'), `@${username}`);
await Messages.updateUsernameAndMessageOfMentionByIdAndOldUsername(msg._id, previousUsername, username, updatedMsg);
}

await Rooms.replaceUsername(previousUsername, username);
await Rooms.replaceMutedUsername(previousUsername, username);
await Rooms.replaceUsernameOfUserByUserId(user._id, username);
await Subscriptions.setUserUsernameByUserId(user._id, username);

await LivechatDepartmentAgents.replaceUsernameOfAgentByUserId(user._id, username);
}

return true;
// update other references if either the name or username has changed
if (usernameChanged || nameChanged) {
// update name and fname of 1-on-1 direct messages
await Subscriptions.updateDirectNameAndFnameByName(previousUsername, rawUsername && username, rawName && name);

// update name and fname of group direct messages
await updateGroupDMsName(user);

// update name and username of users on video conferences
await VideoConference.updateUserReferences(user._id, username || previousUsername, name || previousName);
}
}
2 changes: 1 addition & 1 deletion apps/meteor/client/components/avatar/RoomAvatarEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const RoomAvatarEditor = ({ disabled = false, room, roomAvatar, onChangeAvatar }
danger
icon='trash'
title={t('Accounts_SetDefaultAvatar')}
disabled={roomAvatar === null || isRoomFederated(room) || disabled}
disabled={!roomAvatar || isRoomFederated(room) || disabled}
onClick={clickReset}
/>
</ButtonGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@ const getMessage = (room: IRoom, lastMessage: IMessage | undefined, t: ReturnTyp
return `${lastMessage.u.name || lastMessage.u.username}: ${normalizeSidebarMessage(lastMessage, t)}`;
};

const getBadgeTitle = (
userMentions: number,
threadUnread: number,
groupMentions: number,
unread: number,
t: ReturnType<typeof useTranslation>,
) => {
const title = [] as string[];
if (userMentions) {
title.push(t('mentions_counter', { count: userMentions }));
}
if (threadUnread) {
title.push(t('threads_counter', { count: threadUnread }));
}
if (groupMentions) {
title.push(t('group_mentions_counter', { count: groupMentions }));
}
const count = unread - userMentions - groupMentions;
if (count > 0) {
title.push(t('unread_messages_counter', { count }));
}
return title.join(', ');
};

type RoomListRowProps = {
extended: boolean;
t: ReturnType<typeof useTranslation>;
Expand Down Expand Up @@ -137,10 +161,12 @@ function SideBarItemTemplateWithData({
const isUnread = unread > 0 || threadUnread;
const showBadge = !hideUnreadStatus || (!hideMentionStatus && (Boolean(userMentions) || tunreadUser.length > 0));

const badgeTitle = getBadgeTitle(userMentions, tunread.length, groupMentions, unread, t);

const badges = (
<Margins inlineStart={8}>
{showBadge && isUnread && (
<Badge {...({ style: { display: 'inline-flex', flexShrink: 0 } } as any)} variant={variant}>
<Badge {...({ style: { display: 'inline-flex', flexShrink: 0 } } as any)} variant={variant} title={badgeTitle}>
{unread + tunread?.length}
</Badge>
)}
Expand Down
Loading

0 comments on commit e7992ff

Please sign in to comment.