[gnome-software/wip/williamhua/reviews] WIP: Use login dialog to get OAuth credentials
- From: William Hua <williamhua src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/williamhua/reviews] WIP: Use login dialog to get OAuth credentials
- Date: Sun, 7 Feb 2016 16:31:05 +0000 (UTC)
commit dd2c774b566e88db347776ef36f22963c2175cb1
Author: William Hua <william hua canonical com>
Date: Sun Feb 7 01:34:06 2016 -0500
WIP: Use login dialog to get OAuth credentials
src/gnome-software.gresource.xml | 1 +
src/plugins/gs-plugin-ubuntu-reviews.c | 305 +++++++++++++++++++++++++++++++-
2 files changed, 300 insertions(+), 6 deletions(-)
---
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 710d8da..22928a3 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -27,6 +27,7 @@
<file preprocess="xml-stripblanks">gs-star-widget.ui</file>
<file preprocess="xml-stripblanks">gs-update-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-upgrade-banner.ui</file>
+ <file preprocess="xml-stripblanks">plugins/ubuntu-one.ui</file>
<file preprocess="xml-stripblanks">org.freedesktop.PackageKit.xml</file>
<file>gtk-style.css</file>
<file>gtk-style-hc.css</file>
diff --git a/src/plugins/gs-plugin-ubuntu-reviews.c b/src/plugins/gs-plugin-ubuntu-reviews.c
index 6a2d49e..01afd12 100644
--- a/src/plugins/gs-plugin-ubuntu-reviews.c
+++ b/src/plugins/gs-plugin-ubuntu-reviews.c
@@ -22,6 +22,7 @@
#include <config.h>
#include <math.h>
+#include <glib/gi18n.h>
#include <libsoup/soup.h>
#include <json-glib/json-glib.h>
#include <oauth.h>
@@ -35,6 +36,10 @@ struct GsPluginPrivate {
sqlite3 *db;
gsize db_loaded;
SoupSession *session;
+ gchar *consumer_key;
+ gchar *consumer_secret;
+ gchar *token_key;
+ gchar *token_secret;
};
typedef struct {
@@ -51,6 +56,7 @@ gs_plugin_get_name (void)
return "ubuntu-reviews";
}
+#define UBUNTU_LOGIN_SERVER "https://login.ubuntu.com"
#define UBUNTU_REVIEWS_SERVER "https://reviews.ubuntu.com/reviews"
/* Download new stats every three months */
@@ -86,10 +92,14 @@ gs_plugin_get_deps (GsPlugin *plugin)
void
gs_plugin_destroy (GsPlugin *plugin)
{
- if (plugin->priv->db != NULL)
- sqlite3_close (plugin->priv->db);
- if (plugin->priv->session != NULL)
- g_object_unref (plugin->priv->session);
+ GsPluginPrivate *priv = plugin->priv;
+
+ g_clear_pointer (&priv->token_secret, g_free);
+ g_clear_pointer (&priv->token_key, g_free);
+ g_clear_pointer (&priv->consumer_secret, g_free);
+ g_clear_pointer (&priv->consumer_key, g_free);
+ g_clear_pointer (&priv->db, sqlite3_close);
+ g_clear_object (&priv->session);
}
static gboolean
@@ -790,8 +800,6 @@ set_package_review (GsPlugin *plugin,
/* Write review into database so we can easily access it */
- /* Load OAuth token */
-
/*
result = send_review (plugin,
review,
@@ -806,6 +814,288 @@ set_package_review (GsPlugin *plugin,
return result;
}
+typedef struct
+{
+ GsPlugin *plugin;
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkWidget *cancel;
+ GtkWidget *back;
+ GtkWidget *next;
+ GtkWidget *stack;
+ GtkWidget *email;
+ GtkWidget *password;
+ GtkWidget *passcode;
+ GtkWidget *stack0;
+ GtkWidget *status00;
+ GtkWidget *box0;
+ GtkWidget *status01;
+ GtkWidget *stack1;
+ GtkWidget *status10;
+ GtkWidget *box1;
+ GtkWidget *status11;
+} LoginContext;
+
+static gboolean
+is_email_address (const gchar *text)
+{
+ text = g_utf8_strchr (text, -1, '@');
+
+ if (text == NULL)
+ return FALSE;
+
+ text = g_utf8_strchr (text + 1, -1, '.');
+
+ if (text == NULL)
+ return FALSE;
+
+ return text[1] != '\0';
+}
+
+static void
+update_dialog (LoginContext *context)
+{
+ g_print ("%s %p '%s'\n", G_STRFUNC, context->stack, gtk_stack_get_visible_child_name (GTK_STACK
(context->stack)));
+
+ if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page0")) {
+ gtk_widget_set_visible (context->cancel, TRUE);
+ gtk_widget_set_visible (context->back, FALSE);
+ gtk_widget_set_sensitive (context->next, is_email_address (gtk_entry_get_text (GTK_ENTRY
(context->email))) &&
+ gtk_entry_get_text_length (GTK_ENTRY
(context->password)) > 0);
+ gtk_button_set_label (GTK_BUTTON (context->next), _("_Next"));
+ } else if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page1")) {
+ gtk_widget_set_visible (context->cancel, TRUE);
+ gtk_widget_set_visible (context->back, TRUE);
+ gtk_widget_set_sensitive (context->next, gtk_entry_get_text_length (GTK_ENTRY
(context->passcode)) > 0);
+ gtk_button_set_label (GTK_BUTTON (context->next), _("_Next"));
+ } else if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page2")) {
+ gtk_widget_set_visible (context->cancel, FALSE);
+ gtk_widget_set_visible (context->back, FALSE);
+ gtk_widget_set_sensitive (context->next, TRUE);
+ gtk_button_set_label (GTK_BUTTON (context->next), _("_Close"));
+ }
+}
+
+static void
+dialog_show_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ g_print ("%s\n", G_STRFUNC);
+
+ update_dialog (user_data);
+}
+
+static void
+cancel_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ LoginContext *context = user_data;
+
+ g_print ("%s\n", G_STRFUNC);
+
+ gtk_dialog_response (GTK_DIALOG (context->dialog), GTK_RESPONSE_CANCEL);
+}
+
+static void
+back_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ LoginContext *context = user_data;
+
+ g_print ("%s\n", G_STRFUNC);
+
+ if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page1")) {
+ gtk_stack_set_visible_child_name (GTK_STACK (context->stack), "page0");
+ update_dialog (context);
+ }
+}
+
+static guint
+send_variant_request (SoupSession *session,
+ const gchar *method,
+ const gchar *host,
+ const gchar *uri,
+ GVariant *request,
+ GVariant **response,
+ GError **error)
+{
+ gchar *data;
+ gsize length;
+ gchar *url;
+ SoupMessage *message;
+ guint response_code;
+ GBytes *bytes;
+
+ g_return_val_if_fail (session != NULL, 0);
+ g_return_val_if_fail (method != NULL, 0);
+ g_return_val_if_fail (host != NULL, 0);
+ g_return_val_if_fail (uri != NULL, 0);
+ g_return_val_if_fail (request != NULL, 0);
+
+ g_variant_ref_sink (request);
+ data = json_gvariant_serialize_data (request, &length);
+ g_variant_unref (request);
+
+ url = g_strdup_printf ("%s%s", host, uri);
+ message = soup_message_new (method, url);
+ g_free (url);
+
+ soup_message_set_request (message, "application/json", SOUP_MEMORY_TAKE, data, length);
+ response_code = soup_session_send_message (session, message);
+ g_object_get (message, SOUP_MESSAGE_RESPONSE_BODY_DATA, &bytes, NULL);
+ g_object_unref (message);
+
+ data = g_bytes_unref_to_data (bytes, &length);
+
+ if (response)
+ *response = json_gvariant_deserialize_data (data, length, NULL, error);
+
+ g_free (data);
+
+ return response_code;
+}
+
+static void
+send_first_factor (LoginContext *context)
+{
+ GVariant *request;
+ GVariant *response;
+ guint response_code;
+ const gchar *code;
+ GError *error = NULL;
+
+ request = g_variant_new_parsed ("{ 'token_name' : 'GNOME Software', 'email' : %s, 'password' : %s }",
+ gtk_entry_get_text (GTK_ENTRY (context->email)),
+ gtk_entry_get_text (GTK_ENTRY (context->password)));
+
+ response_code = send_variant_request (context->plugin->priv->session,
+ SOUP_METHOD_POST,
+ UBUNTU_LOGIN_SERVER,
+ "/api/v2/tokens/oauth",
+ request,
+ &response,
+ &error);
+
+ if (response) {
+ g_variant_ref_sink (response);
+
+ switch (response_code) {
+ case 401:
+ g_variant_lookup (response, "code", "&s", &code);
+
+ g_print ("%s\n", code);
+
+ if (g_str_equal (code, "INVALID_CREDENTIALS")) {
+ } else if (g_str_equal (code, "TWOFACTOR_REQUIRED")) {
+ }
+
+ break;
+ }
+
+ g_variant_unref (response);
+ }
+}
+
+static void
+send_second_factor (LoginContext *context)
+{
+}
+
+static void
+next_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ LoginContext *context = user_data;
+
+ g_print ("%s %p '%s'\n", G_STRFUNC, context->stack, gtk_stack_get_visible_child_name (GTK_STACK
(context->stack)));
+
+ if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page0")) {
+ send_first_factor (context);
+ } else if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page1")) {
+ send_second_factor (context);
+ } else if (g_str_equal (gtk_stack_get_visible_child_name (GTK_STACK (context->stack)), "page2")) {
+ gtk_dialog_response (GTK_DIALOG (context->dialog), GTK_RESPONSE_CLOSE);
+ }
+}
+
+static void
+email_notify_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ g_print ("%s\n", G_STRFUNC);
+
+ update_dialog (user_data);
+}
+
+static void
+password_notify_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ g_print ("%s\n", G_STRFUNC);
+
+ update_dialog (user_data);
+}
+
+static void
+passcode_notify_cb (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ g_print ("%s\n", G_STRFUNC);
+
+ update_dialog (user_data);
+}
+
+static gboolean
+sign_into_ubuntu_one (GsPlugin *plugin,
+ GError **error)
+{
+ GsPluginPrivate *priv = plugin->priv;
+ LoginContext context = { NULL };
+
+ if (priv->consumer_key && priv->consumer_secret && priv->token_key && priv->token_secret)
+ return TRUE;
+
+ g_clear_pointer (&priv->token_secret, g_free);
+ g_clear_pointer (&priv->token_key, g_free);
+ g_clear_pointer (&priv->consumer_secret, g_free);
+ g_clear_pointer (&priv->consumer_key, g_free);
+
+ context.plugin = plugin;
+ context.builder = gtk_builder_new_from_resource ("/org/gnome/Software/plugins/ubuntu-one.ui");
+ context.dialog = GTK_WIDGET (gtk_builder_get_object (context.builder, "dialog"));
+ context.cancel = GTK_WIDGET (gtk_builder_get_object (context.builder, "cancel"));
+ context.back = GTK_WIDGET (gtk_builder_get_object (context.builder, "back"));
+ context.next = GTK_WIDGET (gtk_builder_get_object (context.builder, "next"));
+ context.stack = GTK_WIDGET (gtk_builder_get_object (context.builder, "stack"));
+ context.email = GTK_WIDGET (gtk_builder_get_object (context.builder, "email"));
+ context.password = GTK_WIDGET (gtk_builder_get_object (context.builder, "password"));
+ context.passcode = GTK_WIDGET (gtk_builder_get_object (context.builder, "passcode"));
+ context.stack0 = GTK_WIDGET (gtk_builder_get_object (context.builder, "stack0"));
+ context.status00 = GTK_WIDGET (gtk_builder_get_object (context.builder, "status00"));
+ context.box0 = GTK_WIDGET (gtk_builder_get_object (context.builder, "box0"));
+ context.status01 = GTK_WIDGET (gtk_builder_get_object (context.builder, "status01"));
+ context.stack1 = GTK_WIDGET (gtk_builder_get_object (context.builder, "stack1"));
+ context.status10 = GTK_WIDGET (gtk_builder_get_object (context.builder, "status10"));
+ context.box1 = GTK_WIDGET (gtk_builder_get_object (context.builder, "box1"));
+ context.status11 = GTK_WIDGET (gtk_builder_get_object (context.builder, "status11"));
+
+ g_signal_connect (context.dialog, "show", G_CALLBACK (dialog_show_cb), &context);
+ g_signal_connect (context.cancel, "clicked", G_CALLBACK (cancel_clicked_cb), &context);
+ g_signal_connect (context.back, "clicked", G_CALLBACK (back_clicked_cb), &context);
+ g_signal_connect (context.next, "clicked", G_CALLBACK (next_clicked_cb), &context);
+ g_signal_connect (context.email, "notify::text", G_CALLBACK (email_notify_cb), &context);
+ g_signal_connect (context.password, "notify::text", G_CALLBACK (password_notify_cb), &context);
+ g_signal_connect (context.passcode, "notify::text", G_CALLBACK (passcode_notify_cb), &context);
+
+ gtk_dialog_run (GTK_DIALOG (context.dialog));
+
+ gtk_widget_destroy (context.dialog);
+ g_object_unref (context.builder);
+}
+
gboolean
gs_plugin_app_set_review (GsPlugin *plugin,
GsApp *app,
@@ -840,6 +1130,9 @@ gs_plugin_app_set_review (GsPlugin *plugin,
if (!setup_networking (plugin, error))
return FALSE;
+ if (!sign_into_ubuntu_one (plugin, error))
+ return FALSE;
+
/* set rating for each package */
for (i = 0; i < sources->len; i++) {
package_name = g_ptr_array_index (sources, i);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]