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