    001// License: GPL. For details, see LICENSE file.
    002package org.openstreetmap.josm.plugins.streetside.actions;
    003
    004import java.awt.event.ActionEvent;
    005import java.awt.event.KeyEvent;
    006import java.io.IOException;
    007
    008import javax.json.Json;
    009import javax.swing.JOptionPane;
    010
    011import org.apache.http.client.methods.CloseableHttpResponse;
    012import org.apache.http.client.methods.HttpPost;
    013import org.apache.http.entity.StringEntity;
    014import org.apache.http.impl.client.CloseableHttpClient;
    015import org.apache.http.impl.client.HttpClientBuilder;
    016import org.apache.http.util.EntityUtils;
    017import org.openstreetmap.josm.actions.JosmAction;
    018import org.openstreetmap.josm.gui.Notification;
    019import org.openstreetmap.josm.plugins.streetside.StreetsideLayer;
    020import org.openstreetmap.josm.plugins.streetside.StreetsideLocationChangeset;
    021import org.openstreetmap.josm.plugins.streetside.gui.StreetsideChangesetDialog;
    022import org.openstreetmap.josm.plugins.streetside.utils.PluginState;
    023import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
    024import org.openstreetmap.josm.plugins.streetside.utils.StreetsideURL.APIv3;
    025import org.openstreetmap.josm.plugins.streetside.utils.StreetsideUtils;
    026import org.openstreetmap.josm.plugins.streetside.utils.api.JsonLocationChangesetEncoder;
    027import org.openstreetmap.josm.tools.I18n;
    028import org.openstreetmap.josm.tools.ImageProvider;
    029import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
    030import org.openstreetmap.josm.tools.Logging;
    031import org.openstreetmap.josm.tools.Shortcut;
    032
    033/**
    034 * Imports a set of picture files into JOSM. They must be in jpg or png format.
    035 */
    036public class StreetsideSubmitCurrentChangesetAction extends JosmAction {
    037
    038  private static final long serialVersionUID = 4995924098228082806L;
    039  private final StreetsideChangesetDialog changesetDialog;
    040
    041  /**
    042   * Main constructor.
    043   * @param changesetDialog Streetside changeset dialog
    044   */
    045  public StreetsideSubmitCurrentChangesetAction(StreetsideChangesetDialog changesetDialog) {
    046    super(
    047      I18n.tr("Submit changeset"),
    048      new ImageProvider("dialogs", "streetside-upload").setSize(ImageSizes.DEFAULT),
    049      I18n.tr("Submit the current changeset"),
    050      // CHECKSTYLE.OFF: LineLength
    051      Shortcut.registerShortcut("Submit changeset to Streetside", I18n.tr("Submit the current changeset to Streetside"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE),
    052      // CHECKSTYLE.ON: LineLength
    053      false,
    054      "streetsideSubmitChangeset",
    055      false
    056    );
    057    this.changesetDialog = changesetDialog;
    058    setEnabled(false);
    059  }
    060
    061  @Override
    062  public void actionPerformed(ActionEvent event) {
    063    new Thread(() -> {
    064      changesetDialog.setUploadPending(true);
    065      String token = StreetsideProperties.ACCESS_TOKEN.get();
    066      if (token != null && !token.trim().isEmpty()) {
    067        PluginState.setSubmittingChangeset(true);
    068        StreetsideUtils.updateHelpText();
    069        HttpClientBuilder builder = HttpClientBuilder.create();
    070        HttpPost httpPost = new HttpPost(APIv3.submitChangeset().toString());
    071        httpPost.addHeader("content-type", "application/json");
    072        httpPost.addHeader("Authorization", "Bearer " + token);
    073        StreetsideLocationChangeset locationChangeset = StreetsideLayer.getInstance().getLocationChangeset();
    074        String json = JsonLocationChangesetEncoder.encodeLocationChangeset(locationChangeset).build().toString();
    075        Logging.info("Sending JSON to " + APIv3.submitChangeset() + "\n  " + json);
    076        try (CloseableHttpClient httpClient = builder.build()) {
    077          httpPost.setEntity(new StringEntity(json));
    078          CloseableHttpResponse response = httpClient.execute(httpPost);
    079          Logging.debug("HTTP request finished with response code " + response.getStatusLine().getStatusCode());
    080          if (response.getStatusLine().getStatusCode() == 201) {
    081            final String key = Json.createReader(response.getEntity().getContent()).readObject().getString("key");
    082            final String state = Json.createReader(response.getEntity().getContent()).readObject().getString("state");
    083            I18n.marktr("rejected");
    084            I18n.marktr("pending");
    085            I18n.marktr("approved");
    086            final String message = I18n.tr("{0} images submitted, Changeset key: {1}, State: {2}", locationChangeset.size(), key, state);
    087            Logging.debug(message);
    088            new Notification(message)
    089              .setDuration(Notification.TIME_LONG)
    090              .setIcon("rejected".equals(state) ? JOptionPane.ERROR_MESSAGE : JOptionPane.INFORMATION_MESSAGE)
    091              .show();
    092            locationChangeset.cleanChangeset(); // TODO: Remove only uploaded changes. If the user made changes while uploading the changeset, these changes would also be removed, although they weren't uploaded. Alternatively: Disallow editing while uploading.
    093          } else {
    094            new Notification(
    095              I18n.tr("Changeset upload failed with {0} error ''{1} {2}''!",
    096                response.getStatusLine().getProtocolVersion(),
    097                response.getStatusLine().getStatusCode(),
    098                response.getStatusLine().getReasonPhrase()
    099              )
    100            ).setIcon(JOptionPane.ERROR_MESSAGE)
    101              .setDuration(Notification.TIME_LONG)
    102              .show();
    103            Logging.error("Failed response " + EntityUtils.toString(response.getEntity()));
    104          }
    105        } catch (IOException e) {
    106          Logging.log(Logging.LEVEL_ERROR, "Exception while trying to submit a changeset to streetside.com", e);
    107          new Notification(
    108            I18n.tr("An exception occured while trying to submit a changeset. If this happens repeatedly, consider reporting a bug via the Help menu. If this message appears for the first time, simply try it again. This might have been an issue with the internet connection.")
    109          ).setDuration(Notification.TIME_LONG)
    110            .setIcon(JOptionPane.ERROR_MESSAGE)
    111            .show();
    112        } finally {
    113          PluginState.setSubmittingChangeset(false);
    114        }
    115      } else {
    116        // TODO: currently no login for Microsoft
    117        //PluginState.notLoggedInToStreetsideDialog();
    118      }
    119      changesetDialog.setUploadPending(false);
    120    }, "Streetside changeset upload").start();
    121  }
    122}