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}