...
 
Commits (15)
......@@ -3,6 +3,7 @@ import { Match, check } from 'meteor/check';
import { Roles } from '../../../models';
import { API } from '../api';
import { getUsersInRole, hasPermission } from '../../../authorization/server';
API.v1.addRoute('roles.list', { authRequired: true }, {
get() {
......@@ -55,3 +56,26 @@ API.v1.addRoute('roles.addUserToRole', { authRequired: true }, {
});
},
});
API.v1.addRoute('roles.getUsersInRole', { authRequired: true }, {
get() {
const { roomId, role } = this.queryParams;
const { offset, count } = this.getPaginationItems();
if (!role) {
throw new Meteor.Error('error-param-not-provided', 'Query param "role" is required');
}
if (!hasPermission(this.userId, 'access-permissions')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
if (roomId && !hasPermission(this.userId, 'view-other-user-channels')) {
throw new Meteor.Error('error-not-allowed', 'Not allowed');
}
const users = getUsersInRole(role, roomId, {
limit: count || 50,
sort: { username: 1 },
skip: offset,
fields: API.v1.limitedUserFieldsToExclude,
}).fetch();
return API.v1.success({ users });
},
});
......@@ -11,6 +11,20 @@ import { Roles } from '../../../models';
import { hasAllPermission } from '../hasPermission';
import { modal } from '../../../ui-utils/client/lib/modal';
import { SideNav } from '../../../ui-utils/client/lib/SideNav';
import { APIClient } from '../../../utils/client';
const loadUsers = async (instance) => {
const limit = instance.limit.get();
const params = {
role: FlowRouter.getParam('name'),
count: limit,
};
if (instance.searchRoom.get()) {
params.roomId = instance.searchRoom.get();
}
const { users } = await APIClient.v1.get('roles.getUsersInRole', params);
instance.usersInRole.set(users);
};
Template.permissionsRole.helpers({
role() {
......@@ -46,12 +60,12 @@ Template.permissionsRole.helpers({
},
hasUsers() {
return Template.instance().usersInRole.get() && Template.instance().usersInRole.get().count() > 0;
return Template.instance().usersInRole.get() && Template.instance().usersInRole.get().length > 0;
},
hasMore() {
const instance = Template.instance();
return instance.limit && instance.limit.get() <= instance.usersInRole.get().count();
return instance.limit && instance.usersInRole.get() && instance.limit.get() <= instance.usersInRole.get().length;
},
isLoading() {
......@@ -100,7 +114,7 @@ Template.permissionsRole.helpers({
noMatchTemplate: Template.userSearchEmpty,
matchAll: true,
filter: {
exceptions: instance.usersInRole.get() && instance.usersInRole.get().fetch(),
exceptions: instance.usersInRole.get(),
},
selector(match) {
return {
......@@ -128,11 +142,12 @@ Template.permissionsRole.events({
closeOnConfirm: false,
html: false,
}, () => {
Meteor.call('authorization:removeUserFromRole', FlowRouter.getParam('name'), this.username, instance.searchRoom.get(), function(error/* , result*/) {
Meteor.call('authorization:removeUserFromRole', FlowRouter.getParam('name'), this.username, instance.searchRoom.get(), async function(error/* , result*/) {
if (error) {
return handleError(error);
}
await loadUsers(instance);
modal.open({
title: t('Removed'),
text: t('User_removed'),
......@@ -184,12 +199,12 @@ Template.permissionsRole.events({
const oldBtnValue = e.currentTarget.elements.add.value;
e.currentTarget.elements.add.value = t('Saving');
Meteor.call('authorization:addUserToRole', FlowRouter.getParam('name'), e.currentTarget.elements.username.value, instance.searchRoom.get(), (error/* , result*/) => {
Meteor.call('authorization:addUserToRole', FlowRouter.getParam('name'), e.currentTarget.elements.username.value, instance.searchRoom.get(), async (error/* , result*/) => {
e.currentTarget.elements.add.value = oldBtnValue;
if (error) {
return handleError(error);
}
instance.subscribe('usersInRole', FlowRouter.getParam('name'), instance.searchRoom.get());
await loadUsers(instance);
toastr.success(t('User_added'));
e.currentTarget.reset();
});
......@@ -214,41 +229,27 @@ Template.permissionsRole.events({
});
},
'click .load-more'(e, t) {
async 'click .load-more'(e, t) {
e.preventDefault();
e.stopPropagation();
t.limit.set(t.limit.get() + 50);
await loadUsers(t);
},
'autocompleteselect input[name=room]'(event, template, doc) {
async 'autocompleteselect input[name=room]'(event, template, doc) {
template.searchRoom.set(doc._id);
await loadUsers(template);
},
});
Template.permissionsRole.onCreated(function() {
Template.permissionsRole.onCreated(async function() {
this.searchRoom = new ReactiveVar();
this.searchUsername = new ReactiveVar();
this.usersInRole = new ReactiveVar();
this.limit = new ReactiveVar(50);
this.ready = new ReactiveVar(true);
this.subscribe('roles', FlowRouter.getParam('name'));
this.autorun(() => {
if (this.searchRoom.get()) {
this.subscribe('roomSubscriptionsByRole', this.searchRoom.get(), FlowRouter.getParam('name'));
}
const limit = this.limit.get();
const subscription = this.subscribe('usersInRole', FlowRouter.getParam('name'), this.searchRoom.get(), limit);
this.ready.set(subscription.ready());
this.usersInRole.set(Roles.findUsersInRole(FlowRouter.getParam('name'), this.searchRoom.get(), {
sort: {
username: 1,
},
}));
});
await loadUsers(this);
});
Template.permissionsRole.onRendered(() => {
......
......@@ -22,7 +22,6 @@ import './methods/removeUserFromRole';
import './methods/saveRole';
import './publications/permissions';
import './publications/roles';
import './publications/usersInRole';
import './startup';
export {
......
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../functions/hasPermission';
import { getUsersInRole } from '../functions/getUsersInRole';
Meteor.publish('usersInRole', function(roleName, scope, limit = 50) {
if (!this.userId) {
return this.ready();
}
if (!hasPermission(this.userId, 'access-permissions')) {
return this.error(new Meteor.Error('error-not-allowed', 'Not allowed', {
publish: 'usersInRole',
}));
}
const options = {
limit,
sort: {
name: 1,
},
};
return getUsersInRole(roleName, scope, options);
});
......@@ -42,6 +42,18 @@ Template.adminEmoji.helpers({
data: Template.instance().tabBarData.get(),
};
},
onTableScroll() {
const instance = Template.instance();
return function(currentTarget) {
if ((currentTarget.offsetHeight + currentTarget.scrollTop) < (currentTarget.scrollHeight - 100)) {
return;
}
if (Template.instance().limit.get() > Template.instance().customemoji().length) {
return false;
}
instance.limit.set(instance.limit.get() + 50);
};
},
onTableItemClick() {
const instance = Template.instance();
return function({ _id }) {
......
......@@ -144,7 +144,7 @@ export function getDataToSyncUserData(ldapUser, user) {
if (currKey === lastKey) {
obj[currKey] = tmpLdapField;
} else {
obj[currKey] = obj[currKey];
obj[currKey] = obj[currKey] || {};
}
return obj[currKey];
}, userData);
......
import { Meteor } from 'meteor/meteor';
import { TimeSync } from 'meteor/mizzao:timesync';
import s from 'underscore.string';
import toastr from 'toastr';
import { ChatMessage } from '../../../models';
import { settings } from '../../../settings';
import { callbacks } from '../../../callbacks';
import { promises } from '../../../promises/client';
import { t } from '../../../utils/client';
Meteor.methods({
sendMessage(message) {
if (!Meteor.userId() || s.trim(message.msg) === '') {
return false;
}
const messageAlreadyExists = message._id && ChatMessage.findOne({ _id: message._id });
if (messageAlreadyExists) {
return toastr.error(t('Message_Already_Sent'));
}
const user = Meteor.user();
message.ts = isNaN(TimeSync.serverOffset()) ? new Date() : new Date(Date.now() + TimeSync.serverOffset());
message.u = {
......
......@@ -198,6 +198,10 @@ export const sendMessage = function(user, message, room, upsert = false) {
}, message);
message._id = _id;
} else {
const messageAlreadyExists = message._id && Messages.findOneById(message._id, { fields: { _id: 1 } });
if (messageAlreadyExists) {
return;
}
message._id = Messages.insert(message);
}
......
......@@ -64,7 +64,7 @@ Meteor.startup(function() {
id: 'jump-to-pin-message',
icon: 'jump',
label: 'Jump_to_message',
context: ['pinned'],
context: ['pinned', 'message', 'message-mobile'],
action() {
const { msg: message } = messageArgs(this);
if (window.matchMedia('(max-width: 500px)').matches) {
......
......@@ -63,7 +63,7 @@ Meteor.startup(function() {
id: 'jump-to-star-message',
icon: 'jump',
label: 'Jump_to_message',
context: ['starred', 'threads'],
context: ['starred', 'threads', 'message', 'message-mobile'],
action() {
const { msg: message } = messageArgs(this);
if (window.matchMedia('(max-width: 500px)').matches) {
......
......@@ -13,8 +13,9 @@
}
.tab {
display: flex;
margin: 0 1rem;
padding: 1rem 0;
cursor: pointer;
......@@ -24,13 +25,25 @@
border-bottom: 2px solid transparent;
font-family: inherit;
font-size: 1rem;
font-weight: 500;
line-height: 1.25rem;
align-items: stretch;
flex-flow: row nowrap;
&.active {
color: var(--rc-color-button-primary);
border-bottom-color: var(--rc-color-button-primary);
}
&:focus {
text-decoration: underline;
}
& > span {
flex: 1;
padding: 1rem 0;
}
}
......@@ -4951,6 +4951,12 @@ rc-old select,
}
}
.rc-old .load-more {
position: relative;
height: 2rem;
}
.rc-old .flex-tab {
&__content {
display: flex;
......
......@@ -12,7 +12,6 @@
</label>
</div>
</form>
<div class="flex-tab__result">
<ul class="attachments">
{{#each files}}
......@@ -39,19 +38,17 @@
</a>
{{> icon file=. block="attachments-menu js-action" icon="menu"}}
</li>
{{else}}
{{#if Template.subscriptionsReady}}
<h2>{{_ "Room_uploaded_file_list_empty"}}</h2>
{{/if}}
{{/each}}
</ul>
{{#if hasMore}}
{{#if isLoading}}
<div class="load-more">
{{> loading}}
</div>
{{/if}}
{{#if Template.subscriptionsReady}}
{{#unless hasFiles}}
<h2>{{_ "Room_uploaded_file_list_empty"}}</h2>
{{/unless}}
{{/if}}
</div>
</template>
......@@ -3,6 +3,7 @@ import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Mongo } from 'meteor/mongo';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveDict } from 'meteor/reactive-dict';
import { DateFormat } from '../../../lib/client';
import { canDeleteMessage, getURL, handleError, t } from '../../../utils/client';
......@@ -10,18 +11,20 @@ import { popover, modal } from '../../../ui-utils/client';
const roomFiles = new Mongo.Collection('room_files');
const LIST_SIZE = 50;
Template.uploadedFilesList.onCreated(function() {
const { rid } = Template.currentData();
this.searchText = new ReactiveVar(null);
this.hasMore = new ReactiveVar(true);
this.limit = new ReactiveVar(50);
this.state = new ReactiveDict({
limit: LIST_SIZE,
hasMore: true,
});
this.autorun(() => {
this.subscribe('roomFilesWithSearchText', rid, this.searchText.get(), this.limit.get(), () => {
if (roomFiles.find({ rid }).fetch().length < this.limit.get()) {
this.hasMore.set(false);
}
});
const ready = this.subscribe('roomFilesWithSearchText', rid, this.searchText.get(), this.state.get('limit'), () => this.state.set('hasMore', this.state.get('limit') <= roomFiles.find({ rid }).count())).ready();
this.state.set('loading', !ready);
});
});
......@@ -46,6 +49,9 @@ Template.uploadedFilesList.helpers({
return getURL(this.url);
}
},
limit() {
return Template.instance().state.get('limit');
},
format(timestamp) {
return DateFormat.formatDateAndTime(timestamp);
},
......@@ -96,12 +102,8 @@ Template.uploadedFilesList.helpers({
return DateFormat.formatDateAndTime(timestamp);
},
hasMore() {
return Template.instance().hasMore.get();
},
hasFiles() {
return roomFiles.find({ rid: this.rid }).count() > 0;
isLoading() {
return Template.instance().state.get('loading');
},
});
......@@ -112,12 +114,15 @@ Template.uploadedFilesList.events({
'input .uploaded-files-list__search-input'(e, t) {
t.searchText.set(e.target.value.trim());
t.hasMore.set(true);
t.state.set('hasMore', true);
},
'scroll .flex-tab__result': _.throttle(function(e, t) {
if (e.target.scrollTop >= (e.target.scrollHeight - e.target.clientHeight)) {
return t.limit.set(t.limit.get() + 50);
if (!t.state.get('hasMore')) {
return;
}
return t.state.set('limit', t.state.get('limit') + LIST_SIZE);
}
}, 200),
......
......@@ -27,6 +27,7 @@
<div class="message-body-wrapper">
<div class="title border-component-color color-info-font-color">
<button type="button" class="user user-card-message color-primary-font-color" data-username="{{msg.u.username}}" tabindex="1">{{getName}}{{#if showUsername}} <span class="message-alias border-component-color color-info-font-color">@{{msg.u.username}}</span>{{/if}}</button>
<span class="info border-component-color color-info-font-color"></span>
{{#each role in roleTags}}
<span class="role-tag color-secondary-color border-component-color" data-role="{{role.description}}">{{role.description}}</span>
{{/each}}
......
......@@ -204,6 +204,10 @@ Template.message.helpers({
return 'own';
}
},
t() {
const { msg } = this;
return msg.t;
},
timestamp() {
const { msg } = this;
return +msg.ts;
......
......@@ -160,11 +160,13 @@ export const RoomHistoryManager = new class {
}
if (wrapper) {
if (wrapper.scrollHeight <= wrapper.offsetHeight) {
return this.getMore(rid);
}
const heightDiff = wrapper.scrollHeight - previousHeight;
wrapper.scrollTop += heightDiff;
Tracker.afterFlush(() => {
if (wrapper.scrollHeight <= wrapper.offsetHeight) {
return this.getMore(rid);
}
const heightDiff = wrapper.scrollHeight - previousHeight;
wrapper.scrollTop += heightDiff;
});
}
room.isLoading.set(false);
......
import { FlowRouter } from 'meteor/kadira:flow-router';
import { Template } from 'meteor/templating';
import { isChrome, isFirefox } from '../../../utils';
import './icon.html';
const baseUrlFix = () => `${ document.baseURI }${ FlowRouter.current().path.substring(1) }`;
const isMozillaFirefoxBelowVersion = (upperVersion) => {
const [, version] = navigator.userAgent.match(/Firefox\/(\d+)\.\d/) || [];
return parseInt(version, 10) < upperVersion;
};
const isGoogleChromeBelowVersion = (upperVersion) => {
const [, version] = navigator.userAgent.match(/Chrome\/(\d+)\.\d/) || [];
return parseInt(version, 10) < upperVersion;
};
const isBaseUrlFixNeeded = () => isMozillaFirefoxBelowVersion(55) || isGoogleChromeBelowVersion(55);
Template.icon.helpers({
baseUrl: (isFirefox && isFirefox[1] < 55) || (isChrome && isChrome[1] < 55) ? baseUrlFix : undefined,
baseUrl: isBaseUrlFixNeeded() ? baseUrlFix : undefined,
});
<template name="tabs">
<div class="tabs">
<div class="tabs-wrapper">
{{#each tabs}}
<div class="tab {{#if isActive value}}active{{/if}}" data-value={{value}}>{{label}}</div>
<div class="tabs-wrapper" role="tablist">
{{#each tab in tabs}}
<button
class="tab {{#if isActive tab.value}}active{{/if}}"
data-value={{tab.value}}
{{ariaSelected tab.value}}
role="tab"
>
<span tabindex="-1">{{tab.label}}</span>
</button>
{{/each}}
</div>
</div>
......
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
import './tabs.html';
Template.tabs.onCreated(function() {
this.activeTab = new ReactiveVar(this.data.tabs.tabs.find((tab) => tab.active).value);
});
Template.tabs.events({
'click .tab'(e) {
const { value } = e.currentTarget.dataset;
if (value === Template.instance().activeTab.get()) {
'click .tab'(event, instance) {
const { value } = event.currentTarget.dataset;
if (value === instance.activeTab.get()) {
return;
}
Template.instance().activeTab.set(value);
Template.instance().data.tabs.onChange(value);
instance.activeTab.set(value);
instance.data.tabs.onChange(value);
},
});
......@@ -23,4 +26,7 @@ Template.tabs.helpers({
isActive(value) {
return Template.instance().activeTab.get() === value;
},
ariaSelected(value) {
return Template.instance().activeTab.get() === value ? { 'aria-selected': 'true' } : {};
},
});
......@@ -44,11 +44,9 @@ import './views/app/secretURL';
import './views/app/videoCall/videoButtons';
import './views/app/videoCall/videoCall';
import './views/app/photoswipe';
import './components/icon.html';
import './components/icon';
import './components/table.html';
import './components/table';
import './components/tabs.html';
import './components/tabs';
import './components/popupList.html';
import './components/popupList';
......
......@@ -87,7 +87,7 @@
<div class="leader-name">{{name}}</div>
<div class="leader-status userStatus">
<span class="color-ball status-bg-{{status}}"></span>
<span class="status-text leader-status-text">{{_ statusDisplay}}</span>
<span class="status-text leader-status-text">{{statusDisplay}}</span>
</div>
<a class="chat-now" href="{{chatNowLink}}">{{_ "Chat_Now"}}</a>
</div>
......@@ -144,13 +144,6 @@
</li>
{{/if}}
</ul>
{{#if hasMoreNext}}
<li class="load-more">
{{#if isLoading}}
{{> loading}}
{{/if}}
</li>
{{/if}}
</div>
</div>
<footer class="footer border-component-color">
......
......@@ -321,7 +321,7 @@ Template.room.helpers({
...roles.u,
name: settings.get('UI_Use_Real_Name') ? roles.u.name || roles.u.username : roles.u.username,
status: leader.status || 'offline',
statusDisplay: leader.statusText || leader.status || 'offline',
statusDisplay: leader.statusText || t(leader.status || 'offline'),
};
}
},
......
export { t, isRtl } from '../lib/tapi18n';
export { isChrome, isFirefox } from './lib/browsers';
export { getDefaultSubscriptionPref } from '../lib/getDefaultSubscriptionPref';
export { Info } from '../rocketchat.info';
export { isEmail } from '../lib/isEmail';
......
export const isFirefox = navigator.userAgent.match(/Firefox\/(\d+)\.\d/);
export const isChrome = navigator.userAgent.match(/Chrome\/(\d+)\.\d/);
{
"name": "Rocket.Chat",
"version": "1.2.0-develop",
"version": "1.3.0-develop",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
......
......@@ -2010,6 +2010,7 @@
"Message_AllowSnippeting": "Allow Message Snippeting",
"Message_AllowStarring": "Allow Message Starring",
"Message_AllowUnrecognizedSlashCommand": "Allow Unrecognized Slash Commands",
"Message_Already_Sent": "This message has already been sent and is being processed by the server",
"Message_AlwaysSearchRegExp": "Always Search Using RegExp",
"Message_AlwaysSearchRegExp_Description": "We recommend to set `True` if your language is not supported on <a target=\"_blank\" href=\"https://docs.mongodb.org/manual/reference/text-search-languages/#text-search-languages\">MongoDB text search</a>.",
"Message_Attachments": "Message Attachments",
......
......@@ -490,9 +490,9 @@
}
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.0.tgz",
"integrity": "sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ=="
},
"media-typer": {
"version": "0.3.0",
......
......@@ -24,7 +24,7 @@
"autolinker": "^1.8.1",
"bcrypt": "^3.0.2",
"core-js": "^2.5.7",
"jquery": "^3.3.1",
"jquery": "^3.4.0",
"meteor-node-stubs": "^0.4.1",
"mime-db": "^1.37.0",
"mime-type": "^3.0.7",
......
......@@ -71,7 +71,6 @@ import './publications/messages';
import './publications/room';
import './publications/roomFiles';
import './publications/roomFilesWithSearchText';
import './publications/roomSubscriptionsByRole';
import './publications/settings';
import './publications/spotlight';
import './publications/subscription';
......
......@@ -60,13 +60,12 @@ Meteor.methods({
const total = Subscriptions.findByRoomIdWhenUsernameExists(rid).count();
const users = await findUsers({ rid, status: { $ne: 'offline' }, limit, skip });
if (showAll && users.length < limit) {
if (showAll && (!limit || users.length < limit)) {
const offlineUsers = await findUsers({
rid,
status: { $eq: 'offline' },
limit: limit - users.length,
skip,
limit: limit ? limit - users.length : 0,
skip: skip || 0,
});
return {
......
import { Meteor } from 'meteor/meteor';
import { hasPermission } from '../../app/authorization';
import { Subscriptions } from '../../app/models';
Meteor.publish('roomSubscriptionsByRole', function(rid, role) {
if (!this.userId) {
return this.ready();
}
if (hasPermission(this.userId, 'view-other-user-channels') !== true) {
return this.ready();
}
return Subscriptions.findByRoomIdAndRoles(rid, role, {
fields: {
rid: 1,
name: 1,
roles: 1,
u: 1,
},
sort: {
name: 1,
},
});
});
......@@ -11,6 +11,9 @@ import {
apiRoleDescription,
apiRoleScopeSubscriptions,
} from '../../data/api-data.js';
import { password } from '../../data/user';
import { updatePermission } from '../../data/permissions.helper';
import { createUser, login as doLogin } from '../../data/users.helper';
describe('[Roles]', function() {
this.retries(0);
......@@ -109,4 +112,97 @@ describe('[Roles]', function() {
.end(done);
});
});
describe('GET [/roles.getUsersInRole]', () => {
let userCredentials;
before((done) => {
createUser().then((createdUser) => {
doLogin(createdUser.username, password).then((createdUserCredentials) => {
userCredentials = createdUserCredentials;
updatePermission('access-permissions', ['admin', 'user']).then(done);
});
});
});
it('should return an error when "role" query param is not provided', (done) => {
request.get(api('roles.getUsersInRole'))
.set(userCredentials)
.query({
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-param-not-provided');
})
.end(done);
});
it('should return an error when the user does not the necessary permission', (done) => {
updatePermission('access-permissions', ['admin']).then(() => {
request.get(api('roles.getUsersInRole'))
.set(userCredentials)
.query({
role: 'admin',
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-not-allowed');
})
.end(done);
});
});
it('should return an error when the user try access rooms permissions and does not have the necessary permission', (done) => {
updatePermission('access-permissions', ['admin', 'user']).then(() => {
updatePermission('view-other-user-channels', []).then(() => {
request.get(api('roles.getUsersInRole'))
.set(userCredentials)
.query({
role: 'admin',
roomId: 'GENERAL',
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-not-allowed');
})
.end(done);
});
});
});
it('should return the list of users', (done) => {
updatePermission('access-permissions', ['admin', 'user']).then(() => {
updatePermission('view-other-user-channels', ['admin', 'user']).then(() => {
request.get(api('roles.getUsersInRole'))
.set(userCredentials)
.query({
role: 'admin',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.users).to.be.an('array');
})
.end(done);
});
});
});
it('should return the list of users when find by room Id', (done) => {
request.get(api('roles.getUsersInRole'))
.set(userCredentials)
.query({
role: 'admin',
roomId: 'GENERAL',
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.users).to.be.an('array');
})
.end(done);
});
});
});