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