Merge branch 'hotfix/21.56.9' into master
[gitter.git] / server / api / v1 / groups / index.js
blob277c6bad7ae53012c7f57ad3511bb5f1cfc737be
1 'use strict';
3 var Promise = require('bluebird');
4 var StatusError = require('statuserror');
5 var groupService = require('gitter-web-groups/lib/group-service');
6 var policyFactory = require('gitter-web-permissions/lib/policy-factory');
7 var groupCreationService = require('../../../services/group-creation-service');
8 var inviteValidation = require('gitter-web-invites/lib/invite-validation');
9 var restful = require('../../../services/restful');
10 var restSerializer = require('../../../serializers/rest-serializer');
11 var internalClientAccessOnly = require('gitter-web-oauth/lib/internal-client-access-only');
13 var MAX_BATCHED_INVITES = 100;
15 function getInvites(invitesInput) {
16   if (!invitesInput || !invitesInput.length) return [];
18   if (invitesInput.length > MAX_BATCHED_INVITES) {
19     throw new StatusError(400, 'Too many batched invites.');
20   }
22   // This could throw, but it is the basic user-input validation that would
23   // have failed if the frontend didn't call the invite checker API like it
24   // should have anyway.
25   return invitesInput.map(function(input) {
26     return inviteValidation.parseAndValidateInput(input);
27   });
30 function validateStringArray(input, errorMessage) {
31   if (!input) return undefined;
33   if (!Array.isArray(input)) throw new StatusError(400, errorMessage);
35   var valuesAreStrings = input.every(function(s) {
36     return typeof s === 'string';
37   });
39   if (valuesAreStrings) {
40     return input;
41   } else {
42     throw new StatusError(400, errorMessage);
43   }
46 function getGroupOptions(body) {
47   var uri = body.uri ? String(body.uri) : undefined;
48   var name = body.name ? String(body.name) : undefined;
49   var defaultRoomName = body.defaultRoomName ? String(body.defaultRoomName) : undefined;
50   var providers = validateStringArray(body.providers, 'Providers must be strings.');
51   var invites = getInvites(body.invites);
53   var groupOptions = {
54     uri: uri,
55     name: name,
56     defaultRoom: {
57       defaultRoomName: defaultRoomName,
58       providers: providers,
59       addBadge: !!body.addBadge
60     },
61     invites: invites,
62     allowTweeting: body.allowTweeting
63   };
65   if (body.security) {
66     // for GitHub and future group types that are backed by other services
67     groupOptions.type = body.security.type ? String(body.security.type) : undefined;
68     groupOptions.linkPath = body.security.linkPath ? String(body.security.linkPath) : undefined;
69   }
71   return groupOptions;
74 module.exports = {
75   id: 'group',
77   index: function(req) {
78     if (!req.user) {
79       throw new StatusError(401);
80     }
82     var lean = (req.query.lean && parseInt(req.query.lean, 10)) || false;
84     if (req.query.type === 'admin') {
85       return restful.serializeAdminGroupsForUser(req.user, { lean: lean });
86     }
88     return restful.serializeGroupsForUserId(req.user._id, { lean: lean });
89   },
91   create: function(req) {
92     var user = req.user;
94     // This is for internal clients only
95     if (!internalClientAccessOnly.isRequestFromInternalClient(req)) {
96       throw new StatusError(404);
97     }
99     if (!req.user) {
100       throw new StatusError(401);
101     }
103     var groupCreationOptions = getGroupOptions(req.body);
105     return groupCreationService(user, groupCreationOptions).then(function(groupCreationResult) {
106       var group = groupCreationResult.group;
107       var defaultRoom = groupCreationResult.defaultRoom;
109       var groupStrategy = new restSerializer.GroupStrategy({
110         currentUserId: req.user.id
111       });
112       var troupeStrategy = new restSerializer.TroupeStrategy({
113         currentUserId: req.user.id,
114         includeTags: true,
115         includePermissions: true,
116         includeBackend: true
117       });
119       return Promise.join(
120         restSerializer.serializeObject(group, groupStrategy),
121         restSerializer.serializeObject(defaultRoom, troupeStrategy),
122         function(serializedGroup, serializedRoom) {
123           serializedGroup.defaultRoom = serializedRoom;
124           serializedGroup.hookCreationFailedDueToMissingScope =
125             groupCreationResult.hookCreationFailedDueToMissingScope;
126           return serializedGroup;
127         }
128       );
129     });
130   },
132   update: function(req) {
133     var group = req.group;
134     var user = req.user;
136     var promises = [];
137     // Nothing to update on groups
139     if (!promises.length) {
140       throw new StatusError(400, 'Nothing to update.');
141     }
143     return Promise.all(promises).then(function() {
144       var strategy = new restSerializer.GroupStrategy({
145         currentUserId: user && user._id,
146         currentUser: user
147       });
148       return restSerializer.serializeObject(group, strategy);
149     });
150   },
152   show: function(req) {
153     var group = req.group;
154     var user = req.user;
155     var userId = user && user._id;
157     var strategy = new restSerializer.GroupStrategy({
158       currentUserId: userId,
159       currentUser: user
160     });
161     return restSerializer.serializeObject(group, strategy);
162   },
164   load: function(req, id) {
165     return policyFactory
166       .createPolicyForGroupId(req.user, id)
167       .then(function(policy) {
168         // TODO: middleware?
169         req.userGroupPolicy = policy;
171         return req.method === 'GET' ? policy.canRead() : policy.canWrite();
172       })
173       .then(function(access) {
174         if (!access) return null;
176         return groupService.findById(id, { lean: true });
177       });
178   },
180   subresources: {
181     rooms: require('./rooms'),
182     suggestedRooms: require('./suggested-rooms'),
183     security: require('./security')
184   }