diff --git a/src/main/java/org/openstreetmap/josm/plugins/maproulette/actions/downloadtasks/MapRouletteDownloadTaskBox.java b/src/main/java/org/openstreetmap/josm/plugins/maproulette/actions/downloadtasks/MapRouletteDownloadTaskBox.java index 1293413..1235499 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/maproulette/actions/downloadtasks/MapRouletteDownloadTaskBox.java +++ b/src/main/java/org/openstreetmap/josm/plugins/maproulette/actions/downloadtasks/MapRouletteDownloadTaskBox.java @@ -27,6 +27,7 @@ import org.openstreetmap.josm.gui.progress.ProgressMonitor; import org.openstreetmap.josm.gui.progress.ProgressTaskId; import org.openstreetmap.josm.gui.util.GuiHelper; +import org.openstreetmap.josm.io.OsmApiException; import org.openstreetmap.josm.io.OsmTransferException; import org.openstreetmap.josm.plugins.maproulette.api.TaskAPI; import org.openstreetmap.josm.plugins.maproulette.api.UnauthorizedException; @@ -108,7 +109,7 @@ protected void realRun() throws IOException, OsmTransferException { } }); // This is specifically so that user's don't get a bug report message - final var transferException = new OsmTransferException(unauthorizedException); + final var transferException = new OsmApiException(unauthorizedException); transferException.setUrl(MapRouletteConfig.getBaseUrl()); throw transferException; } catch (IOException e) { diff --git a/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/BundleAPI.java b/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/BundleAPI.java index c9d4d2f..f0d3b38 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/BundleAPI.java +++ b/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/BundleAPI.java @@ -84,9 +84,10 @@ public static TaskBundle parseBundle(InputStream bundle) { * * @param id The id of the bundle to get * @return The specified bundle + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ @Nonnull - public static TaskBundle getBundle(long id) { + public static TaskBundle getBundle(long id) throws UnauthorizedException { final var client = get(getBaseUrl() + PATH + "/" + id); try { try (var inputStream = client.connect().getContent()) { @@ -104,8 +105,9 @@ public static TaskBundle getBundle(long id) { * * @param id The bundle to delete * @return {@code true} if the deletion was successful + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static boolean deleteBundle(long id) { + public static boolean deleteBundle(long id) throws UnauthorizedException { final var client = delete(getBaseUrl() + PATH + "/" + id); try { int responseCode = client.connect().getResponseCode(); @@ -126,9 +128,10 @@ public static boolean deleteBundle(long id) { * @param original The original bundle * @param taskIds The tasks to remove * @return The new bundle + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ @Nonnull - public static TaskBundle unbundle(TaskBundle original, long... taskIds) { + public static TaskBundle unbundle(TaskBundle original, long... taskIds) throws UnauthorizedException { final var client = get(getBaseUrl() + PATH + "/" + original.id() + "/unbundle", Map.of("taskIds", LongStream.of(taskIds).mapToObj(Long::toString).collect(Collectors.joining(",")))); try { diff --git a/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/UnauthorizedException.java b/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/UnauthorizedException.java index deccb8e..e5d2c37 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/UnauthorizedException.java +++ b/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/UnauthorizedException.java @@ -1,12 +1,13 @@ // License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.maproulette.api; +import java.io.IOException; import java.io.Serial; /** * Thrown if the user is not authorized for the specified operation */ -public class UnauthorizedException extends RuntimeException { +public class UnauthorizedException extends IOException { /** * The serial UID for this exception */ diff --git a/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/parsers/TaskParser.java b/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/parsers/TaskParser.java index dab46aa..ae7eb9e 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/parsers/TaskParser.java +++ b/src/main/java/org/openstreetmap/josm/plugins/maproulette/api/parsers/TaskParser.java @@ -7,6 +7,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.ArrayList; @@ -20,6 +21,7 @@ import org.openstreetmap.josm.gui.progress.NullProgressMonitor; import org.openstreetmap.josm.io.IllegalDataException; import org.openstreetmap.josm.io.OsmChangeReader; +import org.openstreetmap.josm.plugins.maproulette.api.UnauthorizedException; import org.openstreetmap.josm.plugins.maproulette.api.enums.TaskStatus; import org.openstreetmap.josm.plugins.maproulette.api.model.ElementCreate; import org.openstreetmap.josm.plugins.maproulette.api.model.ElementTagChange; @@ -61,21 +63,33 @@ private TaskParser() { * * @param inputStream the stream to get the task from * @return The new task. May be a singular task or an array of tasks. + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ @Nonnull - public static Object parseTask(InputStream inputStream) { + public static Object parseTask(InputStream inputStream) throws UnauthorizedException { try (var reader = Json.createParser(inputStream)) { while (reader.hasNext()) { var value = switch (reader.next()) { case START_OBJECT -> parseTask(reader.getObject()); case START_ARRAY -> reader.getArrayStream().filter(JsonObject.class::isInstance) - .map(JsonObject.class::cast).map(TaskParser::parseTask).toArray(Task[]::new); + .map(JsonObject.class::cast).map(obj -> { + try { + return parseTask(obj); + } catch (UnauthorizedException e) { + throw new UncheckedIOException(e); + } + }).toArray(Task[]::new); default -> null; }; if (value != null) { return value; } } + } catch (UncheckedIOException e) { + if (e.getCause()instanceof UnauthorizedException unauthorizedException) { + throw unauthorizedException; + } + throw e; } throw new IllegalArgumentException("InputStream did not contain expected JSON data"); } @@ -85,9 +99,10 @@ public static Object parseTask(InputStream inputStream) { * * @param obj the JsonObject to get the task from * @return The new task + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ @Nonnull - private static Task parseTask(JsonObject obj) { + private static Task parseTask(JsonObject obj) throws UnauthorizedException { MessageParser.parse(obj); try { return new Task(obj.getJsonNumber("id").longValue(), obj.getString("name"), diff --git a/src/main/java/org/openstreetmap/josm/plugins/maproulette/util/HttpClientUtils.java b/src/main/java/org/openstreetmap/josm/plugins/maproulette/util/HttpClientUtils.java index b8fcea5..1c4fb4c 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/maproulette/util/HttpClientUtils.java +++ b/src/main/java/org/openstreetmap/josm/plugins/maproulette/util/HttpClientUtils.java @@ -10,6 +10,7 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.openstreetmap.josm.plugins.maproulette.api.UnauthorizedException; import org.openstreetmap.josm.tools.HttpClient; /** @@ -28,8 +29,9 @@ private HttpClientUtils() { * * @param url The url to GET * @return The client to use + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static HttpClient get(String url) { + public static HttpClient get(String url) throws UnauthorizedException { return get(url, Collections.emptyMap()); } @@ -39,8 +41,9 @@ public static HttpClient get(String url) { * @param url The url to GET * @param queryParameters The query parameters * @return The client to use + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static HttpClient get(String url, Map queryParameters) { + public static HttpClient get(String url, Map queryParameters) throws UnauthorizedException { var client = HttpClient.create(safeUrl(url, queryParameters)); sign(client); return client; @@ -69,8 +72,9 @@ private static URL safeUrl(String url, Map queryParameters) { * Sign the client * * @param client The client to add the api key to + * @throws UnauthorizedException if the user isn't logged in or hasn't logged in to MapRoulette before */ - private static void sign(HttpClient client) { + private static void sign(HttpClient client) throws UnauthorizedException { client.setHeader("apiKey", OsmPreferenceUtils.getMapRouletteApiKey()); } @@ -91,8 +95,9 @@ private static String query(Map queryParameters) { * @param url The url to PUT * @param queryParameters The query parameters * @return The client to use + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static HttpClient put(String url, Map queryParameters) { + public static HttpClient put(String url, Map queryParameters) throws UnauthorizedException { var client = put(url, Collections.emptyMap(), query(queryParameters).substring(1).getBytes(StandardCharsets.UTF_8)); client.setHeader("Content-Type", "application/x-www-form-urlencoded"); @@ -106,8 +111,10 @@ public static HttpClient put(String url, Map queryParameters) { * @param queryParameters The query parameters * @param body The body to use * @return The client to use + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static HttpClient put(String url, Map queryParameters, byte[] body) { + public static HttpClient put(String url, Map queryParameters, byte[] body) + throws UnauthorizedException { var client = HttpClient.create(safeUrl(url, queryParameters), "PUT"); client.setRequestBody(Objects.requireNonNullElse(body, new byte[0])); sign(client); @@ -120,8 +127,9 @@ public static HttpClient put(String url, Map queryParameters, by * @param url The URL to POST * @param queryParameters The query parameters to be put in the body * @return The client to use + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static HttpClient post(String url, Map queryParameters) { + public static HttpClient post(String url, Map queryParameters) throws UnauthorizedException { var client = HttpClient.create(safeUrl(url, Collections.emptyMap()), "POST"); client.setRequestBody(query(queryParameters).substring(1).getBytes(StandardCharsets.UTF_8)); sign(client); @@ -133,8 +141,9 @@ public static HttpClient post(String url, Map queryParameters) { * * @param url The URL to DELETE * @return The client to use + * @throws UnauthorizedException if the user hasn't logged in to MapRoulette */ - public static HttpClient delete(String url) { + public static HttpClient delete(String url) throws UnauthorizedException { var client = HttpClient.create(safeUrl(url, Collections.emptyMap()), "DELETE"); sign(client); return client;