[gnome-software] Allow purchase failures to be handled
- From: Kalev Lember <klember src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Allow purchase failures to be handled
- Date: Fri, 23 Mar 2018 16:04:58 +0000 (UTC)
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]