Merge branch 'hotfix/21.56.9' into master
[gitter.git] / server / api / v1 / user / troupes.js
blobf5ef7fabf79cce809f6604aa3313811870245828
1 'use strict';
3 var troupeService = require('gitter-web-rooms/lib/troupe-service');
4 var restful = require('../../../services/restful');
5 var restSerializer = require('../../../serializers/rest-serializer');
6 var recentRoomService = require('gitter-web-rooms/lib/recent-room-service');
7 var userRoomModeUpdateService = require('gitter-web-rooms/lib/user-room-mode-update-service');
8 var roomService = require('gitter-web-rooms');
9 var Promise = require('bluebird');
10 var mongoUtils = require('gitter-web-persistence-utils/lib/mongo-utils');
11 var StatusError = require('statuserror');
12 var policyFactory = require('gitter-web-permissions/lib/policy-factory');
13 var RoomWithPolicyService = require('gitter-web-rooms/lib/room-with-policy-service');
15 function joinRoom(user, room, policy, options) {
16   var roomWithPolicyService = new RoomWithPolicyService(room, user, policy);
17   return roomWithPolicyService.joinRoom(options);
20 async function performUpdateToUserRoom(req) {
21   var user = req.user;
22   if (!user) throw new StatusError(401);
24   var userId = user._id;
25   var troupeId = req.params.userTroupeId;
26   var policy = req.userRoomPolicy;
27   const [troupe, isMember] = await troupeService.findByIdLeanWithMembership(troupeId, userId);
28   const canJoin = await policy.canJoin();
29   if (!isMember && !canJoin) throw new StatusError(403);
31   const updatedTroupe = req.body;
33   const promises = [];
35   if ('favourite' in updatedTroupe) {
36     const fav = updatedTroupe.favourite;
38     if (!fav || isMember) {
39       promises.push(recentRoomService.updateFavourite(userId, troupeId, fav));
40     } else {
41       // The user has added a favourite that they don't belong to
42       // Add them to the room first
43       if (!troupe.oneToOne) {
44         /* Ignore one-to-one rooms */
45         promises.push(
46           joinRoom(user, troupe, policy).then(function() {
47             return recentRoomService.updateFavourite(userId, troupeId, fav);
48           })
49         );
50       }
51     }
52   }
54   if ('updateLastAccess' in updatedTroupe) {
55     promises.push(recentRoomService.saveLastVisitedTroupeforUserId(userId, troupeId));
56   }
58   if ('mode' in updatedTroupe) {
59     promises.push(
60       userRoomModeUpdateService.setModeForUserInRoom(user, troupeId, updatedTroupe.mode)
61     );
62   }
64   await Promise.all(promises);
66   if (req.accepts(['text', 'json']) === 'text') return;
68   const strategy = new restSerializer.TroupeIdStrategy({
69     currentUserId: userId,
70     // include all these because it will replace the troupe in the context
71     includeTags: true,
72     includeGroups: true
73   });
75   return restSerializer.serializeObject(req.params.userTroupeId, strategy);
78 module.exports = {
79   id: 'userTroupeId',
81   index: function(req) {
82     if (!req.user) throw new StatusError(401);
84     return restful.serializeTroupesForUser(req.resourceUser.id);
85   },
87   // Join a room
88   create: function(req) {
89     var user = req.user;
90     if (!user) throw new StatusError(401);
91     var source;
93     if (typeof req.body.source === 'string') {
94       source = req.body.source;
95     }
97     var troupeId = req.body && req.body.id && '' + req.body.id;
98     if (!troupeId || !mongoUtils.isLikeObjectId(troupeId)) throw new StatusError(400);
100     return troupeService
101       .findById(troupeId)
102       .then(function(room) {
103         return [room, policyFactory.createPolicyForRoom(req.user, room)];
104       })
105       .spread(function(room, policy) {
106         var options = {};
108         if (source) {
109           options.tracking = { source: source };
110         }
112         return joinRoom(user, room, policy, options);
113       })
114       .then(function() {
115         var strategy = new restSerializer.TroupeIdStrategy({
116           currentUserId: req.user._id,
117           currentUser: req.user,
118           includePermissions: true,
119           includeGroups: true,
120           includeBackend: true,
121           includeAssociatedRepo: true
122         });
124         return restSerializer.serializeObject(troupeId, strategy);
125       });
126   },
128   update: function(req) {
129     // This route is deprecated
130     return performUpdateToUserRoom(req);
131   },
133   patch: function(req) {
134     return performUpdateToUserRoom(req);
135   },
137   /**
138    * Hides a room from the menu. A user can only request this
139    * on their own behalf.
140    *
141    * DELETE /users/:userId/rooms/:roomId
142    */
143   destroy: function(req) {
144     return troupeService
145       .findById(req.params.userTroupeId)
146       .then(function(troupe) {
147         if (!troupe) throw new StatusError(404);
149         return roomService.hideRoomFromUser(troupe, req.user._id);
150       })
151       .then(() => {
152         return { success: true };
153       });
154   },
156   load: function(req, id) {
157     if (!mongoUtils.isLikeObjectId(id)) throw new StatusError(400);
159     return troupeService
160       .checkIdExists(id)
161       .then(function(exists) {
162         if (!exists) throw new StatusError(404);
164         return id;
165       })
166       .tap(function(id) {
167         return policyFactory.createPolicyForRoomId(req.user, id).then(function(policy) {
168           // TODO: middleware?
169           req.userRoomPolicy = policy;
170         });
171       });
172   },
174   subresources: {
175     settings: require('./troupe-settings'),
176     unreadItems: require('./unread-items')
177   }