Skip to content
Closed
Changes from 3 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 91 additions & 39 deletions apps/meteor/app/api/server/v1/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,52 @@ const isChatPinMessageProps = ajv.compile<ChatPinMessage>(ChatPinMessageSchema);

const isChatUnpinMessageProps = ajv.compile<ChatUnpinMessage>(ChatUnpinMessageSchema);

const isSyncThreadMessagesResponse = ajv.compile<{
messages: {
update: Partial<IMessage>[];
remove: Partial<IMessage>[];
};
}>({
type: 'object',
properties: {
messages: {
type: 'object',
properties: {
update: {
type: 'array',
items: {
type: 'object',
properties: {
_id: { type: 'string' },
},
required: ['_id'],
additionalProperties: true,
},
},
remove: {
type: 'array',
items: {
type: 'object',
properties: {
_id: { type: 'string' },
},
required: ['_id'],
additionalProperties: true,
},
},
},
required: ['update', 'remove'],
additionalProperties: false,
},
success: {
type: 'boolean',
enum: [true],
},
},
required: ['messages', 'success'],
additionalProperties: false,
});

const chatEndpoints = API.v1
.post(
'chat.pinMessage',
Expand Down Expand Up @@ -558,6 +604,51 @@ const chatEndpoints = API.v1

return API.v1.success();
},
)
.get(
'chat.syncThreadMessages',
{
authRequired: true,
query: isChatSyncThreadMessagesProps,
response: {
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
200: isSyncThreadMessagesResponse,
},
},
async function action() {
const { tmid } = this.queryParams;
const { query, fields, sort } = await this.parseJsonQuery();
const { updatedSince } = this.queryParams;
let updatedSinceDate;
if (!settings.get<boolean>('Threads_enabled')) {
throw new Meteor.Error('error-not-allowed', 'Threads Disabled');
}

if (isNaN(Date.parse(updatedSince))) {
throw new Meteor.Error('error-updatedSince-param-invalid', 'The "updatedSince" query parameter must be a valid date.');
} else {
updatedSinceDate = new Date(updatedSince);
}
const thread = await Messages.findOneById(tmid, { projection: { rid: 1 } });
if (!thread?.rid) {
throw new Meteor.Error('error-invalid-message', 'Invalid Message');
}
const [user, room] = await Promise.all([
Users.findOneById(this.userId, { projection: { _id: 1 } }),
Rooms.findOneById(thread.rid, { projection: { ...roomAccessAttributes, t: 1, _id: 1 } }),
]);

if (!room || !user || !(await canAccessRoomAsync(room, user))) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}
return API.v1.success({
messages: {
update: await Messages.find({ ...query, tmid, _updatedAt: { $gt: updatedSinceDate } }, { projection: fields, sort }).toArray(),
remove: await Messages.trashFindDeletedAfter(updatedSinceDate, { ...query, tmid }, { projection: fields, sort }).toArray(),
},
});
},
);

API.v1.addRoute(
Expand Down Expand Up @@ -918,45 +1009,6 @@ API.v1.addRoute(
},
);

API.v1.addRoute(
'chat.syncThreadMessages',
{ authRequired: true, validateParams: isChatSyncThreadMessagesProps },
{
async get() {
const { tmid } = this.queryParams;
const { query, fields, sort } = await this.parseJsonQuery();
const { updatedSince } = this.queryParams;
let updatedSinceDate;
if (!settings.get<boolean>('Threads_enabled')) {
throw new Meteor.Error('error-not-allowed', 'Threads Disabled');
}

if (isNaN(Date.parse(updatedSince))) {
throw new Meteor.Error('error-updatedSince-param-invalid', 'The "updatedSince" query parameter must be a valid date.');
} else {
updatedSinceDate = new Date(updatedSince);
}
const thread = await Messages.findOneById(tmid, { projection: { rid: 1 } });
if (!thread?.rid) {
throw new Meteor.Error('error-invalid-message', 'Invalid Message');
}
// TODO: promise.all? this.user?
const user = await Users.findOneById(this.userId, { projection: { _id: 1 } });
const room = await Rooms.findOneById(thread.rid, { projection: { ...roomAccessAttributes, t: 1, _id: 1 } });

if (!room || !user || !(await canAccessRoomAsync(room, user))) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}
return API.v1.success({
messages: {
update: await Messages.find({ ...query, tmid, _updatedAt: { $gt: updatedSinceDate } }, { projection: fields, sort }).toArray(),
remove: await Messages.trashFindDeletedAfter(updatedSinceDate, { ...query, tmid }, { projection: fields, sort }).toArray(),
},
});
},
},
);

API.v1.addRoute(
'chat.getMentionedMessages',
{ authRequired: true, validateParams: isChatGetMentionedMessagesProps },
Expand Down