Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
8 changes: 8 additions & 0 deletions app/models/server/lib/setUpdatedAt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function setUpdatedAt(record: Record<string, any>): void {
if (/(^|,)\$/.test(Object.keys(record).join(','))) {
record.$set = record.$set || {};
record.$set._updatedAt = new Date();
} else {
record._updatedAt = new Date();
}
}
8 changes: 2 additions & 6 deletions app/models/server/models/_BaseDb.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Match } from 'meteor/check';
import { Mongo } from 'meteor/mongo';
import _ from 'underscore';

import { setUpdatedAt } from '../lib/setUpdatedAt';
import { metrics } from '../../../metrics/server/lib/metrics';
import { getOplogHandle } from './_oplogHandle';

Expand Down Expand Up @@ -111,12 +112,7 @@ export class BaseDb extends EventEmitter {
// }
// }

if (/(^|,)\$/.test(Object.keys(record).join(','))) {
record.$set = record.$set || {};
record.$set._updatedAt = new Date();
} else {
record._updatedAt = new Date();
}
setUpdatedAt(record);

return record;
}
Expand Down
14 changes: 12 additions & 2 deletions app/models/server/raw/BaseRaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
WriteOpResult,
} from 'mongodb';

import { setUpdatedAt } from '../lib/setUpdatedAt';

// [extracted from @types/mongo] TypeScript Omit (Exclude to be specific) does not work for objects with an "any" indexed type, and breaks discriminated unions
type EnhancedOmit<T, K> = string | number extends keyof T
? T // T has indexed type e.g. { _id: string; [k: string]: any; } or it is "any"
Expand All @@ -35,6 +37,8 @@ type ExtractIdType<TSchema> = TSchema extends { _id: infer U } // user has defin
: ObjectId;

type ModelOptionalId<T> = EnhancedOmit<T, '_id'> & { _id?: ExtractIdType<T> };
// InsertionModel forces both _id and _updatedAt to be optional, regardless of how they are declared in T
export type InsertionModel<T> = EnhancedOmit<ModelOptionalId<T>, '_updatedAt'> & { _updatedAt?: Date };

interface ITrash {
__collection__: string;
Expand Down Expand Up @@ -103,36 +107,42 @@ export class BaseRaw<T> implements IBaseRaw<T> {
}

update(filter: FilterQuery<T>, update: UpdateQuery<T> | Partial<T>, options?: UpdateOneOptions & { multi?: boolean }): Promise<WriteOpResult> {
setUpdatedAt(update);
return this.col.update(filter, update, options);
}

updateOne(filter: FilterQuery<T>, update: UpdateQuery<T> | Partial<T>, options?: UpdateOneOptions & { multi?: boolean }): Promise<UpdateWriteOpResult> {
setUpdatedAt(update);
return this.col.updateOne(filter, update, options);
}

updateMany(filter: FilterQuery<T>, update: UpdateQuery<T> | Partial<T>, options?: UpdateManyOptions): Promise<UpdateWriteOpResult> {
setUpdatedAt(update);
return this.col.updateMany(filter, update, options);
}

insertMany(docs: Array<ModelOptionalId<T>>, options?: CollectionInsertOneOptions): Promise<InsertWriteOpResult<WithId<T>>> {
insertMany(docs: Array<InsertionModel<T>>, options?: CollectionInsertOneOptions): Promise<InsertWriteOpResult<WithId<T>>> {
docs = docs.map((doc) => {
if (!doc._id || typeof doc._id !== 'string') {
const oid = new ObjectID();
return { _id: oid.toHexString(), ...doc };
}
setUpdatedAt(doc);
return doc;
});

// TODO reavaluate following type casting
return this.col.insertMany(docs as unknown as Array<OptionalId<T>>, options);
}

insertOne(doc: ModelOptionalId<T>, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult<WithId<T>>> {
insertOne(doc: InsertionModel<T>, options?: CollectionInsertOneOptions): Promise<InsertOneWriteOpResult<WithId<T>>> {
if (!doc._id || typeof doc._id !== 'string') {
const oid = new ObjectID();
doc = { _id: oid.toHexString(), ...doc };
}

setUpdatedAt(doc);

// TODO reavaluate following type casting
return this.col.insertOne(doc as unknown as OptionalId<T>, options);
}
Expand Down
4 changes: 2 additions & 2 deletions app/models/server/raw/Team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class TeamRaw extends BaseRaw<T> {
}

updateMainRoomForTeam(id: string, roomId: string): Promise<UpdateWriteOpResult> {
return this.col.updateOne({
return this.updateOne({
_id: id,
}, {
$set: {
Expand Down Expand Up @@ -92,6 +92,6 @@ export class TeamRaw extends BaseRaw<T> {
Object.assign(update.$set, { type: nameAndType.type });
}

return this.col.updateOne(query, update);
return this.updateOne(query, update);
}
}
7 changes: 3 additions & 4 deletions app/models/server/raw/TeamMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,20 @@ export class TeamMemberRaw extends BaseRaw<T> {
}

updateOneByUserIdAndTeamId(userId: string, teamId: string, update: Partial<T>): Promise<UpdateWriteOpResult> {
return this.col.updateOne({ userId, teamId }, { $set: update });
return this.updateOne({ userId, teamId }, { $set: update });
}

createOneByTeamIdAndUserId(teamId: string, userId: string, createdBy: Pick<IUser, '_id' | 'username'>): Promise<InsertOneWriteOpResult<T>> {
return this.insertOne({
teamId,
userId,
createdAt: new Date(),
_updatedAt: new Date(),
createdBy,
});
}

updateRolesByTeamIdAndUserId(teamId: string, userId: string, roles: Array<string>): Promise<UpdateWriteOpResult> {
return this.col.updateOne({
return this.updateOne({
teamId,
userId,
}, {
Expand All @@ -90,7 +89,7 @@ export class TeamMemberRaw extends BaseRaw<T> {
}

removeRolesByTeamIdAndUserId(teamId: string, userId: string, roles: Array<string>): Promise<UpdateWriteOpResult> {
return this.col.updateOne({
return this.updateOne({
teamId,
userId,
}, {
Expand Down
9 changes: 3 additions & 6 deletions server/services/team/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { checkUsernameAvailability } from '../../../app/lib/server/functions';
import { addUserToRoom } from '../../../app/lib/server/functions/addUserToRoom';
import { removeUserFromRoom } from '../../../app/lib/server/functions/removeUserFromRoom';
import { getSubscribedRoomsForUserWithDetails } from '../../../app/lib/server/functions/getRoomsWithSingleOwner';
import type { InsertionModel } from '../../../app/models/server/raw/BaseRaw';
import { MessagesRaw } from '../../../app/models/server/raw/Messages';
import { RoomsRaw } from '../../../app/models/server/raw/Rooms';
import { SubscriptionsRaw } from '../../../app/models/server/raw/Subscriptions';
Expand Down Expand Up @@ -100,14 +101,13 @@ export class TeamService extends ServiceClass implements ITeamService {
const excludeFromMembers = owner ? [owner] : [uid];

// filter empty strings and falsy values from members list
const membersList: Array<Omit<ITeamMember, '_id'>> = members?.filter(Boolean)
const membersList: Array<InsertionModel<ITeamMember>> = members?.filter(Boolean)
.filter((memberId) => !excludeFromMembers.includes(memberId))
.map((memberId) => ({
teamId,
userId: memberId,
createdAt: new Date(),
createdBy,
_updatedAt: new Date(), // TODO how to avoid having to do this?
})) || [];

membersList.push({
Expand All @@ -116,7 +116,6 @@ export class TeamService extends ServiceClass implements ITeamService {
roles: ['owner'],
createdAt: new Date(),
createdBy,
_updatedAt: new Date(), // TODO how to avoid having to do this?
});

await this.TeamMembersModel.insertMany(membersList);
Expand Down Expand Up @@ -560,13 +559,12 @@ export class TeamService extends ServiceClass implements ITeamService {
throw new Error('invalid-user');
}

const membersList: Array<Omit<ITeamMember, '_id'>> = members?.map((member) => ({
const membersList: Array<InsertionModel<ITeamMember>> = members?.map((member) => ({
teamId,
userId: member.userId,
roles: member.roles || [],
createdAt: new Date(),
createdBy,
_updatedAt: new Date(), // TODO how to avoid having to do this?
})) || [];

await this.TeamMembersModel.insertMany(membersList);
Expand All @@ -580,7 +578,6 @@ export class TeamService extends ServiceClass implements ITeamService {

const memberUpdate: Partial<ITeamMember> = {
roles: member.roles ? member.roles : [],
_updatedAt: new Date(),
};

await this.TeamMembersModel.updateOneByUserIdAndTeamId(member.userId, teamId, memberUpdate);
Expand Down