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;
010
011/**
012 * Represents an individual WebLink file on Box. This class can be used to retrieve the link's URL
013 * or perform other common file operations (move, copy, delete, etc.).
014 *
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 error
017 * occurs. If you wish to implement custom error handling for errors related to the Box REST API,
018 * you should capture this exception explicitly.
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
025   * #getInfo(String...)}.
026   */
027  public static final String[] ALL_FIELDS = {
028    "type",
029    "id",
030    "sequence_id",
031    "etag",
032    "name",
033    "url",
034    "description",
035    "path_collection",
036    "created_at",
037    "modified_at",
038    "trashed_at",
039    "purged_at",
040    "created_by",
041    "modified_by",
042    "owned_by",
043    "shared_link",
044    "parent",
045    "item_status",
046    "collections"
047  };
048
049  /** Copy URL Template. */
050  public static final URLTemplate COPY_URL_TEMPLATE = new URLTemplate("web_links/%s/copy");
051  /** Web Link URL Template. */
052  public static final URLTemplate WEB_LINK_URL_TEMPLATE = new URLTemplate("web_links/%s");
053
054  /**
055   * Constructs a BoxWebLink for a weblink with a given ID.
056   *
057   * @param api the API connection to be used by the weblink.
058   * @param id the ID of the weblink.
059   */
060  public BoxWebLink(BoxAPIConnection api, String id) {
061    super(api, id);
062  }
063
064  /**
065   * Creates a shared link.
066   *
067   * @param sharedLinkRequest Shared link to create
068   * @return Created shared link.
069   */
070  public BoxSharedLink createSharedLink(BoxSharedLinkWithoutPermissionsRequest sharedLinkRequest) {
071    return createSharedLink(sharedLinkRequest.asSharedLink());
072  }
073
074  private BoxSharedLink createSharedLink(BoxSharedLink sharedLink) {
075    BoxWebLink.Info info = new BoxWebLink.Info();
076    info.setSharedLink(sharedLink);
077
078    this.updateInfo(info);
079    return info.getSharedLink();
080  }
081
082  @Override
083  public BoxWebLink.Info copy(BoxFolder destination) {
084    return this.copy(destination, null);
085  }
086
087  @Override
088  public BoxWebLink.Info copy(BoxFolder destination, String newName) {
089    URL url = COPY_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
090
091    JsonObject parent = new JsonObject();
092    parent.add("id", destination.getID());
093
094    JsonObject copyInfo = new JsonObject();
095    copyInfo.add("parent", parent);
096    if (newName != null) {
097      copyInfo.add("name", newName);
098    }
099
100    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "POST");
101    request.setBody(copyInfo.toString());
102    try (BoxJSONResponse response = request.send()) {
103      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
104      BoxWebLink copiedWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString());
105      return copiedWebLink.new Info(responseJSON);
106    }
107  }
108
109  /** Deletes this weblink by moving it to the trash. */
110  public void delete() {
111    URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
112    BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
113    request.send().close();
114  }
115
116  @Override
117  public BoxItem.Info move(BoxFolder destination) {
118    return this.move(destination, null);
119  }
120
121  @Override
122  public BoxItem.Info move(BoxFolder destination, String newName) {
123    URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
124    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
125
126    JsonObject parent = new JsonObject();
127    parent.add("id", destination.getID());
128
129    JsonObject updateInfo = new JsonObject();
130    updateInfo.add("parent", parent);
131    if (newName != null) {
132      updateInfo.add("name", newName);
133    }
134
135    request.setBody(updateInfo.toString());
136    try (BoxJSONResponse response = request.send()) {
137      JsonObject responseJSON = Json.parse(response.getJSON()).asObject();
138      BoxWebLink movedWebLink = new BoxWebLink(this.getAPI(), responseJSON.get("id").asString());
139      return movedWebLink.new Info(responseJSON);
140    }
141  }
142
143  /**
144   * Renames this weblink.
145   *
146   * @param newName the new name of the weblink.
147   */
148  public void rename(String newName) {
149    URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
150    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
151
152    JsonObject updateInfo = new JsonObject();
153    updateInfo.add("name", newName);
154
155    request.setBody(updateInfo.toString());
156    request.send().close();
157  }
158
159  @Override
160  public BoxWebLink.Info getInfo(String... fields) {
161    URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
162    if (fields.length > 0) {
163      String queryString = new QueryStringBuilder().appendParam("fields", fields).toString();
164      url =
165          WEB_LINK_URL_TEMPLATE.buildWithQuery(
166              this.getAPI().getBaseURL(), queryString, this.getID());
167    }
168
169    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "GET");
170    try (BoxJSONResponse response = request.send()) {
171      return new Info(response.getJSON());
172    }
173  }
174
175  /**
176   * Updates the information about this weblink with any info fields that have been modified
177   * locally.
178   *
179   * <p>The only fields that will be updated are the ones that have been modified locally. For
180   * example, the following code won't update any information (or even send a network request) since
181   * none of the info's fields were changed:
182   *
183   * <pre>BoxWebLink webLink = new BoxWebLink(api, id);
184   * BoxWebLink.Info info = webLink.getInfo();
185   * webLink.updateInfo(info);</pre>
186   *
187   * @param info the updated info.
188   */
189  public void updateInfo(BoxWebLink.Info info) {
190    URL url = WEB_LINK_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
191    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
192    request.setBody(info.getPendingChanges());
193    try (BoxJSONResponse response = request.send()) {
194      JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
195      info.update(jsonObject);
196    }
197  }
198
199  @Override
200  public BoxWebLink.Info setCollections(BoxCollection... collections) {
201    JsonArray jsonArray = new JsonArray();
202    for (BoxCollection collection : collections) {
203      JsonObject collectionJSON = new JsonObject();
204      collectionJSON.add("id", collection.getID());
205      jsonArray.add(collectionJSON);
206    }
207    JsonObject infoJSON = new JsonObject();
208    infoJSON.add("collections", jsonArray);
209
210    String queryString = new QueryStringBuilder().appendParam("fields", ALL_FIELDS).toString();
211    URL url =
212        WEB_LINK_URL_TEMPLATE.buildWithQuery(this.getAPI().getBaseURL(), queryString, this.getID());
213    BoxJSONRequest request = new BoxJSONRequest(this.getAPI(), url, "PUT");
214    request.setBody(infoJSON.toString());
215    try (BoxJSONResponse response = request.send()) {
216      JsonObject jsonObject = Json.parse(response.getJSON()).asObject();
217      return new Info(jsonObject);
218    }
219  }
220
221  /** Contains information about a BoxWebLink. */
222  public class Info extends BoxItem.Info {
223    private URL linkURL;
224    private String description;
225
226    /** Constructs an empty Info object. */
227    public Info() {
228      super();
229    }
230
231    /**
232     * Constructs an Info object by parsing information from a JSON string.
233     *
234     * @param json the JSON string to parse.
235     */
236    public Info(String json) {
237      super(json);
238    }
239
240    /**
241     * Constructs an Info object using an already parsed JSON object.
242     *
243     * @param jsonObject the parsed JSON object.
244     */
245    public Info(JsonObject jsonObject) {
246      super(jsonObject.toString());
247    }
248
249    @Override
250    public BoxWebLink getResource() {
251      return BoxWebLink.this;
252    }
253
254    /**
255     * Gets the description of this weblink.
256     *
257     * @return the description of this weblink.
258     */
259    public String getDescription() {
260      return this.description;
261    }
262
263    /**
264     * Gets the URL this weblink points to.
265     *
266     * @return the URL this weblink points to.
267     */
268    public URL getLinkURL() {
269      return this.linkURL;
270    }
271
272    @Override
273    protected void parseJSONMember(JsonObject.Member member) {
274      super.parseJSONMember(member);
275
276      String memberName = member.getName();
277      JsonValue value = member.getValue();
278      try {
279        if (memberName.equals("url")) {
280          try {
281            if (value.asString().isEmpty()) {
282              this.linkURL = null;
283            } else {
284              this.linkURL = new URL(value.asString());
285            }
286          } catch (MalformedURLException e) {
287            throw new BoxAPIException("Couldn't parse url for weblink", e);
288          }
289        } else if (memberName.equals("description")) {
290          this.description = value.asString();
291        }
292      } catch (Exception e) {
293        throw new BoxDeserializationException(memberName, value.toString(), e);
294      }
295    }
296  }
297}