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
6 changes: 6 additions & 0 deletions app/lib/server/functions/addUserToRoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Meteor } from 'meteor/meteor';
import { AppEvents, Apps } from '../../../apps/server';
import { callbacks } from '../../../callbacks';
import { Messages, Rooms, Subscriptions } from '../../../models';
import { Team } from '../../../../server/sdk';
import { RoomMemberActions, roomTypes } from '../../../utils/server';

export const addUserToRoom = function(rid, user, inviter, silenced) {
Expand Down Expand Up @@ -84,5 +85,10 @@ export const addUserToRoom = function(rid, user, inviter, silenced) {
});
}

if (room.teamMain && room.teamId) {
// if user is joining to main team channel, create a membership
Promise.await(Team.addMember(inviter, user._id, room.teamId));
}

return true;
};
16 changes: 15 additions & 1 deletion app/models/server/raw/Team.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Collection, FindOneOptions, Cursor } from 'mongodb';
import { Collection, FindOneOptions, Cursor, UpdateWriteOpResult } from 'mongodb';

import { BaseRaw } from './BaseRaw';
import { ITeam } from '../../../../definition/ITeam';
Expand All @@ -25,4 +25,18 @@ export class TeamRaw extends BaseRaw<T> {
findOneByName(name: string, options?: FindOneOptions<T>): Promise<T | null> {
return this.col.findOne({ name }, options);
}

findOneByMainRoomId(roomId: string, options?: FindOneOptions<T>): Promise<T | null> {
return this.col.findOne({ roomId }, options);
}

updateMainRoomForTeam(id: string, roomId: string): Promise<UpdateWriteOpResult> {
return this.col.updateOne({
_id: id,
}, {
$set: {
roomId,
},
});
}
}
35 changes: 34 additions & 1 deletion app/models/server/raw/TeamMember.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Collection, FindOneOptions, Cursor } from 'mongodb';
import { Collection, FindOneOptions, Cursor, InsertOneWriteOpResult, UpdateWriteOpResult } from 'mongodb';

import { BaseRaw } from './BaseRaw';
import { ITeamMember } from '../../../../definition/ITeam';
import { IUser } from '../../../../definition/IUser';

type T = ITeamMember;
export class TeamMemberRaw extends BaseRaw<T> {
Expand Down Expand Up @@ -30,4 +31,36 @@ export class TeamMemberRaw extends BaseRaw<T> {
findByTeamId(teamId: string, options?: FindOneOptions<T>): Cursor<T> {
return this.col.find({ teamId }, options);
}

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({
teamId,
userId,
}, {
$addToSet: {
roles: { $each: roles },
},
});
}

removeRolesByTeamIdAndUserId(teamId: string, userId: string, roles: Array<string>): Promise<UpdateWriteOpResult> {
return this.col.updateOne({
teamId,
userId,
}, {
$pull: {
roles: { $in: roles },
},
});
}
}
1 change: 1 addition & 0 deletions definition/ITeam.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum TEAM_TYPE {
export interface ITeam extends IRocketChatRecord {
name: string;
type: TEAM_TYPE;
roomId: string;
createdBy: Pick<IUser, '_id' | 'username' >;
createdAt: Date;
}
Expand Down
6 changes: 6 additions & 0 deletions server/methods/addRoomLeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { hasPermission } from '../../app/authorization';
import { Users, Subscriptions, Messages } from '../../app/models';
import { settings } from '../../app/settings';
import { api } from '../sdk/api';
import { Team } from '../sdk';

Meteor.methods({
addRoomLeader(rid, userId) {
Expand Down Expand Up @@ -57,6 +58,11 @@ Meteor.methods({
role: 'leader',
});

const team = Promise.await(Team.getOneByRoomId(rid));
if (team) {
Promise.await(Team.addRolesToMember(team._id, userId, ['leader']));
}

if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'added',
Expand Down
6 changes: 6 additions & 0 deletions server/methods/addRoomModerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { hasPermission } from '../../app/authorization';
import { Users, Subscriptions, Messages } from '../../app/models';
import { settings } from '../../app/settings';
import { api } from '../sdk/api';
import { Team } from '../sdk';

Meteor.methods({
addRoomModerator(rid, userId) {
Expand Down Expand Up @@ -57,6 +58,11 @@ Meteor.methods({
role: 'moderator',
});

const team = Promise.await(Team.getOneByRoomId(rid));
if (team) {
Promise.await(Team.addRolesToMember(team._id, userId, ['moderator']));
}

if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'added',
Expand Down
6 changes: 6 additions & 0 deletions server/methods/addRoomOwner.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { check } from 'meteor/check';

import { hasPermission } from '../../app/authorization';
import { Users, Subscriptions, Messages } from '../../app/models';
import { Team } from '../sdk';
import { settings } from '../../app/settings';
import { api } from '../sdk/api';

Expand Down Expand Up @@ -57,6 +58,11 @@ Meteor.methods({
role: 'owner',
});

const team = Promise.await(Team.getOneByRoomId(rid));
if (team) {
Promise.await(Team.addRolesToMember(team._id, userId, ['owner']));
}

if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'added',
Expand Down
6 changes: 6 additions & 0 deletions server/methods/removeRoomLeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { hasPermission } from '../../app/authorization';
import { Users, Subscriptions, Messages } from '../../app/models';
import { settings } from '../../app/settings';
import { api } from '../sdk/api';
import { Team } from '../sdk';

Meteor.methods({
removeRoomLeader(rid, userId) {
Expand Down Expand Up @@ -57,6 +58,11 @@ Meteor.methods({
role: 'leader',
});

const team = Promise.await(Team.getOneByRoomId(rid));
if (team) {
Promise.await(Team.removeRolesFromMember(team._id, userId, ['leader']));
}

if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'removed',
Expand Down
6 changes: 6 additions & 0 deletions server/methods/removeRoomModerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { hasPermission } from '../../app/authorization';
import { Users, Subscriptions, Messages } from '../../app/models';
import { settings } from '../../app/settings';
import { api } from '../sdk/api';
import { Team } from '../sdk';

Meteor.methods({
removeRoomModerator(rid, userId) {
Expand Down Expand Up @@ -57,6 +58,11 @@ Meteor.methods({
role: 'moderator',
});

const team = Promise.await(Team.getOneByRoomId(rid));
if (team) {
Promise.await(Team.removeRolesFromMember(team._id, userId, ['moderator']));
}

if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'removed',
Expand Down
6 changes: 6 additions & 0 deletions server/methods/removeRoomOwner.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { hasPermission, getUsersInRole } from '../../app/authorization';
import { Users, Subscriptions, Messages } from '../../app/models';
import { settings } from '../../app/settings';
import { api } from '../sdk/api';
import { Team } from '../sdk';

Meteor.methods({
removeRoomOwner(rid, userId) {
Expand Down Expand Up @@ -64,6 +65,11 @@ Meteor.methods({
role: 'owner',
});

const team = Promise.await(Team.getOneByRoomId(rid));
if (team) {
Promise.await(Team.removeRolesFromMember(team._id, userId, ['owner']));
}

if (settings.get('UI_DisplayRoles')) {
api.broadcast('user.roleUpdate', {
type: 'removed',
Expand Down
3 changes: 2 additions & 1 deletion server/sdk/types/IRoomService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ interface ICreateRoomOptions extends Partial<Record<string, string | ISubscripti
subscriptionExtra?: ISubscriptionExtraData;
}

interface ICreateRoomExtraData extends Record<string, string> {
interface ICreateRoomExtraData extends Record<string, string | boolean> {
teamId: string;
teamMain: boolean;
}

export interface ICreateRoomParams {
Expand Down
49 changes: 47 additions & 2 deletions server/services/team/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TeamRaw } from '../../../app/models/server/raw/Team';
import { ITeam, ITeamMember, TEAM_TYPE, IRecordsWithTotal, IPaginationOptions } from '../../../definition/ITeam';
import { Authorization, Room } from '../../sdk';
import { ITeamCreateParams, ITeamService } from '../../sdk/types/ITeamService';
import { IUser } from '../../../definition/IUser';
import { ServiceClass } from '../../sdk/types/ServiceClass';
import { UsersRaw } from '../../../app/models/server/raw/Users';
import { RoomsRaw } from '../../../app/models/server/raw/Rooms';
Expand Down Expand Up @@ -62,13 +63,18 @@ export class TeamService extends ServiceClass implements ITeamService {
createdAt: new Date(),
createdBy,
_updatedAt: new Date(), // TODO how to avoid having to do this?
roomId: '', // this will be populated at the end
};

try {
const result = await this.TeamModel.insertOne(teamData);
const teamId = result.insertedId;
// the same uid can be passed at 3 positions: owner, member list or via caller
// if the owner is present, remove it from the members list
// if the owner is not present, remove the caller from the members list
const excludeFromMembers = owner ? [owner] : [uid];

const membersList: Array<Omit<ITeamMember, '_id'>> = members?.filter((memberId) => ![uid, owner].includes(memberId))
const membersList: Array<Omit<ITeamMember, '_id'>> = members?.filter((memberId) => !excludeFromMembers.includes(memberId))
.map((memberId) => ({
teamId,
userId: memberId,
Expand Down Expand Up @@ -98,10 +104,13 @@ export class TeamService extends ServiceClass implements ITeamService {
extraData: {
...room.extraData,
teamId,
teamMain: true,
},
};

await Room.create(owner || uid, newRoom);
const createdRoom = await Room.create(owner || uid, newRoom);

await this.TeamModel.updateMainRoomForTeam(teamId, createdRoom._id);

return {
_id: teamId,
Expand Down Expand Up @@ -160,6 +169,42 @@ export class TeamService extends ServiceClass implements ITeamService {
return this.TeamMembersModel.findByTeamId(teamId).toArray();
}

async addMember({ _id, username }: IUser, userId: string, teamId: string): Promise<boolean | ITeamMember> {
const isAlreadyAMember = await this.TeamMembersModel.findOneByUserIdAndTeamId(userId, teamId, { projection: { _id: 1 } });

if (isAlreadyAMember) {
return false;
}

return (await this.TeamMembersModel.createOneByTeamIdAndUserId(teamId, userId, { _id, username })).ops[0];
}

async getOneByRoomId(roomId: string): Promise<ITeam | null> {
return this.TeamModel.findOneByMainRoomId(roomId, { projection: { _id: 1 } });
}

async addRolesToMember(teamId: string, userId: string, roles: Array<string>): Promise<boolean> {
const isMember = await this.TeamMembersModel.findOneByUserIdAndTeamId(userId, teamId, { projection: { _id: 1 } });

if (!isMember) {
// TODO should this throw an error instead?
return false;
}

return !!await this.TeamMembersModel.updateRolesByTeamIdAndUserId(teamId, userId, roles);
}

async removeRolesFromMember(teamId: string, userId: string, roles: Array<string>): Promise<boolean> {
const isMember = await this.TeamMembersModel.findOneByUserIdAndTeamId(userId, teamId, { projection: { _id: 1 } });

if (!isMember) {
// TODO should this throw an error instead?
return false;
}

return !!await this.TeamMembersModel.removeRolesByTeamIdAndUserId(teamId, userId, roles);
}

async getInfoByName(teamName: string): Promise<Partial<ITeam> | undefined> {
return this.TeamModel.findOne({
name: teamName,
Expand Down