diff options
author | Jörg Frings-Fürst <debian@jff.email> | 2023-06-14 20:36:37 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff.email> | 2023-06-14 20:36:37 +0200 |
commit | bb80d3feebdc9acc52e3f4ad24084d8425f043a2 (patch) | |
tree | 2084a84c39f159c6aea254775dc0880d52579d45 /plugins/shotwell-publishing/PiwigoPublishing.vala | |
parent | b26ff0798252a1a8072dd2c7a67f6205de9fde11 (diff) | |
parent | 31804433d72460cbe0a39f9f8ea5e76058d84cda (diff) |
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'plugins/shotwell-publishing/PiwigoPublishing.vala')
-rw-r--r-- | plugins/shotwell-publishing/PiwigoPublishing.vala | 445 |
1 files changed, 240 insertions, 205 deletions
diff --git a/plugins/shotwell-publishing/PiwigoPublishing.vala b/plugins/shotwell-publishing/PiwigoPublishing.vala index d311ac5..9bf0013 100644 --- a/plugins/shotwell-publishing/PiwigoPublishing.vala +++ b/plugins/shotwell-publishing/PiwigoPublishing.vala @@ -1,18 +1,28 @@ -/* Copyright 2016 Software Freedom Conservancy Inc. - * - * This software is licensed under the GNU Lesser General Public License - * (version 2.1 or later). See the COPYING file in this distribution. - */ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2016 Software Freedom Conservancy Inc. -public class PiwigoService : Object, Spit.Pluggable, Spit.Publishing.Service { - private const string ICON_FILENAME = "piwigo.svg"; +internal class Publishing.Piwigo.Account : Spit.Publishing.Account, Object { + public string server_uri; + public string user; - private static Gdk.Pixbuf[] icon_pixbuf_set = null; - - public PiwigoService(GLib.File resource_directory) { - if (icon_pixbuf_set == null) - icon_pixbuf_set = Resources.load_from_resource - (Resources.RESOURCE_PATH + "/" + ICON_FILENAME); + public Account(string server_uri, string user) { + this.server_uri = server_uri; + this.user = user; + } + + public string display_name() { + try { + var uri = Uri.parse(server_uri, UriFlags.NONE); + return user + "@" + uri.get_host(); + } catch (Error err) { + debug("Failed to parse uri in Piwigo account. %s", err.message); + return user + "@" + server_uri; + } + } +} + +public class PiwigoService : Object, Spit.Pluggable, Spit.Publishing.Service { + public PiwigoService() { } public int get_pluggable_interface(int min_host_interface, int max_host_interface) { @@ -21,35 +31,68 @@ public class PiwigoService : Object, Spit.Pluggable, Spit.Publishing.Service { } public unowned string get_id() { - return "org.yorba.shotwell.publishing.piwigo"; + return "org.gnome.shotwell.publishing.piwigo"; } public unowned string get_pluggable_name() { return "Piwigo"; } - public void get_info(ref Spit.PluggableInfo info) { + public Spit.PluggableInfo get_info() { + var info = new Spit.PluggableInfo(); + info.authors = "Bruno Girin"; info.copyright = _("Copyright 2016 Software Freedom Conservancy Inc."); info.translators = Resources.TRANSLATORS; info.version = _VERSION; - info.website_name = Resources.WEBSITE_NAME; - info.website_url = Resources.WEBSITE_URL; - info.is_license_wordwrapped = false; - info.license = Resources.LICENSE; - info.icons = icon_pixbuf_set; + info.icon_name = "piwigo"; + + return info; } public void activation(bool enabled) { } public Spit.Publishing.Publisher create_publisher(Spit.Publishing.PluginHost host) { - return new Publishing.Piwigo.PiwigoPublisher(this, host); + return new Publishing.Piwigo.PiwigoPublisher(this, host, null); + } + + public Spit.Publishing.Publisher create_publisher_with_account(Spit.Publishing.PluginHost host, + Spit.Publishing.Account? account) { + return new Publishing.Piwigo.PiwigoPublisher(this, host, account); } public Spit.Publishing.Publisher.MediaType get_supported_media() { return (Spit.Publishing.Publisher.MediaType.PHOTO); } + + public Gee.List<Spit.Publishing.Account>? get_accounts(string profile_id) { + var list = new Gee.ArrayList<Spit.Publishing.Account>(); + + // Always add the empty default account to allow new logins + list.add(new Spit.Publishing.DefaultAccount()); + + // Collect information from saved logins + var schema = new Secret.Schema (Publishing.Piwigo.PiwigoPublisher.PASSWORD_SCHEME, Secret.SchemaFlags.NONE, + Publishing.Piwigo.PiwigoPublisher.SCHEMA_KEY_PROFILE_ID, Secret.SchemaAttributeType.STRING, + "url", Secret.SchemaAttributeType.STRING, + "user", Secret.SchemaAttributeType.STRING); + + var attributes = new HashTable<string, string>(str_hash, str_equal); + attributes[Publishing.Piwigo.PiwigoPublisher.SCHEMA_KEY_PROFILE_ID] = profile_id; + try { + var entries = Secret.password_searchv_sync(schema, attributes, Secret.SearchFlags.ALL, null); + + foreach (var entry in entries) { + var found_attributes = entry.get_attributes(); + list.add(new Publishing.Piwigo.Account(found_attributes["url"], found_attributes["user"])); + } + } catch (Error err) { + warning("Failed to look up accounts for Piwigo: %s", err.message); + } + + return list; + } } namespace Publishing.Piwigo { @@ -117,12 +160,16 @@ internal class PublishingParameters { public SizeEntry photo_size = null; public bool title_as_comment = false; public bool no_upload_tags = false; + public bool no_upload_ratings = false; public PublishingParameters() { } } public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { + internal const string PASSWORD_SCHEME = "org.gnome.Shotwell.Piwigo"; + internal const string SCHEMA_KEY_PROFILE_ID = "shotwell-profile-id"; + private Spit.Publishing.Service service; private Spit.Publishing.PluginHost host; private bool running = false; @@ -131,13 +178,26 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { private Category[] categories = null; private PublishingParameters parameters = null; private Spit.Publishing.ProgressCallback progress_reporter = null; + private Secret.Schema? schema = null; + private Publishing.Piwigo.Account? account = null; public PiwigoPublisher(Spit.Publishing.Service service, - Spit.Publishing.PluginHost host) { + Spit.Publishing.PluginHost host, + Spit.Publishing.Account? account) { debug("PiwigoPublisher instantiated."); this.service = service; this.host = host; session = new Session(); + + // This should only ever be the default account which we don't care about + if (account is Publishing.Piwigo.Account) { + this.account = (Publishing.Piwigo.Account)account; + } + + this.schema = new Secret.Schema (PASSWORD_SCHEME, Secret.SchemaFlags.NONE, + SCHEMA_KEY_PROFILE_ID, Secret.SchemaAttributeType.STRING, + "url", Secret.SchemaAttributeType.STRING, + "user", Secret.SchemaAttributeType.STRING); } // Publisher interface implementation @@ -164,14 +224,16 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { if (session.is_authenticated()) { debug("PiwigoPublisher: session is authenticated."); - do_fetch_categories(); + do_fetch_categories.begin(); } else { debug("PiwigoPublisher: session is not authenticated."); string? persistent_url = get_persistent_url(); string? persistent_username = get_persistent_username(); - string? persistent_password = get_persistent_password(); + string? persistent_password = get_persistent_password(persistent_url, persistent_username); + + // This will only be null if either of the other two was null or the password did not exist if (persistent_url != null && persistent_username != null && persistent_password != null) - do_network_login(persistent_url, persistent_username, + do_network_login.begin(persistent_url, persistent_username, persistent_password, get_remember_password()); else do_show_authentication_pane(); @@ -185,27 +247,65 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { // Session and persistent data public string? get_persistent_url() { - return host.get_config_string("url", null); + if (account != null) { + return account.server_uri; + } + + return null; } private void set_persistent_url(string url) { - host.set_config_string("url", url); + // Do nothing } public string? get_persistent_username() { - return host.get_config_string("username", null); + if (account != null) { + return account.user; + } + + return null; } private void set_persistent_username(string username) { - host.set_config_string("username", username); + // Do nothing } - public string? get_persistent_password() { - return host.get_config_string("password", null); + public string? get_persistent_password(string? url, string? user) { + if (url != null && user != null) { + try { + var pw = Secret.password_lookup_sync(this.schema, null, + SCHEMA_KEY_PROFILE_ID, host.get_current_profile_id(), + "url", url, "user", user); + + return pw; + } catch (Error err) { + critical("Failed to lookup the password for url %s and user %s: %s", url, user, err.message); + + return null; + } + } + + return null; } - private void set_persistent_password(string? password) { - host.set_config_string("password", password); + private void set_persistent_password(string? url, string? user, string? password) { + try { + if (password == null) { + // remove + Secret.password_clear_sync(this.schema, null, + SCHEMA_KEY_PROFILE_ID, host.get_current_profile_id(), + "url", url, "user", user); + } else { + Secret.password_store_sync(this.schema, Secret.COLLECTION_DEFAULT, + "Shotwell publishing (Piwigo account %s@%s)".printf(user, url), + password, + null, + SCHEMA_KEY_PROFILE_ID, host.get_current_profile_id(), + "url", url, "user", user); + } + } catch (Error err) { + critical("Failed to store password for %s@%s: %s", user, url, err.message); + } } public bool get_remember_password() { @@ -256,6 +356,14 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { host.set_config_bool("last-no-upload-tags", no_upload_tags); } + private bool get_last_no_upload_ratings() { + return host.get_config_bool("last-no-upload-ratings", false); + } + + private void set_last_no_upload_ratings(bool no_upload_ratings) { + host.set_config_bool("last-no-upload-ratings", no_upload_ratings); + } + private bool get_metadata_removal_choice() { return host.get_config_bool("strip_metadata", false); } @@ -290,9 +398,14 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { private void do_show_ssl_downgrade_pane (SessionLoginTransaction trans, string url) { - var uri = new Soup.URI (url); + string host_name = ""; + try { + host_name = GLib.Uri.parse (url, GLib.UriFlags.NONE).get_host(); + } catch (Error err) { + debug("Failed to parse URL: %s", err.message); + } host.set_service_locked (false); - var ssl_pane = new SSLErrorPane (trans, uri.get_host ()); + var ssl_pane = new SSLErrorPane (trans, host_name); ssl_pane.proceed.connect (() => { debug ("SSL: User wants us to retry with broken certificate"); this.session = new Session (); @@ -300,9 +413,9 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { string? persistent_url = get_persistent_url(); string? persistent_username = get_persistent_username(); - string? persistent_password = get_persistent_password(); + string? persistent_password = get_persistent_password(persistent_url, persistent_username); if (persistent_url != null && persistent_username != null && persistent_password != null) - do_network_login(persistent_url, persistent_username, + do_network_login.begin(persistent_url, persistent_username, persistent_password, get_remember_password()); else do_show_authentication_pane(); @@ -330,7 +443,7 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { if (!running) return; - do_network_login(url, username, password, remember_password); + do_network_login.begin(url, username, password, remember_password); } /** @@ -344,24 +457,24 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { * @param username the name of the Piwigo user used to login * @param password the password of the Piwigo user used to login */ - private void do_network_login(string url, string username, string password, bool remember_password) { + private async void do_network_login(string url, string username, string password, bool remember_password) { debug("ACTION: logging in"); host.set_service_locked(true); host.install_login_wait_pane(); set_remember_password(remember_password); - if (remember_password) - set_persistent_password(password); - else - set_persistent_password(null); + if (remember_password) { + set_persistent_password(url, username, password); + } else { + set_persistent_password(url, username, null); + } SessionLoginTransaction login_trans = new SessionLoginTransaction( session, normalise_url(url), username, password); - login_trans.network_error.connect(on_login_network_error); - login_trans.completed.connect(on_login_network_complete); try { - login_trans.execute(); + yield login_trans.execute_async(); + on_login_network_complete(login_trans); } catch (Spit.Publishing.PublishingError err) { if (err is Spit.Publishing.PublishingError.SSL_FAILED) { debug ("ERROR: SSL connection problems"); @@ -405,8 +518,6 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { */ private void on_login_network_complete(Publishing.RESTSupport.Transaction txn) { debug("EVENT: on_login_network_complete"); - txn.completed.disconnect(on_login_network_complete); - txn.network_error.disconnect(on_login_network_error); try { Publishing.RESTSupport.XmlDocument.parse_string( @@ -435,34 +546,9 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { debug("Setting session pwg_id to %s", pwg_id); session.set_pwg_id(pwg_id); - do_fetch_session_status(endpoint_url, pwg_id); - } - - /** - * Event triggered when a network login action fails due to a network error. - * - * This event triggered as a result of a network error during the login - * transaction. As a result, it assumes that the service URL entered in the - * authentication dialog is incorrect and re-presents the authentication - * dialog with FAILED_RETRY_URL mode. - * - * @param bad_txn the received REST transaction - * @param err the received error - */ - private void on_login_network_error( - Publishing.RESTSupport.Transaction bad_txn, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_login_network_error"); - bad_txn.completed.disconnect(on_login_network_complete); - bad_txn.network_error.disconnect(on_login_network_error); - - if (session.is_authenticated()) // ignore these events if the session is already auth'd - return; - - do_show_authentication_pane(AuthenticationPane.Mode.FAILED_RETRY_URL); + do_fetch_session_status.begin(endpoint_url, pwg_id); } - + /** * Action to fetch the session status for a known Piwigo user. * @@ -473,29 +559,27 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { * persisted. In this case, it will log the user in and confirm the * identity. */ - private void do_fetch_session_status(string url = "", string pwg_id = "") { + private async void do_fetch_session_status(string url = "", string pwg_id = "") { debug("ACTION: fetching session status"); host.set_service_locked(true); host.install_account_fetch_wait_pane(); if (!session.is_authenticated()) { SessionGetStatusTransaction status_txn = new SessionGetStatusTransaction.unauthenticated(session, url, pwg_id); - status_txn.network_error.connect(on_session_get_status_error); - status_txn.completed.connect(on_session_get_status_complete); try { - status_txn.execute(); + yield status_txn.execute_async(); + on_session_get_status_complete(status_txn); } catch (Spit.Publishing.PublishingError err) { debug("ERROR: do_fetch_session_status, not authenticated"); do_show_error(err); } } else { SessionGetStatusTransaction status_txn = new SessionGetStatusTransaction(session); - status_txn.network_error.connect(on_session_get_status_error); - status_txn.completed.connect(on_session_get_status_complete); try { - status_txn.execute(); + yield status_txn.execute_async(); + on_session_get_status_complete(status_txn); } catch (Spit.Publishing.PublishingError err) { debug("ERROR: do_fetch_session_status, authenticated"); do_show_error(err); @@ -512,8 +596,6 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { */ private void on_session_get_status_complete(Publishing.RESTSupport.Transaction txn) { debug("EVENT: on_session_get_status_complete"); - txn.completed.disconnect(on_session_get_status_complete); - txn.network_error.disconnect(on_session_get_status_error); if (!session.is_authenticated()) { string endpoint_url = txn.get_endpoint_url(); @@ -533,7 +615,7 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { session.authenticate(endpoint_url, username, pwg_id); set_persistent_url(session.get_pwg_url()); set_persistent_username(session.get_username()); - do_fetch_categories(); + do_fetch_categories.begin(); } catch (Spit.Publishing.PublishingError err2) { debug("ERROR: on_session_get_status_complete, inner"); do_show_error(err2); @@ -548,43 +630,30 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { // This should never happen as the session should not be // authenticated at that point so this call is a safeguard // against the interaction not happening properly. - do_fetch_categories(); + do_fetch_categories.begin(); } } /** - * Event triggered when the get session status fails due to a network error. - */ - private void on_session_get_status_error( - Publishing.RESTSupport.Transaction bad_txn, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_session_get_status_error"); - bad_txn.completed.disconnect(on_session_get_status_complete); - bad_txn.network_error.disconnect(on_session_get_status_error); - on_network_error(bad_txn, err); - } - - /** * Action that fetches all available categories from the Piwigo service. * * This action fetches all categories from the Piwigo service in order * to populate the publishing pane presented to the user. */ - private void do_fetch_categories() { + private async void do_fetch_categories() { debug("ACTION: fetching categories"); host.set_service_locked(true); host.install_account_fetch_wait_pane(); CategoriesGetListTransaction cat_trans = new CategoriesGetListTransaction(session); - cat_trans.network_error.connect(on_category_fetch_error); - cat_trans.completed.connect(on_category_fetch_complete); try { - cat_trans.execute(); + yield cat_trans.execute_async(); + on_category_fetch_complete(cat_trans); } catch (Spit.Publishing.PublishingError err) { debug("ERROR: do_fetch_categories"); do_show_error(err); + return; } } @@ -597,8 +666,6 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { */ private void on_category_fetch_complete(Publishing.RESTSupport.Transaction txn) { debug("EVENT: on_category_fetch_complete"); - txn.completed.disconnect(on_category_fetch_complete); - txn.network_error.disconnect(on_category_fetch_error); debug("PiwigoConnector: list of categories: %s", txn.get_response()); // Empty the categories if (categories != null) { @@ -654,20 +721,6 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { } /** - * Event triggered when the fetch categories transaction fails due to a - * network error. - */ - private void on_category_fetch_error( - Publishing.RESTSupport.Transaction bad_txn, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_category_fetch_error"); - bad_txn.completed.disconnect(on_category_fetch_complete); - bad_txn.network_error.disconnect(on_category_fetch_error); - on_network_error(bad_txn, err); - } - - /** * Action that shows the publishing options pane. * * This action method shows the publishing options pane. @@ -678,8 +731,8 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { host.set_service_locked(false); PublishingOptionsPane opts_pane = new PublishingOptionsPane( this, categories, get_last_category(), get_last_permission_level(), get_last_photo_size(), - get_last_title_as_comment(), get_last_no_upload_tags(), get_metadata_removal_choice()); - opts_pane.logout.connect(on_publishing_options_pane_logout_clicked); + get_last_title_as_comment(), get_last_no_upload_tags(), get_last_no_upload_ratings(), get_metadata_removal_choice()); + opts_pane.logout.connect(() => { on_publishing_options_pane_logout_clicked.begin(); }); opts_pane.publish.connect(on_publishing_options_pane_publish_clicked); host.install_dialog_pane(opts_pane, Spit.Publishing.PluginHost.ButtonMode.CLOSE); host.set_dialog_default_widget(opts_pane.get_default_widget()); @@ -688,14 +741,12 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { /** * Event triggered when the user clicks logout in the publishing options pane. */ - private void on_publishing_options_pane_logout_clicked() { + private async void on_publishing_options_pane_logout_clicked() { debug("EVENT: on_publishing_options_pane_logout_clicked"); - SessionLogoutTransaction logout_trans = new SessionLogoutTransaction(session); - logout_trans.network_error.connect(on_logout_network_error); - logout_trans.completed.connect(on_logout_network_complete); try { - logout_trans.execute(); + yield new SessionLogoutTransaction(session).execute_async(); + on_logout_network_complete(); } catch (Spit.Publishing.PublishingError err) { debug("ERROR: on_publishing_options_pane_logout_clicked"); do_show_error(err); @@ -708,29 +759,14 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { * This event de-authenticates the session and shows the authentication * pane again. */ - private void on_logout_network_complete(Publishing.RESTSupport.Transaction txn) { + private void on_logout_network_complete() { debug("EVENT: on_logout_network_complete"); - txn.completed.disconnect(on_logout_network_complete); - txn.network_error.disconnect(on_logout_network_error); session.deauthenticate(); do_show_authentication_pane(AuthenticationPane.Mode.INTRO); } - - /** - * Event triggered when the logout action fails due to a network error. - */ - private void on_logout_network_error( - Publishing.RESTSupport.Transaction bad_txn, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_logout_network_error"); - bad_txn.completed.disconnect(on_logout_network_complete); - bad_txn.network_error.disconnect(on_logout_network_error); - on_network_error(bad_txn, err); - } - + /** * Event triggered when the user clicks publish in the publishing options pane. * @@ -748,9 +784,9 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { this.strip_metadata = strip_metadata; if (parameters.category.is_local()) { - do_create_category(parameters.category); + do_create_category.begin(parameters.category); } else { - do_upload(this.strip_metadata); + do_upload.begin(this.strip_metadata); } } @@ -760,12 +796,12 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { * This actions runs a REST transaction to create a new category in the * Piwigo library. It displays a wait pane with an information message * while the transaction is running. This action should only be called with - * a local cateogory, i.e. one that does not exist on the server and does + * a local category, i.e. one that does not exist on the server and does * not yet have an ID. * * @param category the new category to create on the server */ - private void do_create_category(Category category) { + private async void do_create_category(Category category) { debug("ACTION: creating a new category: %s".printf(category.name)); assert(category.is_local()); @@ -774,11 +810,10 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { CategoriesAddTransaction creation_trans = new CategoriesAddTransaction( session, category.name.strip(), int.parse(category.uppercats), category.comment); - creation_trans.network_error.connect(on_category_add_error); - creation_trans.completed.connect(on_category_add_complete); try { - creation_trans.execute(); + yield creation_trans.execute_async(); + on_category_add_complete(creation_trans); } catch (Spit.Publishing.PublishingError err) { debug("ERROR: do_create_category"); do_show_error(err); @@ -794,8 +829,6 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { */ private void on_category_add_complete(Publishing.RESTSupport.Transaction txn) { debug("EVENT: on_category_add_complete"); - txn.completed.disconnect(on_category_add_complete); - txn.network_error.disconnect(on_category_add_error); // Parse the response try { @@ -808,30 +841,17 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { string id_string = id_node->get_content(); int id = int.parse(id_string); parameters.category.id = id; - do_upload(strip_metadata); + do_upload.begin(strip_metadata); } catch (Spit.Publishing.PublishingError err) { debug("ERROR: on_category_add_complete"); do_show_error(err); } } - - /** - * Event triggered when the add category action fails due to a network error. - */ - private void on_category_add_error( - Publishing.RESTSupport.Transaction bad_txn, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_category_add_error"); - bad_txn.completed.disconnect(on_category_add_complete); - bad_txn.network_error.disconnect(on_category_add_error); - on_network_error(bad_txn, err); - } - + /** * Upload action: the big one, the one we've been waiting for! */ - private void do_upload(bool strip_metadata) { + private async void do_upload(bool strip_metadata) { this.strip_metadata = strip_metadata; debug("ACTION: uploading pictures"); @@ -842,25 +862,27 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { set_last_photo_size(parameters.photo_size.id); set_last_title_as_comment(parameters.title_as_comment); set_last_no_upload_tags(parameters.no_upload_tags); + set_last_no_upload_ratings(parameters.no_upload_ratings); set_metadata_removal_choice(strip_metadata); progress_reporter = host.serialize_publishables(parameters.photo_size.id, this.strip_metadata); Spit.Publishing.Publishable[] publishables = host.get_publishables(); Uploader uploader = new Uploader(session, publishables, parameters); - uploader.upload_complete.connect(on_upload_complete); - uploader.upload_error.connect(on_upload_error); - uploader.upload(on_upload_status_updated); + try { + var num_published = yield uploader.upload_async(on_upload_status_updated); + on_upload_complete(num_published); + } catch (Spit.Publishing.PublishingError err) { + do_show_error(err); + } } /** * Event triggered when the batch uploader reports that at least one of the * network transactions encapsulating uploads has completed successfully */ - private void on_upload_complete(Publishing.RESTSupport.BatchUploader uploader, int num_published) { + private void on_upload_complete(int num_published) { debug("EVENT: on_upload_complete"); - uploader.upload_complete.disconnect(on_upload_complete); - uploader.upload_error.disconnect(on_upload_error); // TODO: should a message be displayed to the user if num_published is zero? @@ -869,22 +891,7 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { do_show_success_pane(); } - - /** - * Event triggered when the batch uploader reports that at least one of the - * network transactions encapsulating uploads has caused a network error - */ - private void on_upload_error( - Publishing.RESTSupport.BatchUploader uploader, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_upload_error"); - uploader.upload_complete.disconnect(on_upload_complete); - uploader.upload_error.disconnect(on_upload_error); - - do_show_error(err); - } - + /** * Event triggered when upload progresses and the status needs to be updated. */ @@ -910,17 +917,6 @@ public class PiwigoPublisher : Spit.Publishing.Publisher, GLib.Object { } /** - * Helper event to handle network errors. - */ - private void on_network_error( - Publishing.RESTSupport.Transaction bad_txn, - Spit.Publishing.PublishingError err - ) { - debug("EVENT: on_network_error"); - do_show_error(err); - } - - /** * Action to display an error to the user. */ private void do_show_error(Spit.Publishing.PublishingError e) { @@ -1029,8 +1025,9 @@ internal class SSLErrorPane : Shotwell.Plugins.Common.BuilderPane { base.constructed (); var label = this.get_builder ().get_object ("main_text") as Gtk.Label; + var bold_host = "<b>%s</b>".printf(host); // %s is the host name that we tried to connect to - label.set_text (_("This does not look like the real <b>%s</b>. Attackers might be trying to steal or alter information going to or from this site (for example, private messages, credit card information, or passwords).").printf (host)); + label.set_text (_("This does not look like the real %s. Attackers might be trying to steal or alter information going to or from this site (for example, private messages, credit card information, or passwords).").printf(bold_host)); label.use_markup = true; label = this.get_builder ().get_object ("ssl_errors") as Gtk.Label; @@ -1136,7 +1133,7 @@ internal class AuthenticationPane : Shotwell.Plugins.Common.BuilderPane { username_entry.set_text(persistent_username); } password_entry = builder.get_object ("password_entry") as Gtk.Entry; - string? persistent_password = publisher.get_persistent_password(); + string? persistent_password = publisher.get_persistent_password(persistent_url, persistent_username); if (persistent_password != null) { password_entry.set_text(persistent_password); } @@ -1205,6 +1202,7 @@ internal class PublishingOptionsPane : Shotwell.Plugins.Common.BuilderPane { private Gtk.CheckButton strip_metadata_check = null; private Gtk.CheckButton title_as_comment_check = null; private Gtk.CheckButton no_upload_tags_check = null; + private Gtk.CheckButton no_upload_ratings_check = null; private Gtk.Button logout_button; private Gtk.Button publish_button; private Gtk.TextView album_comment; @@ -1218,6 +1216,7 @@ internal class PublishingOptionsPane : Shotwell.Plugins.Common.BuilderPane { public int last_photo_size { private get; construct; } public bool last_title_as_comment { private get; construct; } public bool last_no_upload_tags { private get; construct; } + public bool last_no_upload_ratings { private get; construct; } public bool strip_metadata_enabled { private get; construct; } public Gee.List<Category> existing_categories { private get; construct; } public string default_comment { private get; construct; } @@ -1232,6 +1231,7 @@ internal class PublishingOptionsPane : Shotwell.Plugins.Common.BuilderPane { int last_photo_size, bool last_title_as_comment, bool last_no_upload_tags, + bool last_no_upload_ratings, bool strip_metadata_enabled) { Object (resource_path : Resources.RESOURCE_PATH + "/piwigo_publishing_options_pane.ui", @@ -1242,6 +1242,7 @@ internal class PublishingOptionsPane : Shotwell.Plugins.Common.BuilderPane { last_photo_size : last_photo_size, last_title_as_comment : last_title_as_comment, last_no_upload_tags : last_no_upload_tags, + last_no_upload_ratings : last_no_upload_ratings, strip_metadata_enabled : strip_metadata_enabled, existing_categories : new Gee.ArrayList<Category>.wrap (categories, Category.equal), @@ -1275,6 +1276,9 @@ internal class PublishingOptionsPane : Shotwell.Plugins.Common.BuilderPane { no_upload_tags_check = builder.get_object("no_upload_tags_check") as Gtk.CheckButton; no_upload_tags_check.set_active(last_no_upload_tags); + no_upload_ratings_check = builder.get_object("no_upload_ratings_check") as Gtk.CheckButton; + no_upload_ratings_check.set_active(last_no_upload_ratings); + logout_button = builder.get_object("logout_button") as Gtk.Button; logout_button.clicked.connect(on_logout_button_clicked); @@ -1325,6 +1329,7 @@ internal class PublishingOptionsPane : Shotwell.Plugins.Common.BuilderPane { params.photo_size = photo_sizes[size_combo.get_active()]; params.title_as_comment = title_as_comment_check.get_active(); params.no_upload_tags = no_upload_tags_check.get_active(); + params.no_upload_ratings = no_upload_ratings_check.get_active(); if (create_new_radio.get_active()) { string uploadcomment = album_comment.buffer.text.strip(); int a = within_existing_combo.get_active(); @@ -1720,12 +1725,14 @@ private class CategoriesAddTransaction : Transaction { private class ImagesAddTransaction : Publishing.RESTSupport.UploadTransaction { private PublishingParameters parameters = null; + private Session session = null; public ImagesAddTransaction(Session session, PublishingParameters parameters, Spit.Publishing.Publishable publishable) { base.with_endpoint_url(session, publishable, session.get_pwg_url()); if (session.is_authenticated()) { add_header("Cookie", "pwg_id=".concat(session.get_pwg_id())); } + this.session = session; this.parameters = parameters; string[] keywords = publishable.get_publishing_keywords(); @@ -1785,12 +1792,40 @@ private class ImagesAddTransaction : Publishing.RESTSupport.UploadTransaction { !basename.down().has_suffix(".jpg")) { basename += ".jpg"; } - disposition_table.insert("filename", Soup.URI.encode(basename, null)); + disposition_table.insert("filename", GLib.Uri.escape_string(basename, null)); disposition_table.insert("name", "image"); set_binary_disposition_table(disposition_table); + base.completed.connect(on_completed); + } + + private void on_completed() { + try{ + Publishing.RESTSupport.XmlDocument resp_doc = Publishing.RESTSupport.XmlDocument.parse_string( + base.get_response(), Transaction.validate_xml); + Xml.Node* image_node = resp_doc.get_named_child(resp_doc.get_root_node(), "image_id"); + string image_id = image_node->get_content(); + + if (!parameters.no_upload_ratings) + new ImagesAddRating(session, publishable, image_id); + } catch(Spit.Publishing.PublishingError err) { + debug("Response parse error"); + } } } -} // namespace +private class ImagesAddRating : Publishing.RESTSupport.UploadTransaction { + public ImagesAddRating(Session session, Spit.Publishing.Publishable publishable, string image_id) { + base.with_endpoint_url(session, publishable, session.get_pwg_url()); + if (session.is_authenticated()) { + add_header("Cookie", "pwg_id=".concat(session.get_pwg_id())); + } + add_argument("method", "pwg.images.rate"); + add_argument("image_id", image_id); + add_argument("rate", publishable.get_rating().to_string()); + base.execute_async.begin(); + } +} + +} // namespace |