diff --git a/app/models/server/models/Users.js b/app/models/server/models/Users.js index 5de77ec39bec..7f4f6e3265ef 100644 --- a/app/models/server/models/Users.js +++ b/app/models/server/models/Users.js @@ -18,6 +18,7 @@ export class Users extends Base { this.tryEnsureIndex({ statusConnection: 1 }, { sparse: 1 }); this.tryEnsureIndex({ type: 1 }); this.tryEnsureIndex({ 'visitorEmails.address': 1 }); + this.tryEnsureIndex({ federation: 1 }, { sparse: true }); } getLoginTokensByUserId(userId) { @@ -480,7 +481,7 @@ export class Users extends Base { return this.find(query, options); } - findByActiveUsersExcept(searchTerm, exceptions, options, forcedSearchFields) { + findByActiveUsersExcept(searchTerm, exceptions, options, forcedSearchFields, extraQuery = []) { if (exceptions == null) { exceptions = []; } if (options == null) { options = {}; } if (!_.isArray(exceptions)) { @@ -504,6 +505,7 @@ export class Users extends Base { { username: { $exists: true, $nin: exceptions }, }, + ...extraQuery, ], }; @@ -511,6 +513,26 @@ export class Users extends Base { return this._db.find(query, options); } + findByActiveLocalUsersExcept(searchTerm, exceptions, options, forcedSearchFields, localPeer) { + const extraQuery = [ + { + $or: [ + { federation: { $exists: false } }, + { 'federation.peer': localPeer }, + ], + }, + ]; + return this.findByActiveUsersExcept(searchTerm, exceptions, options, forcedSearchFields, extraQuery); + } + + findByActiveExternalUsersExcept(searchTerm, exceptions, options, forcedSearchFields, localPeer) { + const extraQuery = [ + { federation: { $exists: true } }, + { 'federation.peer': { $ne: localPeer } }, + ]; + return this.findByActiveUsersExcept(searchTerm, exceptions, options, forcedSearchFields, extraQuery); + } + findUsersByNameOrUsername(nameOrUsername, options) { const query = { username: { diff --git a/app/ui/client/views/app/directory.html b/app/ui/client/views/app/directory.html index 85327e825f6e..9ef3d822eb30 100644 --- a/app/ui/client/views/app/directory.html +++ b/app/ui/client/views/app/directory.html @@ -5,21 +5,21 @@ {{>tabs tabs=tabsData}}
+ {{#if $eq searchType 'users'}} {{#if federationEnabled}} {{/if}} {{/if}} -
{{#if $eq searchType 'channels'}} @@ -91,10 +91,12 @@
{{_ "Username"}} {{> icon icon=(sortIcon 'username') }}
+ {{#if canViewOtherUserInfo}}
{{_ "Email"}} {{> icon icon=(sortIcon 'email') }}
- {{#if $eq searchWorkspace 'all'}} + {{/if}} + {{#if $eq searchWorkspace 'external'}}
{{_ "Domain"}} {{> icon icon=(sortIcon 'domain') }}
@@ -118,8 +120,10 @@ {{username}} + {{#if canViewOtherUserInfo}} {{email}} - {{#if $eq searchWorkspace 'all'}} + {{/if}} + {{#if $eq searchWorkspace 'external'}} {{domain}} {{/if}} {{createdAt}} diff --git a/app/ui/client/views/app/directory.js b/app/ui/client/views/app/directory.js index 34bdb559dd3e..d2dd074c3d98 100644 --- a/app/ui/client/views/app/directory.js +++ b/app/ui/client/views/app/directory.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; import { ReactiveVar } from 'meteor/reactive-var'; -import { Tracker } from 'meteor/tracker'; +import { hasAllPermission } from '../../../../authorization/client'; import { Template } from 'meteor/templating'; import _ from 'underscore'; import { timeAgo } from './helpers'; @@ -187,6 +187,11 @@ Template.directory.helpers({ sortDirection.set('asc'); }; }, + canViewOtherUserInfo() { + const { canViewOtherUserInfo } = Template.instance(); + + return canViewOtherUserInfo.get(); + }, }); Template.directory.events({ @@ -217,8 +222,7 @@ Template.directory.onRendered(function() { return this.results.set(result); } - Tracker.autorun(() => { - + this.autorun(() => { const searchConfig = { text: this.searchText.get(), workspace: this.searchWorkspace.get(), @@ -243,7 +247,7 @@ Template.directory.onRendered(function() { // If there is no result, searching every workspace and // the search text is an email address, try to find a federated user - if (this.searchWorkspace.get() === 'all' && this.searchText.get().indexOf('@') !== -1) { + if (this.searchWorkspace.get() === 'external' && this.searchText.get().indexOf('@') !== -1) { const email = this.searchText.get(); Meteor.call('federationSearchUsers', email, (error, federatedUsers) => { @@ -297,6 +301,12 @@ Template.directory.onCreated(function() { this.results = new ReactiveVar([]); this.isLoading = new ReactiveVar(false); + + this.canViewOtherUserInfo = new ReactiveVar(false); + + this.autorun(() => { + this.canViewOtherUserInfo.set(hasAllPermission('view-full-other-user-info')); + }); }); Template.directory.onRendered(function() { diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index da291a4c8c90..eab47a80ff7f 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1253,7 +1253,6 @@ "every_hour": "Once every hour", "every_six_hours": "Once every six hours", "every_day": "Once every day", - "Every_Workspace": "Every Workspace", "Everyone_can_access_this_channel": "Everyone can access this channel", "Example_s": "Example: %s", "Exclude_Botnames": "Exclude Bots", @@ -1265,6 +1264,7 @@ "Export_My_Data": "Export My Data", "expression": "Expression", "Extended": "Extended", + "External_Domains": "External Domains", "External_Queue_Service_URL": "External Queue Service URL", "External_Service": "External Service", "Facebook_Page": "Facebook Page", @@ -1833,8 +1833,8 @@ "Loading...": "Loading...", "Loading_more_from_history": "Loading more from history", "Loading_suggestion": "Loading suggestions", + "Local_Domains": "Local Domains", "Local_Password": "Local Password", - "Local_Workspace": "Local Workspace", "Localization": "Localization", "Log_Exceptions_to_Channel_Description": "A channel that will receive all captured exceptions. Leave empty to ignore exceptions.", "Log_Exceptions_to_Channel": "Log Exceptions to Channel", diff --git a/server/methods/browseChannels.js b/server/methods/browseChannels.js index ffb28d5eccaa..d636987aca74 100644 --- a/server/methods/browseChannels.js +++ b/server/methods/browseChannels.js @@ -52,7 +52,7 @@ Meteor.methods({ limit = limit > 0 ? limit : 10; - const options = { + const pagination = { skip, limit, }; @@ -66,7 +66,7 @@ Meteor.methods({ } const result = Rooms.findByNameAndType(regex, 'c', { - ...options, + ...pagination, sort, fields: { description: 1, @@ -90,36 +90,13 @@ Meteor.methods({ return; } - let exceptions = [user.username]; - - // Get exceptions - if (type === 'users' && workspace === 'all') { - const nonFederatedUsers = Users.find({ - $or: [ - { federation: { $exists: false } }, - { 'federation.peer': Federation.localIdentifier }, - ], - }, { fields: { username: 1 } }).map((u) => u.username); - - exceptions = exceptions.concat(nonFederatedUsers); - } else if (type === 'users' && workspace === 'local') { - const federatedUsers = Users.find({ - $and: [ - { federation: { $exists: true } }, - { 'federation.peer': { $ne: Federation.localIdentifier } }, - ], - }, { fields: { username: 1 } }).map((u) => u.username); - - exceptions = exceptions.concat(federatedUsers); - } - - const sort = sortUsers(sortBy, sortDirection); + const exceptions = [user.username]; const forcedSearchFields = workspace === 'all' && ['username', 'name', 'emails.address']; - const result = Users.findByActiveUsersExcept(text, exceptions, { - ...options, - sort, + const options = { + ...pagination, + sort: sortUsers(sortBy, sortDirection), fields: { username: 1, name: 1, @@ -127,7 +104,16 @@ Meteor.methods({ emails: 1, federation: 1, }, - }, forcedSearchFields); + }; + + let result; + if (workspace === 'all') { + result = Users.findByActiveUsersExcept(text, exceptions, options, forcedSearchFields); + } else if (workspace === 'external') { + result = Users.findByActiveExternalUsersExcept(text, exceptions, options, forcedSearchFields, Federation.localIdentifier); + } else { + result = Users.findByActiveLocalUsersExcept(text, exceptions, options, forcedSearchFields, Federation.localIdentifier); + } return { total: result.count(), // count ignores the `skip` and `limit` options