[gnome-software] Allow purchase failures to be handled



commit 4340b4c1919141efa3ff8330641877b8f968545d
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed Jan 31 16:53:09 2018 +1300

    Allow purchase failures to be handled
    
    https://gitlab.gnome.org/GNOME/gnome-software/merge_requests/28

 lib/gs-plugin-loader.c |  6 +++++
 lib/gs-plugin-types.h  |  6 +++++
 lib/gs-plugin.c        |  6 +++++
 src/gs-page.c          | 25 ++++++++++++++++++--
 src/gs-shell.c         | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 103 insertions(+), 2 deletions(-)
---
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 6e956b82..be4e29c2 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -409,6 +409,12 @@ gs_plugin_loader_is_error_fatal (GsPluginFailureFlags failure_flags,
                if (g_error_matches (err, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_AUTH_INVALID))
                        return TRUE;
        }
+       if (failure_flags & GS_PLUGIN_FAILURE_FLAGS_FATAL_PURCHASE) {
+               if (g_error_matches (err, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_PURCHASE_NOT_SETUP))
+                       return TRUE;
+               if (g_error_matches (err, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_PURCHASE_DECLINED))
+                       return TRUE;
+       }
        if (g_error_matches (err, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_TIMED_OUT))
                return TRUE;
        return FALSE;
diff --git a/lib/gs-plugin-types.h b/lib/gs-plugin-types.h
index 2804216a..792828f5 100644
--- a/lib/gs-plugin-types.h
+++ b/lib/gs-plugin-types.h
@@ -92,6 +92,8 @@ typedef guint64 GsPluginFlags;
  * @GS_PLUGIN_ERROR_RESTART_REQUIRED:          A restart is required
  * @GS_PLUGIN_ERROR_AC_POWER_REQUIRED:         AC power is required
  * @GS_PLUGIN_ERROR_TIMED_OUT:                 The job timed out
+ * @GS_PLUGIN_ERROR_PURCHASE_NOT_SETUP:                Purchase support not setup
+ * @GS_PLUGIN_ERROR_PURCHASE_DECLINED:         Purchase was declined
  *
  * The failure error types.
  **/
@@ -115,6 +117,8 @@ typedef enum {
        GS_PLUGIN_ERROR_RESTART_REQUIRED,
        GS_PLUGIN_ERROR_AC_POWER_REQUIRED,
        GS_PLUGIN_ERROR_TIMED_OUT,
+       GS_PLUGIN_ERROR_PURCHASE_NOT_SETUP,
+       GS_PLUGIN_ERROR_PURCHASE_DECLINED,
        /*< private >*/
        GS_PLUGIN_ERROR_LAST
 } GsPluginError;
@@ -325,6 +329,7 @@ typedef enum {
  * @GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY:         Abort after any plugin error
  * @GS_PLUGIN_FAILURE_FLAGS_FATAL_AUTH:                Abort after a authentication error
  * @GS_PLUGIN_FAILURE_FLAGS_NO_CONSOLE:                Do not show a message on the console
+ * @GS_PLUGIN_FAILURE_FLAGS_FATAL_PURCHASE:    Abort after a purchase error
  *
  * The failure flags for the plugin action.
  *
@@ -337,6 +342,7 @@ typedef enum {
 #define GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY              ((guint64) 1 << 1)
 #define GS_PLUGIN_FAILURE_FLAGS_FATAL_AUTH             ((guint64) 1 << 2)
 #define GS_PLUGIN_FAILURE_FLAGS_NO_CONSOLE             ((guint64) 1 << 3)
+#define GS_PLUGIN_FAILURE_FLAGS_FATAL_PURCHASE         ((guint64) 1 << 4)
 typedef guint64 GsPluginFailureFlags;
 
 G_END_DECLS
diff --git a/lib/gs-plugin.c b/lib/gs-plugin.c
index 37e1061e..838057a9 100644
--- a/lib/gs-plugin.c
+++ b/lib/gs-plugin.c
@@ -1667,6 +1667,10 @@ gs_plugin_error_to_string (GsPluginError error)
                return "ac-power-required";
        if (error == GS_PLUGIN_ERROR_TIMED_OUT)
                return "timed-out";
+       if (error == GS_PLUGIN_ERROR_PURCHASE_NOT_SETUP)
+               return "purchase-not-setup";
+       if (error == GS_PLUGIN_ERROR_PURCHASE_DECLINED)
+               return "purchase-declined";
        return NULL;
 }
 
@@ -1988,6 +1992,8 @@ gs_plugin_failure_flags_to_string (GsPluginFailureFlags failure_flags)
                g_ptr_array_add (cstrs, "fatal-auth");
        if (failure_flags & GS_PLUGIN_FAILURE_FLAGS_NO_CONSOLE)
                g_ptr_array_add (cstrs, "no-console");
+       if (failure_flags & GS_PLUGIN_FAILURE_FLAGS_FATAL_PURCHASE)
+               g_ptr_array_add (cstrs, "fatal-purchase");
        if (cstrs->len == 0)
                return g_strdup ("none");
        g_ptr_array_add (cstrs, NULL);
diff --git a/src/gs-page.c b/src/gs-page.c
index a9882e86..7819523c 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -328,7 +328,8 @@ gs_page_purchase_authenticate_cb (GsPage *page,
        plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_PURCHASE,
                                         "app", helper->app,
                                         "price", gs_app_get_price (helper->app),
-                                        "failure-flags", GS_PLUGIN_FAILURE_FLAGS_USE_EVENTS,
+                                        "failure-flags", GS_PLUGIN_FAILURE_FLAGS_USE_EVENTS |
+                                                         GS_PLUGIN_FAILURE_FLAGS_FATAL_PURCHASE,
                                         NULL);
        gs_plugin_loader_job_process_async (priv->plugin_loader, plugin_job,
                                            helper->cancellable,
@@ -372,6 +373,25 @@ gs_page_app_purchased_cb (GObject *source,
                                              helper);
                        g_steal_pointer (&helper);
                        return;
+               } else if (g_error_matches (error,
+                                           GS_PLUGIN_ERROR,
+                                           GS_PLUGIN_ERROR_PURCHASE_NOT_SETUP)) {
+                       const gchar *url;
+
+                       /* have we been given a link */
+                       url = gs_utils_get_error_value (error);
+                       if (url != NULL) {
+                               g_autoptr(GError) error_local = NULL;
+                               g_debug ("showing link in: %s", error->message);
+                               if (!gtk_show_uri_on_window (GTK_WINDOW (gs_shell_get_window (priv->shell)),
+                                                            url,
+                                                            GDK_CURRENT_TIME,
+                                                            &error_local)) {
+                                       g_warning ("failed to show URI %s: %s",
+                                                  url, error_local->message);
+                               }
+                               return;
+                       }
                }
 
                g_warning ("failed to purchase %s: %s",
@@ -421,7 +441,8 @@ gs_page_install_purchase_response_cb (GtkDialog *dialog,
                                         "app", helper->app,
                                         "price", gs_app_get_price (helper->app),
                                         "failure-flags", GS_PLUGIN_FAILURE_FLAGS_USE_EVENTS |
-                                                         GS_PLUGIN_FAILURE_FLAGS_FATAL_AUTH,
+                                                         GS_PLUGIN_FAILURE_FLAGS_FATAL_AUTH |
+                                                         GS_PLUGIN_FAILURE_FLAGS_FATAL_PURCHASE,
                                         NULL);
        gs_plugin_loader_job_process_async (priv->plugin_loader,
                                            plugin_job,
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 351e331d..883004e5 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -982,6 +982,66 @@ gs_shell_show_event_refresh (GsShell *shell, GsPluginEvent *event)
        return TRUE;
 }
 
+static gboolean
+gs_shell_show_event_purchase (GsShell *shell, GsPluginEvent *event)
+{
+       GsApp *app = gs_plugin_event_get_app (event);
+       const GError *error = gs_plugin_event_get_error (event);
+       g_autofree gchar *str_app = NULL;
+       g_autoptr(GString) str = g_string_new (NULL);
+
+       str_app = gs_shell_get_title_from_app (app);
+       switch (error->code) {
+       case GS_PLUGIN_ERROR_AUTH_REQUIRED:
+       case GS_PLUGIN_ERROR_PIN_REQUIRED:
+               /* TRANSLATORS: failure text for the in-app notification,
+                * where the %s is the application name (e.g. "GIMP") */
+               g_string_append_printf (str, _("Unable to purchase %s: "
+                                              "authentication was required"),
+                                       str_app);
+               break;
+       case GS_PLUGIN_ERROR_AUTH_INVALID:
+               /* TRANSLATORS: failure text for the in-app notification,
+                * where the %s is the application name (e.g. "GIMP") */
+               g_string_append_printf (str, _("Unable to purchase %s: "
+                                              "authentication was invalid"),
+                                       str_app);
+               break;
+       case GS_PLUGIN_ERROR_PURCHASE_NOT_SETUP:
+               /* TRANSLATORS: failure text for the in-app notification,
+                * where the %s is the application name (e.g. "GIMP") */
+               g_string_append_printf (str, _("Unable to purchase %s: "
+                                              "no payment method setup"),
+                                       str_app);
+               break;
+       case GS_PLUGIN_ERROR_PURCHASE_DECLINED:
+               /* TRANSLATORS: failure text for the in-app notification,
+                * where the %s is the application name (e.g. "GIMP") */
+               g_string_append_printf (str, _("Unable to purchase %s: "
+                                              "payment was declined"),
+                                       str_app);
+               break;
+       default:
+               /* TRANSLATORS: failure text for the in-app notification,
+                * where the %s is the application name (e.g. "GIMP") */
+               g_string_append_printf (str, _("Unable to purchase %s"), str_app);
+               break;
+       }
+       if (str->len == 0)
+               return FALSE;
+
+       /* add extra debugging for debug builds */
+       if (gs_shell_show_detailed_error (shell, error)) {
+               g_autofree gchar *first_line = get_first_line (error->message);
+               if (first_line != NULL)
+                       g_string_append_printf (str, ":\n%s", first_line);
+       }
+
+       /* show in-app notification */
+       gs_shell_show_event_app_notify (shell, str->str, GS_SHELL_EVENT_BUTTON_NONE);
+       return TRUE;
+}
+
 static gboolean
 gs_shell_show_event_install (GsShell *shell, GsPluginEvent *event)
 {
@@ -1638,6 +1698,8 @@ gs_shell_show_event (GsShell *shell, GsPluginEvent *event)
        switch (action) {
        case GS_PLUGIN_ACTION_REFRESH:
                return gs_shell_show_event_refresh (shell, event);
+       case GS_PLUGIN_ACTION_PURCHASE:
+               return gs_shell_show_event_purchase (shell, event);
        case GS_PLUGIN_ACTION_INSTALL:
                return gs_shell_show_event_install (shell, event);
        case GS_PLUGIN_ACTION_UPDATE:


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]