Skip to content

Commit

Permalink
[NEW] Teams (#20966)
Browse files Browse the repository at this point in the history
  • Loading branch information
gabriellsh authored Mar 24, 2021
1 parent 499b110 commit b543d0c
Show file tree
Hide file tree
Showing 197 changed files with 7,929 additions and 667 deletions.
1 change: 1 addition & 0 deletions app/api/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ import './v1/custom-user-status';
import './v1/instances';
import './v1/banners';
import './v1/email-inbox';
import './v1/teams';

export { API, APIClass, defaultRateLimiterOptions } from './api';
21 changes: 16 additions & 5 deletions app/api/server/lib/rooms.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { Rooms } from '../../../models/server/raw';
import { Subscriptions } from '../../../models';

export async function findAdminRooms({ uid, filter, types = [], pagination: { offset, count, sort } }) {
if (!await hasPermissionAsync(uid, 'view-room-administration')) {
Expand All @@ -24,24 +25,30 @@ export async function findAdminRooms({ uid, filter, types = [], pagination: { of
msgs: 1,
archived: 1,
tokenpass: 1,
teamId: 1,
teamMain: 1,
};

const name = filter && filter.trim();
const discussion = types && types.includes('discussions');
const showTypes = Array.isArray(types) ? types.filter((type) => type !== 'discussions') : [];
const includeTeams = types && types.includes('teams');
const typesToRemove = ['discussions', 'teams'];
const showTypes = Array.isArray(types) ? types.filter((type) => !typesToRemove.includes(type)) : [];
const options = {
fields,
sort: sort || { default: -1, name: 1 },
skip: offset,
limit: count,
};

let cursor = Rooms.findByNameContaining(name, discussion, options);
let cursor;

if (name && showTypes.length) {
cursor = Rooms.findByNameContainingAndTypes(name, showTypes, discussion, options);
cursor = Rooms.findByNameContainingAndTypes(name, showTypes, discussion, includeTeams, options);
} else if (showTypes.length) {
cursor = Rooms.findByTypes(showTypes, discussion, options);
cursor = Rooms.findByTypes(showTypes, discussion, includeTeams, options);
} else {
cursor = Rooms.findByNameContaining(name, discussion, includeTeams, options);
}

const total = await cursor.count();
Expand Down Expand Up @@ -93,6 +100,7 @@ export async function findChannelAndPrivateAutocomplete({ uid, selector }) {
const options = {
fields: {
_id: 1,
fname: 1,
name: 1,
t: 1,
avatarETag: 1,
Expand All @@ -102,8 +110,11 @@ export async function findChannelAndPrivateAutocomplete({ uid, selector }) {
name: 1,
},
};
const userRooms = Subscriptions.cachedFindByUserId(uid, { fields: { rid: 1 } })
.fetch()
.map((item) => item.rid);

const rooms = await Rooms.findChannelAndPrivateByNameStarting(selector.name, options).toArray();
const rooms = await Rooms.findChannelAndPrivateByNameStarting(selector.name, userRooms, options).toArray();

return {
items: rooms,
Expand Down
92 changes: 91 additions & 1 deletion app/api/server/v1/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Meteor } from 'meteor/meteor';
import _ from 'underscore';

import { Rooms, Subscriptions, Messages, Uploads, Integrations, Users } from '../../../models';
import { hasPermission, hasAtLeastOnePermission } from '../../../authorization/server';
import { hasPermission, hasAtLeastOnePermission, hasAllPermission } from '../../../authorization/server';
import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { API } from '../api';
import { settings } from '../../../settings';
import { Team } from '../../../../server/sdk';


// Returns the channel IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
Expand Down Expand Up @@ -184,6 +185,10 @@ function createChannelValidator(params) {
if (params.customFields && params.customFields.value && !(typeof params.customFields.value === 'object')) {
throw new Error(`Param "${ params.customFields.key }" must be an object if provided`);
}

if (params.teams.value && !Array.isArray(params.teams.value)) {
throw new Error(`Param ${ params.teams.key } must be an array`);
}
}

function createChannel(userId, params) {
Expand Down Expand Up @@ -220,6 +225,10 @@ API.v1.addRoute('channels.create', { authRequired: true }, {
value: bodyParams.members,
key: 'members',
},
teams: {
value: bodyParams.teams,
key: 'teams',
},
});
} catch (e) {
if (e.message === 'unauthorized') {
Expand All @@ -233,6 +242,21 @@ API.v1.addRoute('channels.create', { authRequired: true }, {
return error;
}

if (bodyParams.teams) {
const canSeeAllTeams = hasPermission(this.userId, 'view-all-teams');
const teams = Promise.await(Team.listByNames(bodyParams.teams, { projection: { _id: 1 } }));
const teamMembers = [];

for (const team of teams) {
const { records: members } = Promise.await(Team.members(this.userId, team._id, undefined, canSeeAllTeams, { offset: 0, count: Number.MAX_SAFE_INTEGER }));
const uids = members.map((member) => member.user.username);
teamMembers.push(...uids);
}

const membersToAdd = new Set([...teamMembers, ...bodyParams.members]);
bodyParams.members = [...membersToAdd];
}

return API.v1.success(API.channels.create.execute(userId, bodyParams));
},
});
Expand Down Expand Up @@ -472,6 +496,24 @@ API.v1.addRoute('channels.list', { authRequired: true }, {
ourQuery._id = { $in: roomIds };
}

// teams filter - I would love to have a way to apply this filter @ db level :(
const ids = Subscriptions.cachedFindByUserId(this.userId, { fields: { rid: 1 } })
.fetch()
.map((item) => item.rid);

ourQuery.$or = [{
teamId: {
$exists: false,
},
}, {
teamId: {
$exists: true,
},
_id: {
$in: ids,
},
}];

const cursor = Rooms.find(ourQuery, {
sort: sort || { name: 1 },
skip: offset,
Expand Down Expand Up @@ -1050,3 +1092,51 @@ API.v1.addRoute('channels.anonymousread', { authRequired: false }, {
});
},
});

API.v1.addRoute('channels.convertToTeam', { authRequired: true }, {
post() {
if (!hasAllPermission(this.userId, ['create-team', 'edit-room'])) {
return API.v1.unauthorized();
}

const { channelId, channelName } = this.bodyParams;

if (!channelId && !channelName) {
return API.v1.failure('The parameter "channelId" or "channelName" is required');
}

const room = findChannelByIdOrName({
params: {
roomId: channelId,
roomName: channelName,
},
userId: this.userId,
});

if (!room) {
return API.v1.failure('Channel not found');
}

const subscriptions = Subscriptions.findByRoomId(room._id, {
fields: { 'u._id': 1 },
});

const members = subscriptions.fetch().map((s) => s.u && s.u._id);

const teamData = {
team: {
name: room.name,
type: room.t === 'c' ? 0 : 1,
},
members,
room: {
name: room.name,
id: room._id,
},
};

const team = Promise.await(Team.create(this.userId, teamData));

return API.v1.success({ team });
},
});
51 changes: 50 additions & 1 deletion app/api/server/v1/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { Match } from 'meteor/check';

import { mountIntegrationQueryBasedOnPermissions } from '../../../integrations/server/lib/mountQueriesBasedOnPermission';
import { Subscriptions, Rooms, Messages, Uploads, Integrations, Users } from '../../../models/server';
import { hasPermission, hasAtLeastOnePermission, canAccessRoom } from '../../../authorization/server';
import { hasPermission, hasAtLeastOnePermission, canAccessRoom, hasAllPermission } from '../../../authorization/server';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { API } from '../api';
import { Team } from '../../../../server/sdk';

// Returns the private group subscription IF found otherwise it will return the failure of why it didn't. Check the `statusCode` property
export function findPrivateGroupByIdOrName({ params, userId, checkedArchived = true }) {
Expand Down Expand Up @@ -840,3 +841,51 @@ API.v1.addRoute('groups.setEncrypted', { authRequired: true }, {
});
},
});

API.v1.addRoute('groups.convertToTeam', { authRequired: true }, {
post() {
if (!hasAllPermission(this.userId, ['create-team', 'edit-room'])) {
return API.v1.unauthorized();
}

const { roomId, roomName } = this.requestParams();

if (!roomId && !roomName) {
return API.v1.failure('The parameter "roomId" or "roomName" is required');
}

const room = findPrivateGroupByIdOrName({
params: {
roomId,
roomName,
},
userId: this.userId,
});

if (!room) {
return API.v1.failure('Private group not found');
}

const subscriptions = Subscriptions.findByRoomId(room.rid, {
fields: { 'u._id': 1 },
});

const members = subscriptions.fetch().map((s) => s.u && s.u._id);

const teamData = {
team: {
name: room.name,
type: 1,
},
members,
room: {
name: room.name,
id: room.rid,
},
};

const team = Promise.await(Team.create(this.userId, teamData));

return API.v1.success({ team });
},
});
Loading

0 comments on commit b543d0c

Please sign in to comment.