Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
b5f8e93
Add property to identify main team room
KevLehman Mar 12, 2021
1875719
Add missing types
KevLehman Mar 12, 2021
a63eb72
Add Team Members' endpoints
Mar 12, 2021
5abc8ee
Change members method's return type
matheusbsilva137 Mar 12, 2021
281b2c6
Add ITeamMember import
matheusbsilva137 Mar 12, 2021
bee07e0
Add tests to the new endpoints
matheusbsilva137 Mar 13, 2021
a64e661
Move permission checks to endpoints
matheusbsilva137 Mar 13, 2021
77ca408
Fix services parameters
matheusbsilva137 Mar 13, 2021
e00904e
Fix PR comments
KevLehman Mar 15, 2021
4b8ffa5
Return team member element on addMember call
KevLehman Mar 15, 2021
bb8585e
Reflect role changes on other room role changes
KevLehman Mar 15, 2021
f6d1e81
Merge branch 'new/teams-back' into new/teams-mainroom
pierre-lehnen-rc Mar 15, 2021
811f2c7
Merge branch 'new/teams-mainroom' of github.com:RocketChat/Rocket.Cha…
pierre-lehnen-rc Mar 15, 2021
ecdd312
Fix queries' formats and add members' verifications to tests
matheusbsilva137 Mar 15, 2021
ec4869d
Merge pull request #21097 from RocketChat/new/teams-mainroom
pierre-lehnen-rc Mar 15, 2021
5ad8ed1
Merge branch 'new/teams-back' into new/teams-back-add-members
matheusbsilva137 Mar 15, 2021
893f973
Remove unused imports
matheusbsilva137 Mar 15, 2021
7c418fa
Add missing import
matheusbsilva137 Mar 15, 2021
bbc717a
Fix verifications in tests
matheusbsilva137 Mar 16, 2021
b84c358
Fix tests and remove unused variables
matheusbsilva137 Mar 16, 2021
545a39d
Update app/api/server/v1/teams.ts
pierre-lehnen-rc Mar 16, 2021
51853eb
Update app/api/server/v1/teams.ts
pierre-lehnen-rc Mar 16, 2021
44657ed
Update app/api/server/v1/teams.ts
pierre-lehnen-rc Mar 16, 2021
3a30713
Update app/api/server/v1/teams.ts
pierre-lehnen-rc Mar 16, 2021
b89d0f4
Removed blank line
pierre-lehnen-rc Mar 16, 2021
806c3f0
Merge pull request #21099 from RocketChat/new/teams-back-add-members
pierre-lehnen-rc Mar 16, 2021
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
71 changes: 65 additions & 6 deletions app/api/server/v1/teams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Promise } from 'meteor/promise';

import { API } from '../api';
import { Team } from '../../../../server/sdk';
import { hasPermission } from '../../../authorization/server';
import { hasAtLeastOnePermission, hasPermission } from '../../../authorization/server';

API.v1.addRoute('teams.list', { authRequired: true }, {
get() {
Expand Down Expand Up @@ -40,6 +40,9 @@ API.v1.addRoute('teams.listAll', { authRequired: true }, {

API.v1.addRoute('teams.create', { authRequired: true }, {
post() {
if (!hasPermission(this.userId, 'create-team')) {
return API.v1.unauthorized();
}
const { name, type, members, room, owner } = this.bodyParams;

if (!name) {
Expand All @@ -62,15 +65,71 @@ API.v1.addRoute('teams.create', { authRequired: true }, {

API.v1.addRoute('teams.members', { authRequired: true }, {
get() {
const { teamId } = this.queryParams;
const { offset, count } = this.getPaginationItems();
const { teamId, teamName } = this.queryParams;

const { records, total } = Promise.await(Team.members(teamId, teamName, { offset, count }));

return API.v1.success({
members: records,
total,
count: records.length,
offset,
});
},
});

API.v1.addRoute('teams.addMembers', { authRequired: true }, {
post() {
if (!hasAtLeastOnePermission(this.userId, ['add-team-member', 'edit-team-member'])) {
return API.v1.unauthorized();
}

const { teamId, teamName, members } = this.bodyParams;

Promise.await(Team.addMembers(this.userId, teamId, teamName, members));

return API.v1.success();
},
});

API.v1.addRoute('teams.updateMember', { authRequired: true }, {
post() {
if (!hasAtLeastOnePermission(this.userId, ['edit-team-member'])) {
return API.v1.unauthorized();
}

const { teamId, teamName, member } = this.bodyParams;

Promise.await(Team.updateMember(teamId, teamName, member));

return API.v1.success();
},
});

if (!teamId) {
return API.v1.failure('Team ID is required');
API.v1.addRoute('teams.removeMembers', { authRequired: true }, {
post() {
if (!hasAtLeastOnePermission(this.userId, ['edit-team-member'])) {
return API.v1.unauthorized();
}

const members = Promise.await(Team.members(this.userId, teamId));
const { teamId, teamName, members } = this.bodyParams;

Promise.await(Team.removeMembers(teamId, teamName, members));

return API.v1.success();
},
});

API.v1.addRoute('teams.leave', { authRequired: true }, {
post() {
const { teamId, teamName } = this.bodyParams;

Promise.await(Team.removeMembers(teamId, teamName, [{
userId: this.userId,
}]));

return API.v1.success({ members });
return API.v1.success();
},
});

Expand Down
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,
},
});
}
}
39 changes: 38 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,40 @@ export class TeamMemberRaw extends BaseRaw<T> {
findByTeamId(teamId: string, options?: FindOneOptions<T>): Cursor<T> {
return this.col.find({ teamId }, options);
}

updateOneByUserIdAndTeamId(userId: string, teamId: string, update: Partial<T>): Promise<UpdateWriteOpResult> {
return this.col.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({
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
11 changes: 10 additions & 1 deletion server/sdk/types/ITeamService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,20 @@ export interface ITeamCreateParams {
owner?: string; // the team owner. If not present, owner = requester
}

export interface ITeamMemberParams {
userId?: string;
userName?: string;
roles?: Array<string>;
}

export interface ITeamService {
create(uid: string, params: ITeamCreateParams): Promise<ITeam>;
list(uid: string, options?: IPaginationOptions): Promise<IRecordsWithTotal<ITeam>>;
listAll(options?: IPaginationOptions): Promise<IRecordsWithTotal<ITeam>>;
members(uid: string, teamId: string): Promise<Array<ITeamMember>>;
members(teamId: string, teamName: string, options?: IPaginationOptions): Promise<IRecordsWithTotal<ITeamMember>>;
addMembers(uid: string, teamId: string, teamName: string, members: Array<ITeamMemberParams>): Promise<void>;
updateMember(teamId: string, teamName: string, members: ITeamMemberParams): Promise<void>;
removeMembers(teamId: string, teamName: string, members: Array<ITeamMemberParams>): Promise<void>;
getInfoByName(teamName: string): Promise<Partial<ITeam> | undefined>;
getInfoById(teamId: string): Promise<Partial<ITeam> | undefined>;
}
Loading