001package com.box.sdk;
002
003import java.net.URL;
004import java.util.ArrayList;
005import java.util.Collection;
006import java.util.Iterator;
007
008import com.box.sdk.BoxGroupMembership.Role;
009import com.eclipsesource.json.JsonArray;
010import com.eclipsesource.json.JsonObject;
011import com.eclipsesource.json.JsonValue;
012
013/**
014 * Represents a set of Box users.
015 *
016 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked
017 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error
018 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p>
019 */
020@BoxResourceType("group")
021public class BoxGroup extends BoxCollaborator {
022
023    /**
024     * @see #getAllGroups(BoxAPIConnection, String...)
025     */
026    private static final URLTemplate GROUPS_URL_TEMPLATE = new URLTemplate("groups");
027
028    /**
029     * @see #getInfo()
030     */
031    private static final URLTemplate GROUP_URL_TEMPLATE = new URLTemplate("groups/%s");
032
033    /**
034     * @see #getMemberships()
035     */
036    private static final URLTemplate MEMBERSHIPS_URL_TEMPLATE = new URLTemplate("groups/%s/memberships");
037
038    /**
039     * @see #addMembership(BoxUser)
040     */
041    private static final URLTemplate ADD_MEMBERSHIP_URL_TEMPLATE = new URLTemplate("group_memberships");
042
043    /**
044     * @see #getCollaborations()
045     */
046    private static final URLTemplate COLLABORATIONS_URL_TEMPLATE = new URLTemplate("groups/%s/collaborations");
047
048    /**
049     * Constructs a BoxGroup for a group with a given ID.
050     * @param  api the API connection to be used by the group.
051     * @param  id  the ID of the group.
052     */
053    public BoxGroup(BoxAPIConnection api, String id) {
054        super(api, id);
055    }
056
057    /**
058     * Creates a new group with a specified name.
059     * @param  api  the API connection to be used by the group.
060     * @param  name the name of the new group.
061     * @return      info about the created group.
062     */
063    public static BoxGroup.Info createGroup(BoxAPIConnection api, String name) {
064        return createGroup(api, name, null, null, null, null, null);
065    }
066
067    /**
068     * Creates a new group with a specified name.
069     * @param  api  the API connection to be used by the group.
070     * @param  name the name of the new group.
071     * @param provenance the provenance of the new group
072     * @param externalSyncIdentifier the external_sync_identifier of the new group
073     * @param description the description of the new group
074     * @param invitabilityLevel the invitibility_level of the new group
075     * @param memberViewabilityLevel the member_viewability_level of the new group
076     * @return      info about the created group.
077     */
078    public static BoxGroup.Info createGroup(BoxAPIConnection api, String name, String provenance,
079                                            String externalSyncIdentifier, String description,
080                                            String invitabilityLevel, String memberViewabilityLevel) {
081        JsonObject requestJSON = new JsonObject();
082        requestJSON.add("name", name);
083
084        if (provenance != null) {
085            requestJSON.add("provenance", provenance);
086        }
087        if (externalSyncIdentifier != null) {
088            requestJSON.add("external_sync_identifier", externalSyncIdentifier);
089        }
090        if (description != null) {
091            requestJSON.add("description", description);
092        }
093        if (invitabilityLevel != null) {
094            requestJSON.add("invitability_level", invitabilityLevel);
095        }
096        if (memberViewabilityLevel != null) {
097            requestJSON.add("member_viewability_level", memberViewabilityLevel);
098        }
099
100        URL url = GROUPS_URL_TEMPLATE.build(api.getBaseURL());
101        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
102        request.setBody(requestJSON.toString());
103        BoxJSONResponse response = (BoxJSONResponse) request.send();
104        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
105
106        BoxGroup group = new BoxGroup(api, responseJSON.get("id").asString());
107        return group.new Info(responseJSON);
108    }
109
110    /**
111     * Gets an iterable of all the groups in the enterprise.
112     * @param  api the API connection to be used when retrieving the groups.
113     * @return     an iterable containing info about all the groups.
114     */
115    public static Iterable<BoxGroup.Info> getAllGroups(final BoxAPIConnection api) {
116        return new Iterable<BoxGroup.Info>() {
117            public Iterator<BoxGroup.Info> iterator() {
118                URL url = GROUPS_URL_TEMPLATE.build(api.getBaseURL());
119                return new BoxGroupIterator(api, url);
120            }
121        };
122    }
123
124    /**
125     * Gets an iterable of all the groups in the enterprise.
126     * @param  api the API connection to be used when retrieving the groups.
127     * @param fields the fields to retrieve.
128     * @return     an iterable containing info about all the groups.
129     */
130    public static Iterable<BoxGroup.Info> getAllGroups(final BoxAPIConnection api, String ... fields) {
131        final QueryStringBuilder builder = new QueryStringBuilder();
132        if (fields.length > 0) {
133            builder.appendParam("fields", fields);
134        }
135        return new Iterable<BoxGroup.Info>() {
136            public Iterator<BoxGroup.Info> iterator() {
137                URL url = GROUPS_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString());
138                return new BoxGroupIterator(api, url);
139            }
140        };
141    }
142
143    /**
144     * Gets information about this group.
145     * @return info about this group.
146     */
147    public Info getInfo() {
148        URL url = GROUP_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
149        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
150        BoxJSONResponse response = (BoxJSONResponse) request.send();
151        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
152        return new Info(responseJSON);
153    }
154
155    /**
156     * Gets information about this group.
157     * @param fields the fields to retrieve.
158     * @return info about this group.
159     */
160    public Info getInfo(String ... fields) {
161        QueryStringBuilder builder = new QueryStringBuilder();
162        if (fields.length > 0) {
163            builder.appendParam("fields", fields);
164        }
165        URL url = GROUP_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID());
166        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
167        BoxJSONResponse response = (BoxJSONResponse) request.send();
168        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
169        return new Info(responseJSON);
170    }
171
172    /**
173     * Gets information about all of the group memberships for this group.
174     * Does not support paging.
175     * @return a collection of information about the group memberships for this group.
176     */
177    public Collection<BoxGroupMembership.Info> getMemberships() {
178        final BoxAPIConnection api = this.getAPI();
179        final String groupID = this.getID();
180
181        Iterable<BoxGroupMembership.Info> iter = new Iterable<BoxGroupMembership.Info>() {
182            public Iterator<BoxGroupMembership.Info> iterator() {
183                URL url = MEMBERSHIPS_URL_TEMPLATE.build(api.getBaseURL(), groupID);
184                return new BoxGroupMembershipIterator(api, url);
185            }
186        };
187
188        // We need to iterate all results because this method must return a Collection. This logic should be removed in
189        // the next major version, and instead return the Iterable directly.
190        Collection<BoxGroupMembership.Info> memberships = new ArrayList<BoxGroupMembership.Info>();
191        for (BoxGroupMembership.Info membership : iter) {
192            memberships.add(membership);
193        }
194        return memberships;
195    }
196
197    /**
198     * Gets information about all of the group memberships for this group as iterable with paging support.
199     * @param fields the fields to retrieve.
200     * @return an iterable with information about the group memberships for this group.
201     */
202    public Iterable<BoxGroupMembership.Info> getAllMemberships(String ... fields) {
203        final QueryStringBuilder builder = new QueryStringBuilder();
204        if (fields.length > 0) {
205            builder.appendParam("fields", fields);
206        }
207        return new Iterable<BoxGroupMembership.Info>() {
208            public Iterator<BoxGroupMembership.Info> iterator() {
209                URL url = MEMBERSHIPS_URL_TEMPLATE.buildWithQuery(
210                        BoxGroup.this.getAPI().getBaseURL(), builder.toString(), BoxGroup.this.getID());
211                return new BoxGroupMembershipIterator(BoxGroup.this.getAPI(), url);
212            }
213        };
214    }
215
216    /**
217     * Adds a member to this group with the default role.
218     * @param  user the member to be added to this group.
219     * @return      info about the new group membership.
220     */
221    public BoxGroupMembership.Info addMembership(BoxUser user) {
222        return this.addMembership(user, null);
223    }
224
225    /**
226     * Adds a member to this group with the specified role.
227     * @param  user the member to be added to this group.
228     * @param  role the role of the user in this group. Can be null to assign the default role.
229     * @return      info about the new group membership.
230     */
231    public BoxGroupMembership.Info addMembership(BoxUser user, Role role) {
232        BoxAPIConnection api = this.getAPI();
233
234        JsonObject requestJSON = new JsonObject();
235        requestJSON.add("user", new JsonObject().add("id", user.getID()));
236        requestJSON.add("group", new JsonObject().add("id", this.getID()));
237        if (role != null) {
238            requestJSON.add("role", role.toJSONString());
239        }
240
241        URL url = ADD_MEMBERSHIP_URL_TEMPLATE.build(api.getBaseURL());
242        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
243        request.setBody(requestJSON.toString());
244        BoxJSONResponse response = (BoxJSONResponse) request.send();
245        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
246
247        BoxGroupMembership membership = new BoxGroupMembership(api, responseJSON.get("id").asString());
248        return membership.new Info(responseJSON);
249    }
250
251    /**
252     * Gets information about all of the collaborations for this group.
253     * @return a collection of information about the collaborations for this group.
254     */
255    public Collection<BoxCollaboration.Info> getCollaborations() {
256        BoxAPIConnection api = this.getAPI();
257        URL url = COLLABORATIONS_URL_TEMPLATE.build(api.getBaseURL(), this.getID());
258
259        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
260        BoxJSONResponse response = (BoxJSONResponse) request.send();
261        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
262
263        int entriesCount = responseJSON.get("total_count").asInt();
264        Collection<BoxCollaboration.Info> collaborations = new ArrayList<BoxCollaboration.Info>(entriesCount);
265        JsonArray entries = responseJSON.get("entries").asArray();
266        for (JsonValue entry : entries) {
267            JsonObject entryObject = entry.asObject();
268            BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString());
269            BoxCollaboration.Info info = collaboration.new Info(entryObject);
270            collaborations.add(info);
271        }
272
273        return collaborations;
274    }
275
276    /**
277     * Deletes this group.
278     */
279    public void delete() {
280        URL url = GROUP_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
281        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
282        BoxAPIResponse response = request.send();
283        response.disconnect();
284    }
285
286    /**
287     * Updates the information about this group with any info fields that have been modified locally.
288     * @param info the updated info.
289     */
290    public void updateInfo(BoxGroup.Info info) {
291        URL url = GROUP_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
292        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
293        request.setBody(info.getPendingChanges());
294        BoxJSONResponse response = (BoxJSONResponse) request.send();
295        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
296        info.update(jsonObject);
297    }
298
299    /**
300     * Contains information about a BoxGroup.
301     */
302    public class Info extends BoxCollaborator.Info {
303
304        /**
305         * @see #getProvenance()
306         */
307        private String provenance;
308
309        /**
310         * @see #getExternalSyncIdentifier()
311         */
312        private String externalSyncIdentifier;
313
314        /**
315         * @see #getDescription()
316         */
317        private String description;
318
319        /**
320         * @see #getInvitabilityLevel()
321         */
322        private String invitabilityLevel;
323
324        /**
325         * @see #getMemberViewabilityLevel()
326         */
327        private String memberViewabilityLevel;
328
329        /**
330         * Constructs an empty Info object.
331         */
332        public Info() {
333            super();
334        }
335
336        /**
337         * Constructs an Info object by parsing information from a JSON string.
338         * @param  json the JSON string to parse.
339         */
340        public Info(String json) {
341            super(json);
342        }
343
344        /**
345         * Constructs an Info object using an already parsed JSON object.
346         * @param  jsonObject the parsed JSON object.
347         */
348        Info(JsonObject jsonObject) {
349            super(jsonObject);
350        }
351
352        /**
353         * {@inheritDoc}
354         */
355        @Override
356        public BoxGroup getResource() {
357            return BoxGroup.this;
358        }
359
360        /**
361         * {@inheritDoc}
362         */
363        @Override
364        protected void parseJSONMember(JsonObject.Member member) {
365            super.parseJSONMember(member);
366
367            String memberName = member.getName();
368            JsonValue value = member.getValue();
369            if (memberName.equals("description")) {
370                this.description = value.asString();
371            } else if (memberName.equals("external_sync_identifier")) {
372                this.externalSyncIdentifier = value.asString();
373            } else if (memberName.equals("invitability_level")) {
374                this.invitabilityLevel = value.asString();
375            } else if (memberName.equals("member_viewability_level")) {
376                this.memberViewabilityLevel = value.asString();
377            } else if (memberName.equals("provenance")) {
378                this.provenance = value.asString();
379            }
380        }
381
382        /**
383         * Gets the description for the group.
384         * @return the description for the group.
385         */
386        public String getDescription() {
387            return this.description;
388        }
389
390        /**
391         * Sets the description for the group.
392         * @param description the description for the group.
393         */
394        public void setDescription(String description) {
395            this.description = description;
396            addPendingChange("description", description);
397        }
398
399        /**
400         * Gets the external_sync_identifier for the group.
401         * @return the external_sync_identifier for the group.
402         */
403        public String getExternalSyncIdentifier() {
404            return this.externalSyncIdentifier;
405        }
406
407        /**
408         * Sets the external_sync_identifier for the group.
409         * @param externalSyncIdentifier the external_sync_identifier for the group.
410         */
411        public void setExternalSyncIdentifier(String externalSyncIdentifier) {
412            this.externalSyncIdentifier = externalSyncIdentifier;
413            addPendingChange("external_sync_identifier", externalSyncIdentifier);
414        }
415
416        /**
417         * Gets the invitability_level for the group.
418         * @return the invitability_level for the group.
419         */
420        public String getInvitabilityLevel() {
421            return this.invitabilityLevel;
422        }
423
424        /**
425         * Sets the invitability_level for the group.
426         * @param invitabilityLevel the invitability_level for the group.
427         */
428        public void setInvitabilityLevel(String invitabilityLevel) {
429            this.invitabilityLevel = invitabilityLevel;
430            addPendingChange("invitability_level", invitabilityLevel);
431        }
432
433        /**
434         * Gets the member_viewability_level for the group.
435         * @return the member_viewability_level for the group.
436         */
437        public String getMemberViewabilityLevel() {
438            return this.memberViewabilityLevel;
439        }
440
441        /**
442         * Sets the member_viewability_level for the group.
443         * @param memberViewabilityLevel the member_viewability_level for the group.
444         */
445        public void setMemberViewabilityLevel(String memberViewabilityLevel) {
446            this.memberViewabilityLevel = memberViewabilityLevel;
447            addPendingChange("member_viewability_level", memberViewabilityLevel);
448        }
449
450        /**
451         * Gets the provenance for the group.
452         * @return the provenance for the group.
453         */
454        public String getProvenance() {
455            return this.provenance;
456        }
457
458        /**
459         * Sets the provenance for the group.
460         * @param provenance the provenance for the group.
461         */
462        public void setProvenance(String provenance) {
463            this.provenance = provenance;
464            addPendingChange("provenance", provenance);
465        }
466    }
467}