Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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