001package com.box.sdk;
002
003import com.eclipsesource.json.Json;
004import com.eclipsesource.json.JsonObject;
005import com.eclipsesource.json.JsonValue;
006import java.net.URL;
007import java.util.Date;
008
009/**
010 * Represents a legal hold policy. Legal Hold Policy information describes the basic characteristics
011 * of the Policy, such as name, description, and filter dates.
012 *
013 * @see <a href="https://developer.box.com/reference/resources/legal-hold-policy/">Box legal
014 *     holds</a>
015 *     <p>Unless otherwise noted, the methods in this class can throw an unchecked {@link
016 *     BoxAPIException} (unchecked meaning that the compiler won't force you to handle it) if an
017 *     error occurs. If you wish to implement custom error handling for errors related to the Box
018 *     REST API, you should capture this exception explicitly.
019 */
020@BoxResourceType("legal_hold")
021public class BoxLegalHoldPolicy extends BoxResource {
022  /** Legal Hold URL Template. */
023  public static final URLTemplate LEGAL_HOLD_URL_TEMPLATE =
024      new URLTemplate("legal_hold_policies/%s");
025  /** All Legal Hold URL Template. */
026  public static final URLTemplate ALL_LEGAL_HOLD_URL_TEMPLATE =
027      new URLTemplate("legal_hold_policies");
028  /** Legal Hold Assignments URL Template. */
029  public static final URLTemplate LEGAL_HOLD_ASSIGNMENTS_URL_TEMPLATE =
030      new URLTemplate("legal_hold_policies/%s/assignments");
031  /** List of File Version Holds URL Template. */
032  public static final URLTemplate LIST_OF_FILE_VERSION_HOLDS_URL_TEMPLATE =
033      new URLTemplate("file_version_legal_holds");
034
035  private static final int DEFAULT_LIMIT = 100;
036
037  /**
038   * Constructs a BoxLegalHoldPolicy for a resource with a given ID.
039   *
040   * @param api the API connection to be used by the resource.
041   * @param id the ID of the resource.
042   */
043  public BoxLegalHoldPolicy(BoxAPIConnection api, String id) {
044    super(api, id);
045  }
046
047  /**
048   * Creates a new Legal Hold Policy.
049   *
050   * @param api the API connection to be used by the resource.
051   * @param name the name of Legal Hold Policy.
052   * @return information about the Legal Hold Policy created.
053   */
054  public static BoxLegalHoldPolicy.Info create(BoxAPIConnection api, String name) {
055    return createOngoing(api, name, null);
056  }
057
058  /**
059   * Creates a new Legal Hold Policy.
060   *
061   * @param api the API connection to be used by the resource.
062   * @param name the name of Legal Hold Policy.
063   * @param description the description of Legal Hold Policy.
064   * @param filterStartedAt optional date filter applies to Custodian assignments only.
065   * @param filterEndedAt optional date filter applies to Custodian assignments only.
066   * @return information about the Legal Hold Policy created.
067   */
068  public static BoxLegalHoldPolicy.Info create(
069      BoxAPIConnection api,
070      String name,
071      String description,
072      Date filterStartedAt,
073      Date filterEndedAt) {
074    URL url = ALL_LEGAL_HOLD_URL_TEMPLATE.build(api.getBaseURL());
075    BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
076    JsonObject requestJSON = new JsonObject().add("policy_name", name);
077    if (description != null) {
078      requestJSON.add("description", description);
079    }
080    if (filterStartedAt != null) {
081      requestJSON.add("filter_started_at", BoxDateFormat.format(filterStartedAt));
082    }
083    if (filterEndedAt != null) {
084      requestJSON.add("filter_ended_at", BoxDateFormat.format(filterEndedAt));
085    }
086    request.setBody(requestJSON.toString());
087    try (BoxJSONResponse response = request.send()) {
088      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
089      BoxLegalHoldPolicy createdPolicy =
090          new BoxLegalHoldPolicy(api, responseJSON.get("id").asString());
091      return createdPolicy.new Info(responseJSON);
092    }
093  }
094
095  /**
096   * Creates a new ongoing Legal Hold Policy.
097   *
098   * @param api the API connection to be used by the resource.
099   * @param name the name of Legal Hold Policy.
100   * @param description the description of Legal Hold Policy.
101   * @return information about the Legal Hold Policy created.
102   */
103  public static BoxLegalHoldPolicy.Info createOngoing(
104      BoxAPIConnection api, String name, String description) {
105    return createOngoing(api, name, description, null);
106  }
107
108  /**
109   * Creates a new ongoing Legal Hold Policy.
110   *
111   * @param api the API connection to be used by the resource.
112   * @param name the name of Legal Hold Policy.
113   * @param description the description of Legal Hold Policy.
114   * @param filterStartedAt optional date filter applies to Custodian assignments only.
115   * @return information about the Legal Hold Policy created.
116   */
117  public static BoxLegalHoldPolicy.Info createOngoing(
118      BoxAPIConnection api, String name, String description, Date filterStartedAt) {
119    URL url = ALL_LEGAL_HOLD_URL_TEMPLATE.build(api.getBaseURL());
120    BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
121    JsonObject requestJSON = new JsonObject().add("policy_name", name).add("is_ongoing", true);
122    if (description != null) {
123      requestJSON.add("description", description);
124    }
125    if (filterStartedAt != null) {
126      requestJSON.add("filter_started_at", BoxDateFormat.format(filterStartedAt));
127    }
128    request.setBody(requestJSON.toString());
129    try (BoxJSONResponse response = request.send()) {
130      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
131      BoxLegalHoldPolicy createdPolicy =
132          new BoxLegalHoldPolicy(api, responseJSON.get("id").asString());
133      return createdPolicy.new Info(responseJSON);
134    }
135  }
136
137  /**
138   * Retrieves a list of Legal Hold Policies that belong to your Enterprise as an Iterable.
139   *
140   * @param api api the API connection to be used by the resource.
141   * @return the Iterable of Legal Hold Policies in your Enterprise.
142   */
143  public static Iterable<BoxLegalHoldPolicy.Info> getAll(final BoxAPIConnection api) {
144    return getAll(api, null, DEFAULT_LIMIT);
145  }
146
147  /**
148   * Retrieves a list of Legal Hold Policies that belong to your Enterprise as an Iterable.
149   *
150   * @param api api the API connection to be used by the resource.
151   * @param policyName case insensitive prefix-match filter on Policy name.
152   * @param limit the limit of retrieved entries per page.
153   * @param fields the optional fields to retrieve.
154   * @return the Iterable of Legal Hold Policies in your Enterprise that match the filter
155   *     parameters.
156   */
157  public static Iterable<BoxLegalHoldPolicy.Info> getAll(
158      final BoxAPIConnection api, String policyName, int limit, String... fields) {
159    QueryStringBuilder builder = new QueryStringBuilder();
160    if (policyName != null) {
161      builder.appendParam("policy_name", policyName);
162    }
163    if (fields.length > 0) {
164      builder.appendParam("fields", fields);
165    }
166    return new BoxResourceIterable<BoxLegalHoldPolicy.Info>(
167        api,
168        ALL_LEGAL_HOLD_URL_TEMPLATE.buildWithQuery(api.getBaseURL(), builder.toString()),
169        limit) {
170
171      @Override
172      protected BoxLegalHoldPolicy.Info factory(JsonObject jsonObject) {
173        BoxLegalHoldPolicy policy = new BoxLegalHoldPolicy(api, jsonObject.get("id").asString());
174        return policy.new Info(jsonObject);
175      }
176    };
177  }
178
179  /**
180   * Gets information about the Legal Hold.
181   *
182   * @param fields the fields to retrieve.
183   * @return information about this legal hold policy.
184   */
185  public Info getInfo(String... fields) {
186    QueryStringBuilder builder = new QueryStringBuilder();
187    if (fields.length > 0) {
188      builder.appendParam("fields", fields);
189    }
190    URL url =
191        LEGAL_HOLD_URL_TEMPLATE.buildWithQuery(
192            this.getAPI().getBaseURL(), builder.toString(), this.getID());
193    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
194    try (BoxJSONResponse response = request.send()) {
195      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
196      return new Info(responseJSON);
197    }
198  }
199
200  /** Deletes the legal hold policy. */
201  public void delete() {
202    URL url = LEGAL_HOLD_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
203    BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
204    request.send().close();
205  }
206
207  /**
208   * Updates the information about this retention policy with modified locally info. Only
209   * policy_name, description and release_notes can be modified.
210   *
211   * @param info the updated info.
212   */
213  public void updateInfo(BoxLegalHoldPolicy.Info info) {
214    URL url = LEGAL_HOLD_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
215    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
216    request.setBody(info.getPendingChanges());
217    try (BoxJSONResponse response = request.send()) {
218      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
219      info.update(responseJSON);
220    }
221  }
222
223  /**
224   * Assigns this legal holds policy to the given box resource. Currently only {@link BoxFile},
225   * {@link BoxFileVersion}, {@link BoxFolder} and {@link BoxUser} are supported.
226   *
227   * @param resource the box resource to assign legal hold policy to.
228   * @return info about created legal hold policy assignment.
229   */
230  public BoxLegalHoldAssignment.Info assignTo(BoxResource resource) {
231    return BoxLegalHoldAssignment.create(
232        this.getAPI(),
233        this.getID(),
234        BoxResource.getResourceType(resource.getClass()),
235        resource.getID());
236  }
237
238  /**
239   * Returns iterable containing assignments for this single legal hold policy.
240   *
241   * @param fields the fields to retrieve.
242   * @return an iterable containing assignments for this single legal hold policy.
243   */
244  public Iterable<BoxLegalHoldAssignment.Info> getAssignments(String... fields) {
245    return this.getAssignments(null, null, DEFAULT_LIMIT, fields);
246  }
247
248  /**
249   * Returns iterable containing assignments for this single legal hold policy. Parameters can be
250   * used to filter retrieved assignments.
251   *
252   * @param type filter assignments of this type only. Can be "file_version", "file", "folder",
253   *     "user" or null if no type filter is necessary.
254   * @param id filter assignments to this ID only. Can be null if no id filter is necessary.
255   * @param limit the limit of entries per page. Default limit is 100.
256   * @param fields the fields to retrieve.
257   * @return an iterable containing assignments for this single legal hold policy.
258   */
259  public Iterable<BoxLegalHoldAssignment.Info> getAssignments(
260      String type, String id, int limit, String... fields) {
261    QueryStringBuilder builder = new QueryStringBuilder();
262    if (type != null) {
263      builder.appendParam("assign_to_type", type);
264    }
265    if (id != null) {
266      builder.appendParam("assign_to_id", id);
267    }
268    if (fields.length > 0) {
269      builder.appendParam("fields", fields);
270    }
271    return new BoxResourceIterable<BoxLegalHoldAssignment.Info>(
272        this.getAPI(),
273        LEGAL_HOLD_ASSIGNMENTS_URL_TEMPLATE.buildWithQuery(
274            this.getAPI().getBaseURL(), builder.toString(), this.getID()),
275        limit) {
276
277      @Override
278      protected BoxLegalHoldAssignment.Info factory(JsonObject jsonObject) {
279        BoxLegalHoldAssignment assignment =
280            new BoxLegalHoldAssignment(
281                BoxLegalHoldPolicy.this.getAPI(), jsonObject.get("id").asString());
282        return assignment.new Info(jsonObject);
283      }
284    };
285  }
286
287  /**
288   * Returns iterable with all non-deleted file version legal holds for this legal hold policy.
289   *
290   * @param fields the fields to retrieve.
291   * @return an iterable containing file version legal holds info.
292   */
293  public Iterable<BoxFileVersionLegalHold.Info> getFileVersionHolds(String... fields) {
294    return this.getFileVersionHolds(DEFAULT_LIMIT, fields);
295  }
296
297  /**
298   * Returns iterable with all non-deleted file version legal holds for this legal hold policy.
299   *
300   * @param limit the limit of entries per response. The default value is 100.
301   * @param fields the fields to retrieve.
302   * @return an iterable containing file version legal holds info.
303   */
304  public Iterable<BoxFileVersionLegalHold.Info> getFileVersionHolds(int limit, String... fields) {
305    QueryStringBuilder queryString =
306        new QueryStringBuilder().appendParam("policy_id", this.getID());
307    if (fields.length > 0) {
308      queryString.appendParam("fields", fields);
309    }
310    URL url =
311        LIST_OF_FILE_VERSION_HOLDS_URL_TEMPLATE.buildWithQuery(
312            getAPI().getBaseURL(), queryString.toString());
313    return new BoxResourceIterable<BoxFileVersionLegalHold.Info>(getAPI(), url, limit) {
314
315      @Override
316      protected BoxFileVersionLegalHold.Info factory(JsonObject jsonObject) {
317        BoxFileVersionLegalHold assignment =
318            new BoxFileVersionLegalHold(getAPI(), jsonObject.get("id").asString());
319        return assignment.new Info(jsonObject);
320      }
321    };
322  }
323
324  /** Contains information about the legal hold policy. */
325  public class Info extends BoxResource.Info {
326
327    /** @see #getPolicyName() */
328    private String policyName;
329
330    /** @see #getDescription() */
331    private String description;
332
333    /** @see #getStatus() */
334    private String status;
335
336    /** @see #getAssignmentCountUser() */
337    private int assignmentCountUser;
338
339    /** @see #getAssignmentCountFolder() */
340    private int assignmentCountFolder;
341
342    /** @see #getAssignmentCountFile() */
343    private int assignmentCountFile;
344
345    /** @see #getAssignmentCountFileVersion() */
346    private int assignmentCountFileVersion;
347
348    /** @see #getCreatedAt() */
349    private BoxUser.Info createdBy;
350
351    /** @see #getCreatedAt() */
352    private Date createdAt;
353
354    /** @see #getModifiedAt() */
355    private Date modifiedAt;
356
357    /** @see #getDeletedAt() */
358    private Date deletedAt;
359
360    /** @see #getFilterStartedAt() */
361    private Date filterStartedAt;
362
363    /** @see #getFilterEndedAt() */
364    private Date filterEndedAt;
365
366    /** @see #getReleaseNotes() */
367    private String releaseNotes;
368
369    /** @see #getIsOngoing() */
370    private Boolean isOngoing;
371
372    /** Constructs an empty Info object. */
373    public Info() {
374      super();
375    }
376
377    /**
378     * Constructs an Info object by parsing information from a JSON string.
379     *
380     * @param json the JSON string to parse.
381     */
382    public Info(String json) {
383      super(json);
384    }
385
386    /**
387     * Constructs an Info object using an already parsed JSON object.
388     *
389     * @param jsonObject the parsed JSON object.
390     */
391    Info(JsonObject jsonObject) {
392      super(jsonObject);
393    }
394
395    /** {@inheritDoc} */
396    @Override
397    public BoxResource getResource() {
398      return BoxLegalHoldPolicy.this;
399    }
400
401    /** @return the name of the policy. */
402    public String getPolicyName() {
403      return this.policyName;
404    }
405
406    /**
407     * Sets the policy's name.
408     *
409     * @param policyName the policy's new name.
410     */
411    public void setPolicyName(String policyName) {
412      this.policyName = policyName;
413      this.addPendingChange("policy_name", policyName);
414    }
415
416    /** @return the description of the policy. */
417    public String getDescription() {
418      return this.description;
419    }
420
421    /**
422     * Sets the policy's description.
423     *
424     * @param description the policy's new description.
425     */
426    public void setDescription(String description) {
427      this.description = description;
428      this.addPendingChange("description", description);
429    }
430
431    /**
432     * Status can be "active", "applying", "releasing" or "released".
433     *
434     * @return the status of the policy.
435     */
436    public String getStatus() {
437      return this.status;
438    }
439
440    /** @return count of users this policy assigned to. */
441    public int getAssignmentCountUser() {
442      return this.assignmentCountUser;
443    }
444
445    /** @return count of folders this policy assigned to. */
446    public int getAssignmentCountFolder() {
447      return this.assignmentCountFolder;
448    }
449
450    /** @return count of files this policy assigned to. */
451    public int getAssignmentCountFile() {
452      return this.assignmentCountFile;
453    }
454
455    /** @return count of file versions this policy assigned to. */
456    public int getAssignmentCountFileVersion() {
457      return this.assignmentCountFileVersion;
458    }
459
460    /** @return info about the user who created this policy. */
461    public BoxUser.Info getCreatedBy() {
462      return this.createdBy;
463    }
464
465    /** @return time the policy was created. */
466    public Date getCreatedAt() {
467      return this.createdAt;
468    }
469
470    /** @return time the policy was modified. */
471    public Date getModifiedAt() {
472      return this.modifiedAt;
473    }
474
475    /** @return time that the policy release request was sent. */
476    public Date getDeletedAt() {
477      return this.deletedAt;
478    }
479
480    /** @return optional date filter applies to Custodian assignments only. */
481    public Date getFilterStartedAt() {
482      return this.filterStartedAt;
483    }
484
485    /** @return optional date filter applies to Custodian assignments only. */
486    public Date getFilterEndedAt() {
487      return this.filterEndedAt;
488    }
489
490    /** @return notes around why the policy was released. */
491    public String getReleaseNotes() {
492      return this.releaseNotes;
493    }
494
495    /**
496     * Sets the policy's release notes.
497     *
498     * @param releaseNotes the policy's new release notes.
499     */
500    public void setReleaseNotes(String releaseNotes) {
501      this.releaseNotes = releaseNotes;
502      this.addPendingChange("release_notes", releaseNotes);
503    }
504
505    /**
506     * @return boolean indicating whether the policy will continue applying to files based on
507     *     events, indefinitely.
508     */
509    public Boolean getIsOngoing() {
510      return this.isOngoing;
511    }
512
513    /** {@inheritDoc} */
514    @Override
515    void parseJSONMember(JsonObject.Member member) {
516      super.parseJSONMember(member);
517      String memberName = member.getName();
518      JsonValue value = member.getValue();
519      try {
520        if (memberName.equals("policy_name")) {
521          this.policyName = value.asString();
522        } else if (memberName.equals("description")) {
523          this.description = value.asString();
524        } else if (memberName.equals("status")) {
525          this.status = value.asString();
526        } else if (memberName.equals("release_notes")) {
527          this.releaseNotes = value.asString();
528        } else if (memberName.equals("assignment_counts")) {
529          JsonObject countsJSON = value.asObject();
530          this.assignmentCountUser = countsJSON.get("user").asInt();
531          this.assignmentCountFolder = countsJSON.get("folder").asInt();
532          this.assignmentCountFile = countsJSON.get("file").asInt();
533          this.assignmentCountFileVersion = countsJSON.get("file_version").asInt();
534        } else if (memberName.equals("created_by")) {
535          JsonObject userJSON = value.asObject();
536          if (this.createdBy == null) {
537            String userID = userJSON.get("id").asString();
538            BoxUser user = new BoxUser(getAPI(), userID);
539            this.createdBy = user.new Info(userJSON);
540          } else {
541            this.createdBy.update(userJSON);
542          }
543        } else if (memberName.equals("created_at")) {
544          this.createdAt = BoxDateFormat.parse(value.asString());
545        } else if (memberName.equals("modified_at")) {
546          this.modifiedAt = BoxDateFormat.parse(value.asString());
547        } else if (memberName.equals("deleted_at")) {
548          this.deletedAt = BoxDateFormat.parse(value.asString());
549        } else if (memberName.equals("filter_started_at")) {
550          this.filterStartedAt = BoxDateFormat.parse(value.asString());
551        } else if (memberName.equals("filter_ended_at")) {
552          this.filterEndedAt = BoxDateFormat.parse(value.asString());
553        } else if (memberName.equals("is_ongoing")) {
554          this.isOngoing = value.asBoolean();
555        }
556      } catch (Exception e) {
557        throw new BoxDeserializationException(memberName, value.toString(), e);
558      }
559    }
560  }
561}