1 /* eslint complexity: ["error", 21] */
4 var Promise = require('bluebird');
5 var identityService = require('gitter-web-identity');
6 var presenceService = require('gitter-web-presence');
7 var avatars = require('gitter-web-avatars');
8 var resolveUserAvatarUrl = require('gitter-web-shared/avatars/resolve-user-avatar-url');
9 var userScopes = require('gitter-web-identity/lib/user-scopes');
10 var collections = require('gitter-web-utils/lib/collections');
11 var getVersion = require('gitter-web-serialization/lib/get-model-version');
12 var troupeService = require('gitter-web-rooms/lib/troupe-service');
13 var adminFilter = require('gitter-web-permissions/lib/known-external-access/admin-filter');
15 function UserRoleInTroupeStrategy(options) {
18 this.preload = function(userIds) {
19 if (userIds.isEmpty()) return;
21 return Promise.try(function() {
22 if (options.includeRolesForTroupe) {
23 return options.includeRolesForTroupe;
26 if (options.includeRolesForTroupeId) {
27 // TODO: don't do this
28 return troupeService.findById(options.includeRolesForTroupeId);
31 .then(function(troupe) {
32 if (!troupe || !troupe.sd) return;
34 if (troupe.sd.members === troupe.sd.admins) {
35 // If all members of the room are always
36 // admins, no point in showing who the
41 return adminFilter(troupe, userIds);
43 .then(function(adminUserIds) {
47 adminUserIds.forEach(function(userId) {
48 contributors[userId] = 'admin';
54 this.map = function(userId) {
55 return contributors && contributors[userId];
59 UserRoleInTroupeStrategy.prototype = {
60 name: 'UserRoleInTroupeStrategy'
63 function UserPresenceInTroupeStrategy(troupeId) {
66 this.preload = function() {
67 return presenceService.findOnlineUsersForTroupe(troupeId).then(function(result) {
68 onlineUsers = collections.hashArray(result);
72 this.map = function(userId) {
73 return !!onlineUsers[userId];
76 UserPresenceInTroupeStrategy.prototype = {
77 name: 'UserPresenceInTroupeStrategy'
80 function UserProvidersStrategy() {
81 var providersByUser = {};
83 this.preload = function(users) {
84 // NOTE: This is currently operating on the assumption that a user can only
85 // have one identity. Once we allow multiple identities per user we'll have
88 users.each(function(user) {
89 const userId = user.id || user._id;
91 if (userScopes.isGitHubUser(user)) {
92 // github user so no need to look up identities at the time of writing
93 providersByUser[userId] = ['github'];
95 // non-github, so we have to look up the user's identities.
100 if (!nonGitHub.length) {
101 return Promise.resolve();
104 return Promise.map(nonGitHub, function(user) {
105 return identityService.listProvidersForUser(user).then(function(providers) {
106 providersByUser[user.id] = providers;
111 this.map = function(userId) {
112 return providersByUser[userId] || [];
115 UserProvidersStrategy.prototype = {
116 name: 'UserProvidersStrategy'
119 function UserStrategy(options) {
120 options = options ? options : {};
121 var lean = !!options.lean;
123 var userRoleInTroupeStrategy;
124 var userPresenceInTroupeStrategy;
125 var userProvidersStrategy;
127 this.preload = function(users) {
128 if (users.isEmpty()) return;
132 if (options.includeRolesForTroupeId || options.includeRolesForTroupe) {
133 userRoleInTroupeStrategy = new UserRoleInTroupeStrategy(options);
135 userRoleInTroupeStrategy.preload(
136 users.map(function(user) {
137 const userId = user.id || user._id;
144 if (options.showPresenceForTroupeId) {
145 userPresenceInTroupeStrategy = new UserPresenceInTroupeStrategy(
146 options.showPresenceForTroupeId
148 strategies.push(userPresenceInTroupeStrategy.preload());
151 if (options.includeProviders) {
152 userProvidersStrategy = new UserProvidersStrategy();
153 strategies.push(userProvidersStrategy.preload(users));
156 return Promise.all(strategies);
159 function displayNameForUser(user) {
160 return options.exposeRawDisplayName ? user.displayName : user.displayName || user.username;
163 // eslint-disable-next-line complexity
164 this.map = function(user) {
165 if (!user) return null;
168 if (options.includeScopes && userScopes.isGitHubUser(user)) {
169 scopes = userScopes.getScopesHash(user);
174 const userId = user.id || user._id;
179 status: options.includeEmail ? user.status : undefined,
180 username: user.username,
182 (userPresenceInTroupeStrategy && userPresenceInTroupeStrategy.map(userId)) || undefined,
183 role: (userRoleInTroupeStrategy && userRoleInTroupeStrategy.map(userId)) || undefined,
184 removed: user.state === 'REMOVED' || undefined, // true or undefined
188 if (user.gravatarVersion) {
190 obj.gv = user.gravatarVersion;
193 obj.gravatarImageUrl = user.gravatarImageUrl;
201 status: options.includeEmail ? user.status : undefined,
202 username: user.username,
203 displayName: displayNameForUser(user),
204 url: '/' + user.username,
205 avatarUrl: avatars.getForUser(user),
206 avatarUrlSmall: resolveUserAvatarUrl(user, 60),
207 avatarUrlMedium: resolveUserAvatarUrl(user, 128),
210 (userPresenceInTroupeStrategy && userPresenceInTroupeStrategy.map(userId)) || undefined,
212 role: (userRoleInTroupeStrategy && userRoleInTroupeStrategy.map(userId)) || undefined,
213 providers: (userProvidersStrategy && userProvidersStrategy.map(userId)) || undefined,
214 removed: user.state === 'REMOVED' || undefined, // true or undefined
218 // NOTE: does it make sense to send gv (or the full url) AND small&medium?
219 if (user.gravatarVersion) {
221 obj.gv = user.gravatarVersion;
224 // NOTE: should we just remove this and keep using avatarUrlSmall for now?
225 //obj.gravatarImageUrl = user.gravatarImageUrl;
232 UserStrategy.prototype = {
236 function SlimUserStrategy() {}
237 SlimUserStrategy.prototype = {
238 preload: function() {},
239 map: function(user) {
240 const userId = user.id || user._id;
244 username: user.username,
245 displayName: user.displayName,
246 avatarUrl: avatars.getForUser(user)
249 name: 'SlimUserStrategy'
252 UserStrategy.slim = function() {
253 return new SlimUserStrategy();
255 module.exports = UserStrategy;