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        return createOngoing(api, name, description, null);
105    }
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    ) {
120        URL url = ALL_LEGAL_HOLD_URL_TEMPLATE.build(api.getBaseURL());
121        BoxJSONRequest request = new BoxJSONRequest(api, url, "POST");
122        JsonObject requestJSON = new JsonObject()
123                .add("policy_name", name)
124                .add("is_ongoing", true);
125        if (description != null) {
126            requestJSON.add("description", description);
127        }
128        if (filterStartedAt != null) {
129            requestJSON.add("filter_started_at", BoxDateFormat.format(filterStartedAt));
130        }
131        request.setBody(requestJSON.toString());
132        try (BoxJSONResponse response = request.send()) {
133            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
134            BoxLegalHoldPolicy createdPolicy = new BoxLegalHoldPolicy(api, responseJSON.get("id").asString());
135            return createdPolicy.new Info(responseJSON);
136        }
137    }
138
139    /**
140     * Retrieves a list of Legal Hold Policies that belong to your Enterprise as an Iterable.
141     *
142     * @param api api the API connection to be used by the resource.
143     * @return the Iterable of Legal Hold Policies in your Enterprise.
144     */
145    public static Iterable<BoxLegalHoldPolicy.Info> getAll(final BoxAPIConnection api) {
146        return getAll(api, null, DEFAULT_LIMIT);
147    }
148
149    /**
150     * Retrieves a list of Legal Hold Policies that belong to your Enterprise as an Iterable.
151     *
152     * @param api        api the API connection to be used by the resource.
153     * @param policyName case insensitive prefix-match filter on Policy name.
154     * @param limit      the limit of retrieved entries per page.
155     * @param fields     the optional fields to retrieve.
156     * @return the Iterable of Legal Hold Policies in your Enterprise that match the filter parameters.
157     */
158    public static Iterable<BoxLegalHoldPolicy.Info> getAll(
159        final BoxAPIConnection api, String policyName, int limit, String... fields) {
160        QueryStringBuilder builder = new QueryStringBuilder();
161        if (policyName != null) {
162            builder.appendParam("policy_name", policyName);
163        }
164        if (fields.length > 0) {
165            builder.appendParam("fields", fields);
166        }
167        return new BoxResourceIterable<BoxLegalHoldPolicy.Info>(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 = LEGAL_HOLD_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), builder.toString(), this.getID());
191        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
192        try (BoxJSONResponse response = request.send()) {
193            JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
194            return new Info(responseJSON);
195        }
196    }
197
198    /**
199     * Deletes the legal hold policy.
200     */
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.
209     * Only 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.
225     * Currently only {@link BoxFile}, {@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(), this.getID(), BoxResource.getResourceType(resource.getClass()), resource.getID());
233    }
234
235    /**
236     * Returns iterable containing assignments for this single legal hold policy.
237     *
238     * @param fields the fields to retrieve.
239     * @return an iterable containing assignments for this single legal hold policy.
240     */
241    public Iterable<BoxLegalHoldAssignment.Info> getAssignments(String... fields) {
242        return this.getAssignments(null, null, DEFAULT_LIMIT, fields);
243    }
244
245    /**
246     * Returns iterable containing assignments for this single legal hold policy.
247     * Parameters can be used to filter retrieved assignments.
248     *
249     * @param type   filter assignments of this type only.
250     *               Can be "file_version", "file", "folder", "user" or null if no type filter is necessary.
251     * @param id     filter assignments to this ID only. Can be null if no id filter is necessary.
252     * @param limit  the limit of entries per page. Default limit is 100.
253     * @param fields the fields to retrieve.
254     * @return an iterable containing assignments for this single legal hold policy.
255     */
256    public Iterable<BoxLegalHoldAssignment.Info> getAssignments(String type, String id, int limit, String... fields) {
257        QueryStringBuilder builder = new QueryStringBuilder();
258        if (type != null) {
259            builder.appendParam("assign_to_type", type);
260        }
261        if (id != null) {
262            builder.appendParam("assign_to_id", id);
263        }
264        if (fields.length > 0) {
265            builder.appendParam("fields", fields);
266        }
267        return new BoxResourceIterable<BoxLegalHoldAssignment.Info>(
268            this.getAPI(), LEGAL_HOLD_ASSIGNMENTS_URL_TEMPLATE.buildWithQuery(
269            this.getAPI().getBaseURL(), builder.toString(), this.getID()), limit) {
270
271            @Override
272            protected BoxLegalHoldAssignment.Info factory(JsonObject jsonObject) {
273                BoxLegalHoldAssignment assignment = new BoxLegalHoldAssignment(
274                    BoxLegalHoldPolicy.this.getAPI(), jsonObject.get("id").asString());
275                return assignment.new Info(jsonObject);
276            }
277        };
278    }
279
280    /**
281     * Returns iterable with all non-deleted file version legal holds for this legal hold policy.
282     *
283     * @param fields the fields to retrieve.
284     * @return an iterable containing file version legal holds info.
285     */
286    public Iterable<BoxFileVersionLegalHold.Info> getFileVersionHolds(String... fields) {
287        return this.getFileVersionHolds(DEFAULT_LIMIT, fields);
288    }
289
290    /**
291     * Returns iterable with all non-deleted file version legal holds for this legal hold policy.
292     *
293     * @param limit  the limit of entries per response. The default value is 100.
294     * @param fields the fields to retrieve.
295     * @return an iterable containing file version legal holds info.
296     */
297    public Iterable<BoxFileVersionLegalHold.Info> getFileVersionHolds(int limit, String... fields) {
298        QueryStringBuilder queryString = new QueryStringBuilder().appendParam("policy_id", this.getID());
299        if (fields.length > 0) {
300            queryString.appendParam("fields", fields);
301        }
302        URL url = LIST_OF_FILE_VERSION_HOLDS_URL_TEMPLATE.buildWithQuery(getAPI().getBaseURL(), queryString.toString());
303        return new BoxResourceIterable<BoxFileVersionLegalHold.Info>(getAPI(), url, limit) {
304
305            @Override
306            protected BoxFileVersionLegalHold.Info factory(JsonObject jsonObject) {
307                BoxFileVersionLegalHold assignment
308                    = new BoxFileVersionLegalHold(getAPI(), jsonObject.get("id").asString());
309                return assignment.new Info(jsonObject);
310            }
311
312        };
313    }
314
315    /**
316     * Contains information about the legal hold policy.
317     */
318    public class Info extends BoxResource.Info {
319
320        /**
321         * @see #getPolicyName()
322         */
323        private String policyName;
324
325        /**
326         * @see #getDescription()
327         */
328        private String description;
329
330        /**
331         * @see #getStatus()
332         */
333        private String status;
334
335        /**
336         * @see #getAssignmentCountUser()
337         */
338        private int assignmentCountUser;
339
340        /**
341         * @see #getAssignmentCountFolder()
342         */
343        private int assignmentCountFolder;
344
345        /**
346         * @see #getAssignmentCountFile()
347         */
348        private int assignmentCountFile;
349
350        /**
351         * @see #getAssignmentCountFileVersion()
352         */
353        private int assignmentCountFileVersion;
354
355        /**
356         * @see #getCreatedAt()
357         */
358        private BoxUser.Info createdBy;
359
360        /**
361         * @see #getCreatedAt()
362         */
363        private Date createdAt;
364
365        /**
366         * @see #getModifiedAt()
367         */
368        private Date modifiedAt;
369
370        /**
371         * @see #getDeletedAt()
372         */
373        private Date deletedAt;
374
375        /**
376         * @see #getFilterStartedAt()
377         */
378        private Date filterStartedAt;
379
380        /**
381         * @see #getFilterEndedAt()
382         */
383        private Date filterEndedAt;
384
385        /**
386         * @see #getReleaseNotes()
387         */
388        private String releaseNotes;
389
390        /**
391         * @see #getIsOngoing()
392         */
393        private Boolean isOngoing;
394
395        /**
396         * Constructs an empty Info object.
397         */
398        public Info() {
399            super();
400        }
401
402        /**
403         * Constructs an Info object by parsing information from a JSON string.
404         *
405         * @param json the JSON string to parse.
406         */
407        public Info(String json) {
408            super(json);
409        }
410
411        /**
412         * Constructs an Info object using an already parsed JSON object.
413         *
414         * @param jsonObject the parsed JSON object.
415         */
416        Info(JsonObject jsonObject) {
417            super(jsonObject);
418        }
419
420        /**
421         * {@inheritDoc}
422         */
423        @Override
424        public BoxResource getResource() {
425            return BoxLegalHoldPolicy.this;
426        }
427
428        /**
429         * @return the name of the policy.
430         */
431        public String getPolicyName() {
432            return this.policyName;
433        }
434
435        /**
436         * Sets the policy's name.
437         *
438         * @param policyName the policy's new name.
439         */
440        public void setPolicyName(String policyName) {
441            this.policyName = policyName;
442            this.addPendingChange("policy_name", policyName);
443        }
444
445        /**
446         * @return the description of the policy.
447         */
448        public String getDescription() {
449            return this.description;
450        }
451
452        /**
453         * Sets the policy's description.
454         *
455         * @param description the policy's new description.
456         */
457        public void setDescription(String description) {
458            this.description = description;
459            this.addPendingChange("description", description);
460        }
461
462        /**
463         * Status can be "active", "applying", "releasing" or "released".
464         *
465         * @return the status of the policy.
466         */
467        public String getStatus() {
468            return this.status;
469        }
470
471        /**
472         * @return count of users this policy assigned to.
473         */
474        public int getAssignmentCountUser() {
475            return this.assignmentCountUser;
476        }
477
478        /**
479         * @return count of folders this policy assigned to.
480         */
481        public int getAssignmentCountFolder() {
482            return this.assignmentCountFolder;
483        }
484
485        /**
486         * @return count of files this policy assigned to.
487         */
488        public int getAssignmentCountFile() {
489            return this.assignmentCountFile;
490        }
491
492        /**
493         * @return count of file versions this policy assigned to.
494         */
495        public int getAssignmentCountFileVersion() {
496            return this.assignmentCountFileVersion;
497        }
498
499        /**
500         * @return info about the user who created this policy.
501         */
502        public BoxUser.Info getCreatedBy() {
503            return this.createdBy;
504        }
505
506        /**
507         * @return time the policy was created.
508         */
509        public Date getCreatedAt() {
510            return this.createdAt;
511        }
512
513        /**
514         * @return time the policy was modified.
515         */
516        public Date getModifiedAt() {
517            return this.modifiedAt;
518        }
519
520        /**
521         * @return time that the policy release request was sent.
522         */
523        public Date getDeletedAt() {
524            return this.deletedAt;
525        }
526
527        /**
528         * @return optional date filter applies to Custodian assignments only.
529         */
530        public Date getFilterStartedAt() {
531            return this.filterStartedAt;
532        }
533
534        /**
535         * @return optional date filter applies to Custodian assignments only.
536         */
537        public Date getFilterEndedAt() {
538            return this.filterEndedAt;
539        }
540
541        /**
542         * @return notes around why the policy was released.
543         */
544        public String getReleaseNotes() {
545            return this.releaseNotes;
546        }
547
548        /**
549         * Sets the policy's release notes.
550         *
551         * @param releaseNotes the policy's new release notes.
552         */
553        public void setReleaseNotes(String releaseNotes) {
554            this.releaseNotes = releaseNotes;
555            this.addPendingChange("release_notes", releaseNotes);
556        }
557
558        /**
559         * @return boolean indicating whether the policy will continue applying to files based on events, indefinitely.
560         */
561        public Boolean getIsOngoing() {
562            return this.isOngoing;
563        }
564
565        /**
566         * {@inheritDoc}
567         */
568        @Override
569        void parseJSONMember(JsonObject.Member member) {
570            super.parseJSONMember(member);
571            String memberName = member.getName();
572            JsonValue value = member.getValue();
573            try {
574                if (memberName.equals("policy_name")) {
575                    this.policyName = value.asString();
576                } else if (memberName.equals("description")) {
577                    this.description = value.asString();
578                } else if (memberName.equals("status")) {
579                    this.status = value.asString();
580                } else if (memberName.equals("release_notes")) {
581                    this.releaseNotes = value.asString();
582                } else if (memberName.equals("assignment_counts")) {
583                    JsonObject countsJSON = value.asObject();
584                    this.assignmentCountUser = countsJSON.get("user").asInt();
585                    this.assignmentCountFolder = countsJSON.get("folder").asInt();
586                    this.assignmentCountFile = countsJSON.get("file").asInt();
587                    this.assignmentCountFileVersion = countsJSON.get("file_version").asInt();
588                } else if (memberName.equals("created_by")) {
589                    JsonObject userJSON = value.asObject();
590                    if (this.createdBy == null) {
591                        String userID = userJSON.get("id").asString();
592                        BoxUser user = new BoxUser(getAPI(), userID);
593                        this.createdBy = user.new Info(userJSON);
594                    } else {
595                        this.createdBy.update(userJSON);
596                    }
597                } else if (memberName.equals("created_at")) {
598                    this.createdAt = BoxDateFormat.parse(value.asString());
599                } else if (memberName.equals("modified_at")) {
600                    this.modifiedAt = BoxDateFormat.parse(value.asString());
601                } else if (memberName.equals("deleted_at")) {
602                    this.deletedAt = BoxDateFormat.parse(value.asString());
603                } else if (memberName.equals("filter_started_at")) {
604                    this.filterStartedAt = BoxDateFormat.parse(value.asString());
605                } else if (memberName.equals("filter_ended_at")) {
606                    this.filterEndedAt = BoxDateFormat.parse(value.asString());
607                } else if (memberName.equals("is_ongoing")) {
608                    this.isOngoing = value.asBoolean();
609                }
610            } catch (Exception e) {
611                throw new BoxDeserializationException(memberName, value.toString(), e);
612            }
613        }
614    }
615}