001package com.box.sdk;
002
003import com.box.sdk.BoxGroupMembership.Permission;
004import com.box.sdk.BoxGroupMembership.Role;
005import com.eclipsesource.json.JsonArray;
006import com.eclipsesource.json.JsonObject;
007import com.eclipsesource.json.JsonValue;
008import java.net.URL;
009import java.util.ArrayList;
010import java.util.Collection;
011import java.util.Iterator;
012import java.util.Map;
013
014/**
015 * Represents a set of Box users.
016 *
017 * <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link BoxAPIException} (unchecked
018 * meaning that the compiler won't force you to handle it) if an error occurs. If you wish to implement custom error
019 * handling for errors related to the Box REST API, you should capture this exception explicitly.</p>
020 */
021@BoxResourceType("group")
022public class BoxGroup extends BoxCollaborator {
023
024    /**
025     * @see #getAllGroups(BoxAPIConnection, String...)
026     */
027    public static final URLTemplate GROUPS_URL_TEMPLATE = new URLTemplate("groups");
028
029    /**
030     * @see #getInfo()
031     */
032    public static final URLTemplate GROUP_URL_TEMPLATE = new URLTemplate("groups/%s");
033
034    /**
035     * @see #getMemberships()
036     */
037    public static final URLTemplate MEMBERSHIPS_URL_TEMPLATE = new URLTemplate("groups/%s/memberships");
038
039    /**
040     * @see #addMembership(BoxUser)
041     */
042    public static final URLTemplate ADD_MEMBERSHIP_URL_TEMPLATE = new URLTemplate("group_memberships");
043
044    /**
045     * @see #getCollaborations()
046     */
047    public static final URLTemplate COLLABORATIONS_URL_TEMPLATE = new URLTemplate("groups/%s/collaborations");
048
049    /**
050     * Constructs a BoxGroup for a group with a given ID.
051     *
052     * @param api the API connection to be used by the group.
053     * @param id  the ID of the group.
054     */
055    public BoxGroup(BoxAPIConnection api, String id) {
056        super(api, id);
057    }
058
059    /**
060     * Creates a new group with a specified name.
061     *
062     * @param api  the API connection to be used by the group.
063     * @param name the name of the new group.
064     * @return info about the created group.
065     */
066    public static BoxGroup.Info createGroup(BoxAPIConnection api, String name) {
067        return createGroup(api, name, null, null, null, null, null);
068    }
069
070    /**
071     * Creates a new group with a specified name.
072     *
073     * @param api                    the API connection to be used by the group.
074     * @param name                   the name of the new group.
075     * @param provenance             the provenance of the new group
076     * @param externalSyncIdentifier the external_sync_identifier of the new group
077     * @param description            the description of the new group
078     * @param invitabilityLevel      the invitibility_level of the new group
079     * @param memberViewabilityLevel the member_viewability_level of the new group
080     * @return info about the created group.
081     */
082    public static BoxGroup.Info createGroup(BoxAPIConnection api, String name, String provenance,
083                                            String externalSyncIdentifier, String description,
084                                            String invitabilityLevel, String memberViewabilityLevel) {
085        JsonObject requestJSON = new JsonObject();
086        requestJSON.add("name", name);
087
088        if (provenance != null) {
089            requestJSON.add("provenance", provenance);
090        }
091        if (externalSyncIdentifier != null) {
092            requestJSON.add("external_sync_identifier", externalSyncIdentifier);
093        }
094        if (description != null) {
095            requestJSON.add("description", description);
096        }
097        if (invitabilityLevel != null) {
098            requestJSON.add("invitability_level", invitabilityLevel);
099        }
100        if (memberViewabilityLevel != null) {
101            requestJSON.add("member_viewability_level", memberViewabilityLevel);
102        }
103
104        URL url = GROUPS_URL_TEMPLATE.build(api.getBaseURL());
105        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
106        request.setBody(requestJSON.toString());
107        BoxJSONResponse response = (BoxJSONResponse) request.send();
108        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
109
110        BoxGroup group = new BoxGroup(api, responseJSON.get("id").asString());
111        return group.new Info(responseJSON);
112    }
113
114    /**
115     * Gets an iterable of all the groups in the enterprise.
116     *
117     * @param api the API connection to be used when retrieving the groups.
118     * @return an iterable containing info about all the groups.
119     */
120    public static Iterable<BoxGroup.Info> getAllGroups(final BoxAPIConnection api) {
121        return new Iterable<BoxGroup.Info>() {
122            public Iterator<BoxGroup.Info> iterator() {
123                URL url = GROUPS_URL_TEMPLATE.build(api.getBaseURL());
124                return new BoxGroupIterator(api, url);
125            }
126        };
127    }
128
129    /**
130     * Gets an iterable of all the groups in the enterprise.
131     *
132     * @param api    the API connection to be used when retrieving the groups.
133     * @param fields the fields to retrieve.
134     * @return an iterable containing info about all the groups.
135     */
136    public static Iterable<BoxGroup.Info> getAllGroups(final BoxAPIConnection api, String... fields) {
137        final QueryStringBuilder builder = new QueryStringBuilder();
138        if (fields.length > 0) {
139            builder.appendParam("fields", fields);
140        }
141        return new Iterable<BoxGroup.Info>() {
142            public Iterator<BoxGroup.Info> iterator() {
143                URL url = GROUPS_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString());
144                return new BoxGroupIterator(api, url);
145            }
146        };
147    }
148
149    /**
150     * Gets an iterable of all the groups in the enterprise that are starting with the given name string.
151     *
152     * @param api  the API connection to be used when retrieving the groups.
153     * @param name the name prefix of the groups. If the groups need to searched by full name that has spaces,
154     *             then the parameter string should have been wrapped with "".
155     * @return an iterable containing info about all the groups.
156     */
157    public static Iterable<BoxGroup.Info> getAllGroupsByName(final BoxAPIConnection api, String name) {
158        return getAllGroupsByName(api, name, null);
159    }
160
161    /**
162     * Gets an iterable of all the groups in the enterprise that are starting with the given name string.
163     *
164     * @param api    the API connection to be used when retrieving the groups.
165     * @param name   the name prefix of the groups. If the groups need to searched by full name that has spaces,
166     *               then the parameter string should have been wrapped with "".
167     * @param fields the fields to retrieve.
168     * @return an iterable containing info about all the groups.
169     */
170    public static Iterable<BoxGroup.Info> getAllGroupsByName(final BoxAPIConnection api, String name,
171                                                             String... fields) {
172        final QueryStringBuilder builder = new QueryStringBuilder();
173        if (name == null || name.trim().isEmpty()) {
174            throw new BoxAPIException("Searching groups by name requires a non NULL or non empty name");
175        } else {
176            builder.appendParam("filter_term", name);
177            if (fields != null && fields.length > 0) {
178                builder.appendParam("fields", fields);
179            }
180        }
181
182        return new Iterable<BoxGroup.Info>() {
183            public Iterator<BoxGroup.Info> iterator() {
184                URL url = GROUPS_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString());
185                return new BoxGroupIterator(api, url);
186            }
187        };
188    }
189
190    /**
191     * Gets information about this group.
192     *
193     * @return info about this group.
194     */
195    public Info getInfo() {
196        URL url = GROUP_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
197        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
198        BoxJSONResponse response = (BoxJSONResponse) request.send();
199        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
200        return new Info(responseJSON);
201    }
202
203    /**
204     * Gets information about this group.
205     *
206     * @param fields the fields to retrieve.
207     * @return info about this group.
208     */
209    public Info getInfo(String... fields) {
210        QueryStringBuilder builder = new QueryStringBuilder();
211        if (fields.length > 0) {
212            builder.appendParam("fields", fields);
213        }
214        URL url = GROUP_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID());
215        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
216        BoxJSONResponse response = (BoxJSONResponse) request.send();
217        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
218        return new Info(responseJSON);
219    }
220
221    /**
222     * Gets information about all of the group memberships for this group.
223     * Does not support paging.
224     *
225     * @return a collection of information about the group memberships for this group.
226     */
227    public Collection<BoxGroupMembership.Info> getMemberships() {
228        final BoxAPIConnection api = this.getAPI();
229        final String groupID = this.getID();
230
231        Iterable<BoxGroupMembership.Info> iter = new Iterable<BoxGroupMembership.Info>() {
232            public Iterator<BoxGroupMembership.Info> iterator() {
233                URL url = MEMBERSHIPS_URL_TEMPLATE.build(api.getBaseURL(), groupID);
234                return new BoxGroupMembershipIterator(api, url);
235            }
236        };
237
238        // We need to iterate all results because this method must return a Collection. This logic should be removed in
239        // the next major version, and instead return the Iterable directly.
240        Collection<BoxGroupMembership.Info> memberships = new ArrayList<BoxGroupMembership.Info>();
241        for (BoxGroupMembership.Info membership : iter) {
242            memberships.add(membership);
243        }
244        return memberships;
245    }
246
247    /**
248     * Gets information about all of the group memberships for this group as iterable with paging support.
249     *
250     * @param fields the fields to retrieve.
251     * @return an iterable with information about the group memberships for this group.
252     */
253    public Iterable<BoxGroupMembership.Info> getAllMemberships(String... fields) {
254        final QueryStringBuilder builder = new QueryStringBuilder();
255        if (fields.length > 0) {
256            builder.appendParam("fields", fields);
257        }
258        return new Iterable<BoxGroupMembership.Info>() {
259            public Iterator<BoxGroupMembership.Info> iterator() {
260                URL url = MEMBERSHIPS_URL_TEMPLATE.buildWithQuery(
261                    BoxGroup.this.getAPI().getBaseURL(), builder.toString(), BoxGroup.this.getID());
262                return new BoxGroupMembershipIterator(BoxGroup.this.getAPI(), url);
263            }
264        };
265    }
266
267    /**
268     * Adds a member to this group with the default role.
269     *
270     * @param user the member to be added to this group.
271     * @return info about the new group membership.
272     */
273    public BoxGroupMembership.Info addMembership(BoxUser user) {
274        return this.addMembership(user, (Role) null, null);
275    }
276
277    /**
278     * Adds a member to this group with the specified role.
279     *
280     * @param user the member to be added to this group.
281     * @param role the role of the user in this group. Can be null to assign the default role.
282     * @return info about the new group membership.
283     * @deprecated use addMembership(BoxUser user, BoxGroupMembership.GroupRole role) instead.
284     */
285    @Deprecated
286    public BoxGroupMembership.Info addMembership(BoxUser user, Role role) {
287        return this.addMembership(user, role, null);
288    }
289
290    /**
291     * Adds a member to this group with the specified role.
292     *
293     * @param user the member to be added to this group.
294     * @param role the role of the user in this group. Can be null to assign the default role.
295     * @return info about the new group membership.
296     */
297    public BoxGroupMembership.Info addMembership(BoxUser user, BoxGroupMembership.GroupRole role) {
298        return this.addMembership(user, role, null);
299    }
300
301    /**
302     * Adds a member to this group with the specified role.
303     *
304     * @param user                    the member to be added to this group.
305     * @param role                    the role of the user in this group. Can be null to assign the default role.
306     * @param configurablePermissions the configurable permission of the user as a group admin.
307     *                                Can be null to give all group admin permissions.
308     * @return info about the new group membership.
309     * @deprecated use {@code addMembership(BoxUser user, GroupRole role,
310     * Map<BoxGroupMembership.Permission, Boolean> configurablePermissions)} instead.
311     */
312    @Deprecated
313    public BoxGroupMembership.Info addMembership(BoxUser user, Role role,
314                                                 Map<BoxGroupMembership.Permission, Boolean> configurablePermissions) {
315        BoxAPIConnection api = this.getAPI();
316
317        JsonObject requestJSON = new JsonObject();
318        requestJSON.add("user", new JsonObject().add("id", user.getID()));
319        requestJSON.add("group", new JsonObject().add("id", this.getID()));
320        if (role != null) {
321            requestJSON.add("role", role.toJSONString());
322        }
323
324        if (configurablePermissions != null) {
325            JsonObject configurablePermissionJson = new JsonObject();
326            for (Permission attrKey : configurablePermissions.keySet()) {
327                configurablePermissionJson.set(attrKey.toJSONValue(), configurablePermissions.get(attrKey));
328            }
329            requestJSON.add("configurable_permissions", configurablePermissionJson);
330        }
331
332        URL url = ADD_MEMBERSHIP_URL_TEMPLATE.build(api.getBaseURL());
333        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
334        request.setBody(requestJSON.toString());
335        BoxJSONResponse response = (BoxJSONResponse) request.send();
336        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
337
338        BoxGroupMembership membership = new BoxGroupMembership(api, responseJSON.get("id").asString());
339        return membership.new Info(responseJSON);
340    }
341
342    /**
343     * Adds a member to this group with the specified role.
344     *
345     * @param user                    the member to be added to this group.
346     * @param role                    the role of the user in this group. Can be null to assign the default role.
347     * @param configurablePermissions the configurable permission of the user as a group admin.
348     *                                Can be null to give all group admin permissions.
349     * @return info about the new group membership.
350     */
351    public BoxGroupMembership.Info addMembership(BoxUser user, BoxGroupMembership.GroupRole role,
352                                                 Map<BoxGroupMembership.Permission, Boolean> configurablePermissions) {
353        BoxAPIConnection api = this.getAPI();
354
355        JsonObject requestJSON = new JsonObject();
356        requestJSON.add("user", new JsonObject().add("id", user.getID()));
357        requestJSON.add("group", new JsonObject().add("id", this.getID()));
358        if (role != null) {
359            requestJSON.add("role", role.toJSONString());
360        }
361
362        if (configurablePermissions != null) {
363            JsonObject configurablePermissionJson = new JsonObject();
364            for (Permission attrKey : configurablePermissions.keySet()) {
365                configurablePermissionJson.set(attrKey.toJSONValue(), configurablePermissions.get(attrKey));
366            }
367            requestJSON.add("configurable_permissions", configurablePermissionJson);
368        }
369
370        URL url = ADD_MEMBERSHIP_URL_TEMPLATE.build(api.getBaseURL());
371        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
372        request.setBody(requestJSON.toString());
373        BoxJSONResponse response = (BoxJSONResponse) request.send();
374        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
375
376        BoxGroupMembership membership = new BoxGroupMembership(api, responseJSON.get("id").asString());
377        return membership.new Info(responseJSON);
378    }
379
380    /**
381     * Gets information about all of the collaborations for this group.
382     *
383     * @return a collection of information about the collaborations for this group.
384     */
385    public Collection<BoxCollaboration.Info> getCollaborations() {
386        BoxAPIConnection api = this.getAPI();
387        URL url = COLLABORATIONS_URL_TEMPLATE.build(api.getBaseURL(), this.getID());
388
389        BoxAPIRequest request = new BoxAPIRequest(api, url, "GET");
390        BoxJSONResponse response = (BoxJSONResponse) request.send();
391        JsonObject responseJSON = JsonObject.readFrom(response.getJSON());
392
393        int entriesCount = responseJSON.get("total_count").asInt();
394        Collection<BoxCollaboration.Info> collaborations = new ArrayList<BoxCollaboration.Info>(entriesCount);
395        JsonArray entries = responseJSON.get("entries").asArray();
396        for (JsonValue entry : entries) {
397            JsonObject entryObject = entry.asObject();
398            BoxCollaboration collaboration = new BoxCollaboration(api, entryObject.get("id").asString());
399            BoxCollaboration.Info info = collaboration.new Info(entryObject);
400            collaborations.add(info);
401        }
402
403        return collaborations;
404    }
405
406    /**
407     * Gets information about all of the collaborations for this group.
408     *
409     * @param fields the optional fields to retrieve.
410     * @return An iterable of BoxCollaboration.Info instances associated with the item.
411     */
412    public Iterable<BoxCollaboration.Info> getAllCollaborations(String... fields) {
413        final BoxAPIConnection api = this.getAPI();
414        final QueryStringBuilder builder = new QueryStringBuilder();
415        if (fields.length > 0) {
416            builder.appendParam("fields", fields);
417        }
418        return new Iterable<BoxCollaboration.Info>() {
419            public Iterator<BoxCollaboration.Info> iterator() {
420                URL url = COLLABORATIONS_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString(),
421                    BoxGroup.this.getID());
422                return new BoxCollaborationIterator(api, url);
423            }
424        };
425    }
426
427    /**
428     * Deletes this group.
429     */
430    public void delete() {
431        URL url = GROUP_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
432        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
433        BoxAPIResponse response = request.send();
434        response.disconnect();
435    }
436
437    /**
438     * Updates the information about this group with any info fields that have been modified locally.
439     *
440     * @param info the updated info.
441     */
442    public void updateInfo(BoxGroup.Info info) {
443        URL url = GROUP_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
444        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
445        request.setBody(info.getPendingChanges());
446        BoxJSONResponse response = (BoxJSONResponse) request.send();
447        JsonObject jsonObject = JsonObject.readFrom(response.getJSON());
448        info.update(jsonObject);
449    }
450
451    /**
452     * Contains information about a BoxGroup.
453     */
454    public class Info extends BoxCollaborator.Info {
455
456        /**
457         * @see #getProvenance()
458         */
459        private String provenance;
460
461        /**
462         * @see #getExternalSyncIdentifier()
463         */
464        private String externalSyncIdentifier;
465
466        /**
467         * @see #getDescription()
468         */
469        private String description;
470
471        /**
472         * @see #getInvitabilityLevel()
473         */
474        private String invitabilityLevel;
475
476        /**
477         * @see #getMemberViewabilityLevel()
478         */
479        private String memberViewabilityLevel;
480
481        /**
482         * Constructs an empty Info object.
483         */
484        public Info() {
485            super();
486        }
487
488        /**
489         * Constructs an Info object by parsing information from a JSON string.
490         *
491         * @param json the JSON string to parse.
492         */
493        public Info(String json) {
494            super(json);
495        }
496
497        /**
498         * Constructs an Info object using an already parsed JSON object.
499         *
500         * @param jsonObject the parsed JSON object.
501         */
502        Info(JsonObject jsonObject) {
503            super(jsonObject);
504        }
505
506        /**
507         * {@inheritDoc}
508         */
509        @Override
510        public BoxGroup getResource() {
511            return BoxGroup.this;
512        }
513
514        /**
515         * {@inheritDoc}
516         */
517        @Override
518        protected void parseJSONMember(JsonObject.Member member) {
519            super.parseJSONMember(member);
520
521            String memberName = member.getName();
522            JsonValue value = member.getValue();
523            try {
524                if (memberName.equals("description")) {
525                    this.description = value.asString();
526                } else if (memberName.equals("external_sync_identifier")) {
527                    this.externalSyncIdentifier = value.asString();
528                } else if (memberName.equals("invitability_level")) {
529                    this.invitabilityLevel = value.asString();
530                } else if (memberName.equals("member_viewability_level")) {
531                    this.memberViewabilityLevel = value.asString();
532                } else if (memberName.equals("provenance")) {
533                    this.provenance = value.asString();
534                }
535            } catch (Exception e) {
536                throw new BoxDeserializationException(memberName, value.toString(), e);
537            }
538        }
539
540        /**
541         * Gets the description for the group.
542         *
543         * @return the description for the group.
544         */
545        public String getDescription() {
546            return this.description;
547        }
548
549        /**
550         * Sets the description for the group.
551         *
552         * @param description the description for the group.
553         */
554        public void setDescription(String description) {
555            this.description = description;
556            addPendingChange("description", description);
557        }
558
559        /**
560         * Gets the external_sync_identifier for the group.
561         *
562         * @return the external_sync_identifier for the group.
563         */
564        public String getExternalSyncIdentifier() {
565            return this.externalSyncIdentifier;
566        }
567
568        /**
569         * Sets the external_sync_identifier for the group.
570         *
571         * @param externalSyncIdentifier the external_sync_identifier for the group.
572         */
573        public void setExternalSyncIdentifier(String externalSyncIdentifier) {
574            this.externalSyncIdentifier = externalSyncIdentifier;
575            addPendingChange("external_sync_identifier", externalSyncIdentifier);
576        }
577
578        /**
579         * Gets the invitability_level for the group.
580         *
581         * @return the invitability_level for the group.
582         */
583        public String getInvitabilityLevel() {
584            return this.invitabilityLevel;
585        }
586
587        /**
588         * Sets the invitability_level for the group.
589         *
590         * @param invitabilityLevel the invitability_level for the group.
591         */
592        public void setInvitabilityLevel(String invitabilityLevel) {
593            this.invitabilityLevel = invitabilityLevel;
594            addPendingChange("invitability_level", invitabilityLevel);
595        }
596
597        /**
598         * Gets the member_viewability_level for the group.
599         *
600         * @return the member_viewability_level for the group.
601         */
602        public String getMemberViewabilityLevel() {
603            return this.memberViewabilityLevel;
604        }
605
606        /**
607         * Sets the member_viewability_level for the group.
608         *
609         * @param memberViewabilityLevel the member_viewability_level for the group.
610         */
611        public void setMemberViewabilityLevel(String memberViewabilityLevel) {
612            this.memberViewabilityLevel = memberViewabilityLevel;
613            addPendingChange("member_viewability_level", memberViewabilityLevel);
614        }
615
616        /**
617         * Gets the provenance for the group.
618         *
619         * @return the provenance for the group.
620         */
621        public String getProvenance() {
622            return this.provenance;
623        }
624
625        /**
626         * Sets the provenance for the group.
627         *
628         * @param provenance the provenance for the group.
629         */
630        public void setProvenance(String provenance) {
631            this.provenance = provenance;
632            addPendingChange("provenance", provenance);
633        }
634    }
635}