001package com.box.sdk;
002
003import com.box.sdk.sharedlink.BoxSharedLinkWithoutPermissionsRequest;
004import com.eclipsesource.json.Json;
005import com.eclipsesource.json.JsonArray;
006import com.eclipsesource.json.JsonObject;
007import com.eclipsesource.json.JsonValue;
008import java.net.MalformedURLException;
009import java.net.URL;
010import java.util.Date;
011
012/**
013 * Represents an individual WebLink file on Box. This class can be used to retrieve the link's URL or perform other
014 * common file operations (move, copy, delete, etc.).
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("web_link")
021public class BoxWebLink extends BoxItem {
022
023    /**
024     * An array of all possible weblink fields that can be requested when calling {@link #getInfo()}.
025     */
026    public static final String[] ALL_FIELDS = {"type", "id", "sequence_id", "etag", "name", "url", "description",
027        "path_collection", "created_at", "modified_at", "trashed_at", "purged_at", "created_by", "modified_by",
028        "owned_by", "shared_link", "parent", "item_status", "collections"};
029
030    /**
031     * Copy URL Template.
032     */
033    public static final URLTemplate COPY_URL_TEMPLATE = new URLTemplate("web_links/%s/copy");
034    /**
035     * Web Link URL Template.
036     */
037    public static final URLTemplate WEB_LINK_URL_TEMPLATE = new URLTemplate("web_links/%s");
038
039    /**
040     * Constructs a BoxWebLink for a weblink with a given ID.
041     *
042     * @param api the API connection to be used by the weblink.
043     * @param id  the ID of the weblink.
044     */
045    public BoxWebLink(BoxAPIConnection api, String id) {
046        super(api, id);
047    }
048
049    /**
050     * Creates a new shared link for this item.
051     *
052     * <p>This method is a convenience method for manually creating a new shared link and applying it to this item with
053     * {@link BoxItem.Info#setSharedLink}. You may want to create the shared link manually so that it can be updated along with
054     * other changes to the item's info in a single network request, giving a boost to performance.</p>
055     *
056     * @param access      the access level of the shared link.
057     * @param unshareDate the date and time at which the link will expire. Can be null to create a non-expiring link.
058     * @param permissions the permissions of the shared link. Can be null to use the default permissions.
059     * @return the created shared link.
060     * @deprecated use {@link BoxWebLink#createSharedLink(BoxSharedLinkWithoutPermissionsRequest)}
061     */
062    @Override
063    @Deprecated
064    public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate,
065                                          BoxSharedLink.Permissions permissions) {
066
067        if (permissions != null) {
068            throw new IllegalArgumentException(
069                "Cannot set permissions on a shared link to web link. "
070                    + "The BoxWebLink#createSharedLink(BoxSharedLinkWithoutPermissionsRequest) is preferred."
071            );
072        }
073        BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions);
074        return this.createSharedLink(sharedLink);
075    }
076
077    /**
078     * Creates new SharedLink for a BoxWebLink with a password.
079     *
080     * @param access      The access level of the shared link.
081     * @param unshareDate A specified date to unshare the Box web link.
082     * @param permissions The permissions to set on the shared link for the Box web link.
083     * @param password    Password set on the shared link to give access to the Box web link.
084     * @return information about the newly created shared link.
085     * @deprecated Use {@link BoxWebLink#createSharedLink(BoxSharedLinkWithoutPermissionsRequest)}
086     */
087    @Deprecated
088    public BoxSharedLink createSharedLink(BoxSharedLink.Access access, Date unshareDate,
089                                          BoxSharedLink.Permissions permissions, String password) {
090
091        if (permissions != null) {
092            throw new IllegalArgumentException(
093                "Cannot set permissions on a shared link to web link. "
094                    + "The BoxWebLink#createSharedLink(BoxSharedLinkWithoutPermissionsRequest) is supported."
095            );
096        }
097        BoxSharedLink sharedLink = new BoxSharedLink(access, unshareDate, permissions, password);
098        return this.createSharedLink(sharedLink);
099    }
100
101    /**
102     * Creates a shared link.
103     *
104     * @param sharedLinkRequest Shared link to create
105     * @return Created shared link.
106     */
107    public BoxSharedLink createSharedLink(BoxSharedLinkWithoutPermissionsRequest sharedLinkRequest) {
108        return createSharedLink(sharedLinkRequest.asSharedLink());
109    }
110
111    private BoxSharedLink createSharedLink(BoxSharedLink sharedLink) {
112        BoxWebLink.Info info = new BoxWebLink.Info();
113        info.setSharedLink(sharedLink);
114
115        this.updateInfo(info);
116        return info.getSharedLink();
117    }
118
119
120    @Override
121    public BoxWebLink.Info copy(BoxFolder destination) {
122        return this.copy(destination, null);
123    }
124
125    @Override
126    public BoxWebLink.Info copy(BoxFolder destination, String newName) {
127        URL url = COPY_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
128
129        JsonObject parent = new JsonObject();
130        parent.add("id", destination.getID());
131
132        JsonObject copyInfo = new JsonObject();
133        copyInfo.add("parent", parent);
134        if (newName != null) {
135            copyInfo.add("name", newName);
136        }
137
138        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
139        request.setBody(copyInfo.toString());
140        BoxJSONResponse response = (BoxJSONResponse) request.send();
141        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
142        BoxWebLink copiedWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString());
143        return copiedWebLink.new Info(responseJSON);
144    }
145
146    /**
147     * Deletes this weblink by moving it to the trash.
148     */
149    public void delete() {
150        URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
151        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
152        BoxAPIResponse response = request.send();
153        response.disconnect();
154    }
155
156    @Override
157    public BoxItem.Info move(BoxFolder destination) {
158        return this.move(destination, null);
159    }
160
161    @Override
162    public BoxItem.Info move(BoxFolder destination, String newName) {
163        URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
164        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
165
166        JsonObject parent = new JsonObject();
167        parent.add("id", destination.getID());
168
169        JsonObject updateInfo = new JsonObject();
170        updateInfo.add("parent", parent);
171        if (newName != null) {
172            updateInfo.add("name", newName);
173        }
174
175        request.setBody(updateInfo.toString());
176        BoxJSONResponse response = (BoxJSONResponse) request.send();
177        JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
178        BoxWebLink movedWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString());
179        return movedWebLink.new Info(responseJSON);
180    }
181
182    /**
183     * Renames this weblink.
184     *
185     * @param newName the new name of the weblink.
186     */
187    public void rename(String newName) {
188        URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
189        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
190
191        JsonObject updateInfo = new JsonObject();
192        updateInfo.add("name", newName);
193
194        request.setBody(updateInfo.toString());
195        BoxJSONResponse response = (BoxJSONResponse) request.send();
196        response.getJSON();
197    }
198
199    @Override
200    public BoxWebLink.Info getInfo() {
201        URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
202        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
203        BoxJSONResponse response = (BoxJSONResponse) request.send();
204        return new Info(response.getJSON());
205    }
206
207    @Override
208    public BoxWebLink.Info getInfo(String... fields) {
209        String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
210        URL url = WEB_LINK_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
211
212        BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "GET");
213        BoxJSONResponse response = (BoxJSONResponse) request.send();
214        return new Info(response.getJSON());
215    }
216
217    /**
218     * Updates the information about this weblink with any info fields that have been modified locally.
219     *
220     * <p>The only fields that will be updated are the ones that have been modified locally. For example, the following
221     * code won't update any information (or even send a network request) since none of the info's fields were
222     * changed:</p>
223     *
224     * <pre>BoxWebLink webLink = new BoxWebLink(api, id);
225     * BoxWebLink.Info info = webLink.getInfo();
226     * webLink.updateInfo(info);</pre>
227     *
228     * @param info the updated info.
229     */
230    public void updateInfo(BoxWebLink.Info info) {
231        URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
232        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
233        request.setBody(info.getPendingChanges());
234        BoxJSONResponse response = (BoxJSONResponse) request.send();
235        JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
236        info.update(jsonObject);
237    }
238
239    @Override
240    public BoxWebLink.Info setCollections(BoxCollection... collections) {
241        JsonArray jsonArray = new JsonArray();
242        for (BoxCollection collection : collections) {
243            JsonObject collectionJSON = new JsonObject();
244            collectionJSON.add("id", collection.getID());
245            jsonArray.add(collectionJSON);
246        }
247        JsonObject infoJSON = new JsonObject();
248        infoJSON.add("collections", jsonArray);
249
250        String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString();
251        URL url = WEB_LINK_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
252        BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
253        request.setBody(infoJSON.toString());
254        BoxJSONResponse response = (BoxJSONResponse) request.send();
255        JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
256        return new Info(jsonObject);
257    }
258
259    /**
260     * Contains information about a BoxWebLink.
261     */
262    public class Info extends BoxItem.Info {
263        private URL linkURL;
264        private String description;
265
266        /**
267         * Constructs an empty Info object.
268         */
269        public Info() {
270            super();
271        }
272
273        /**
274         * Constructs an Info object by parsing information from a JSON string.
275         *
276         * @param json the JSON string to parse.
277         */
278        public Info(String json) {
279            super(json);
280        }
281
282        /**
283         * Constructs an Info object using an already parsed JSON object.
284         *
285         * @param jsonObject the parsed JSON object.
286         */
287        public Info(JsonObject jsonObject) {
288            super(jsonObject.toString());
289        }
290
291        @Override
292        public BoxWebLink getResource() {
293            return BoxWebLink.this;
294        }
295
296        /**
297         * Gets the description of this weblink.
298         *
299         * @return the description of this weblink.
300         */
301        public String getDescription() {
302            return this.description;
303        }
304
305        /**
306         * Gets the URL this weblink points to.
307         *
308         * @return the URL this weblink points to.
309         */
310        public URL getLinkURL() {
311            return this.linkURL;
312        }
313
314        @Override
315        protected void parseJSONMember(JsonObject.Member member) {
316            super.parseJSONMember(member);
317
318            String memberName = member.getName();
319            JsonValue value = member.getValue();
320            try {
321                if (memberName.equals("url")) {
322                    try {
323                        if (value.asString().isEmpty()) {
324                            this.linkURL = null;
325                        } else {
326                            this.linkURL = new URL(value.asString());
327                        }
328                    } catch (MalformedURLException e) {
329                        throw new BoxAPIException("Couldn't parse url for weblink", e);
330                    }
331                } else if (memberName.equals("description")) {
332                    this.description = value.asString();
333                }
334            } catch (Exception e) {
335                throw new BoxDeserializationException(memberName, value.toString(), e);
336            }
337        }
338    }
339}