[gnome-software/wip/hughsie/xdg-app-reviews] Add a plugin to do application reviews using the xdg-app webservice



commit 63759e81fe7608f01d270c1270f4580b25d87d4f
Author: Richard Hughes <richard hughsie com>
Date:   Wed Feb 3 16:42:46 2016 +0000

    Add a plugin to do application reviews using the xdg-app webservice

 src/plugins/Makefile.am                 |   14 ++
 src/plugins/gs-plugin-xdg-app-reviews.c |  305 +++++++++++++++++++++++++++++++
 2 files changed, 319 insertions(+), 0 deletions(-)
---
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 3349a3f..0ab42f1 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -10,6 +10,7 @@ AM_CPPFLAGS =                                         \
        $(SOUP_CFLAGS)                                  \
        $(SQLITE_CFLAGS)                                \
        $(FWUPD_CFLAGS)                                 \
+       $(JSON_GLIB_CFLAGS)                             \
        $(LIMBA_CFLAGS)                                 \
        $(XDG_APP_CFLAGS)                               \
        -DBINDIR=\"$(bindir)\"                          \
@@ -23,6 +24,14 @@ AM_CPPFLAGS =                                                \
        -DTESTDATADIR=\""$(top_srcdir)/data/tests"\"    \
        -I$(top_srcdir)/src
 
+noinst_PROGRAMS = xdg-app-reviews
+xdg_app_reviews_SOURCES = gs-plugin-xdg-app-reviews.c
+xdg_app_reviews_LDADD = $(GLIB_LIBS) $(JSON_GLIB_LIBS) $(SOUP_LIBS)
+xdg_app_reviews_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+
+gnome_software_cmd_CFLAGS =                            \
+       $(WARN_CFLAGS)
+
 noinst_LTLIBRARIES =                                   \
        libgs_plugin_self_test.la
 
@@ -126,6 +135,11 @@ libgs_plugin_xdg_app_la_LDFLAGS = -module -avoid-version
 libgs_plugin_xdg_app_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 endif
 
+#libgs_plugin_xdg_app_reviews_la_SOURCES = gs-plugin-xdg-app-reviews.c
+#libgs_plugin_xdg_app_reviews_la_LIBADD = $(GS_PLUGIN_LIBS) $(JSON_GLIB_LIBS)
+#libgs_plugin_xdg_app_reviews_la_LDFLAGS = -module -avoid-version
+#libgs_plugin_xdg_app_reviews_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+
 libgs_plugin_moduleset_la_SOURCES =                    \
        gs-moduleset.c                                  \
        gs-moduleset.h                                  \
diff --git a/src/plugins/gs-plugin-xdg-app-reviews.c b/src/plugins/gs-plugin-xdg-app-reviews.c
new file mode 100644
index 0000000..5439852
--- /dev/null
+++ b/src/plugins/gs-plugin-xdg-app-reviews.c
@@ -0,0 +1,305 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <json-glib/json-glib.h>
+#include <libsoup/soup.h>
+#include <string.h>
+
+#define XDG_APP_SERVER         "http://apps-xdgapp.rhcloud.com/1.0/reviews";
+//#define XDG_APP_SERVER               "http://localhost:5000/1.0/reviews";
+
+#ifndef JsonParser_autoptr
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(JsonParser, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(JsonBuilder, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(JsonNode, json_node_free)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(JsonGenerator, g_object_unref)
+#endif
+
+#define GS_PLUGIN_ERROR 1
+#define GS_PLUGIN_ERROR_FAILED 0
+
+/**
+ * gs_plugin_xdg_app_reviews_parse_results:
+ */
+static gboolean
+gs_plugin_xdg_app_reviews_parse_results (const gchar *data,
+                                        gsize data_len,
+                                        GError **error)
+{
+       JsonArray *json_reviews;
+       JsonNode *json_root;
+       guint i;
+       g_autoptr(JsonParser) json_parser = NULL;
+
+       /* parse the data and find the array or ratings */
+       json_parser = json_parser_new ();
+       if (!json_parser_load_from_data (json_parser, data, data_len, error))
+               return FALSE;
+       json_root = json_parser_get_root (json_parser);
+       if (json_root == NULL) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no root");
+               return FALSE;
+       }
+       if (json_node_get_node_type (json_root) != JSON_NODE_ARRAY) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no array");
+               return FALSE;
+       }
+
+       /* parse each rating */
+       json_reviews = json_node_get_array (json_root);
+       for (i = 0; i < json_array_get_length (json_reviews); i++) {
+               JsonNode *json_review;
+               JsonObject *json_item;
+
+               /* extract the data */
+               json_review = json_array_get_element (json_reviews, i);
+               if (json_node_get_node_type (json_review) != JSON_NODE_OBJECT) {
+                       g_set_error_literal (error,
+                                            GS_PLUGIN_ERROR,
+                                            GS_PLUGIN_ERROR_FAILED,
+                                            "no object type");
+                       return FALSE;
+               }
+               json_item = json_node_get_object (json_review);
+               if (json_item == NULL) {
+                       g_set_error_literal (error,
+                                            GS_PLUGIN_ERROR,
+                                            GS_PLUGIN_ERROR_FAILED,
+                                            "no object");
+                       return FALSE;
+               }
+
+               g_warning ("appid=%s, karma=%" G_GINT64_FORMAT,
+                          json_object_get_string_member (json_item, "appid"),
+                          json_object_get_int_member (json_item, "karma"));
+       }
+       return TRUE;
+}
+
+/**
+ * gs_plugin_xdg_app_reviews_parse_success:
+ */
+static gboolean
+gs_plugin_xdg_app_reviews_parse_success (const gchar *data,
+                                        gsize data_len,
+                                        GError **error)
+{
+       JsonNode *json_root;
+       JsonObject *json_item;
+       const gchar *msg = NULL;
+       g_autoptr(JsonParser) json_parser = NULL;
+
+       /* parse the data and find the success */
+       json_parser = json_parser_new ();
+       if (!json_parser_load_from_data (json_parser, data, data_len, error))
+               return FALSE;
+       json_root = json_parser_get_root (json_parser);
+       if (json_root == NULL) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no error root");
+               return FALSE;
+       }
+       if (json_node_get_node_type (json_root) != JSON_NODE_OBJECT) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no error object");
+               return FALSE;
+       }
+       json_item = json_node_get_object (json_root);
+       if (json_item == NULL) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no error object");
+               return FALSE;
+       }
+
+       /* failed? */
+       if (json_object_has_member (json_item, "msg"))
+               msg = json_object_get_string_member (json_item, "msg");
+       if (!json_object_get_boolean_member (json_item, "success")) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    msg != NULL ? msg : "unknown failure");
+               return FALSE;
+       }
+
+       /* just for the console */
+       if (msg != NULL)
+               g_debug ("success: %s", msg);
+       return TRUE;
+}
+
+/**
+ * get_reviews_for_appid:
+ */
+static gboolean
+get_reviews_for_appid (SoupSession *session, const gchar *appid, GError **error)
+{
+       guint status_code;
+       g_autofree gchar *uri = NULL;
+       g_autoptr(SoupMessage) msg = NULL;
+
+       /* create the GET data */
+       uri = g_strdup_printf ("%s/app/%s", XDG_APP_SERVER, appid);
+       msg = soup_message_new (SOUP_METHOD_GET, uri);
+       status_code = soup_session_send_message (session, msg);
+       if (status_code != SOUP_STATUS_OK) {
+               return gs_plugin_xdg_app_reviews_parse_success (msg->response_body->data,
+                                                               msg->response_body->length,
+                                                               error);
+       }
+
+       if (!gs_plugin_xdg_app_reviews_parse_results (msg->response_body->data,
+                                                     msg->response_body->length,
+                                                     error)) {
+               return FALSE;
+       }
+
+       g_warning ("GOT: %s", msg->response_body->data);
+       return TRUE;
+}
+
+/**
+ * gs_plugin_get_machine_hash:
+ */
+static gchar *
+gs_plugin_get_machine_hash (GError **error)
+{
+       g_autofree gchar *data = NULL;
+       g_autofree gchar *salted = NULL;
+
+       if (!g_file_get_contents ("/etc/machine-id", &data, NULL, error))
+               return NULL;
+
+       salted = g_strdup_printf ("gnome-software[%s]", data);
+       return g_compute_checksum_for_string (G_CHECKSUM_SHA1, salted, -1);
+}
+
+/**
+ * gs_plugin_xdg_app_reviews_build_review:
+ */
+static gchar *
+gs_plugin_xdg_app_reviews_build_review (GError **error)
+{
+       g_autofree gchar *machine_hash = NULL;
+       g_autoptr(JsonBuilder) json_builder = NULL;
+       g_autoptr(JsonGenerator) json_generator = NULL;
+       g_autoptr(JsonNode) json_root = NULL;
+
+       json_builder = json_builder_new ();
+
+       /* create object with review data */
+       machine_hash = gs_plugin_get_machine_hash (error);
+       if (machine_hash == NULL)
+               return NULL;
+
+       json_builder_begin_object (json_builder);
+       json_builder_set_member_name (json_builder, "user_id");
+       json_builder_add_string_value (json_builder, machine_hash);
+       json_builder_set_member_name (json_builder, "appid");
+       json_builder_add_string_value (json_builder, "org.gnome.Software.desktop");
+       json_builder_set_member_name (json_builder, "locale");
+       json_builder_add_string_value (json_builder, "en_GB");
+       json_builder_set_member_name (json_builder, "distro");
+       json_builder_add_string_value (json_builder, "fedora");
+       json_builder_set_member_name (json_builder, "version");
+       json_builder_add_string_value (json_builder, "3.19.4");
+       json_builder_set_member_name (json_builder, "summary");
+       json_builder_add_string_value (json_builder, "Simply Awesome!");
+       json_builder_set_member_name (json_builder, "description");
+       json_builder_add_string_value (json_builder, "It is really easy to install and remove applications 
with this program");
+       json_builder_end_object (json_builder);
+
+       /* export as a string */
+       json_root = json_builder_get_root (json_builder);
+       json_generator = json_generator_new ();
+       json_generator_set_pretty (json_generator, TRUE);
+       json_generator_set_root (json_generator, json_root);
+       return json_generator_to_data (json_generator, NULL);
+}
+
+/**
+ * add_review:
+ */
+static gboolean
+add_review (SoupSession *session, GError **error)
+{
+       guint status_code;
+       g_autofree gchar *data = NULL;
+       g_autofree gchar *uri = NULL;
+       g_autoptr(SoupMessage) msg = NULL;
+
+       /* create the GET data */
+       uri = g_strdup_printf ("%s/app", XDG_APP_SERVER);
+       msg = soup_message_new (SOUP_METHOD_POST, uri);
+       data = gs_plugin_xdg_app_reviews_build_review (error);
+       if (data == NULL)
+               return FALSE;
+g_warning ("SENDING: %s", data);
+       soup_message_set_request (msg, "application/json",
+                                 SOUP_MEMORY_COPY, data, strlen (data));
+
+       /* set sync request */
+       status_code = soup_session_send_message (session, msg);
+       if (status_code != SOUP_STATUS_OK) {
+               g_warning ("Failed to set rating on xdg-app-review: %s",
+                          soup_status_get_phrase (status_code));
+       }
+
+       /* process returned JSON */
+g_warning ("RECIEVED: %s", msg->response_body->data);
+       return gs_plugin_xdg_app_reviews_parse_success (msg->response_body->data,
+                                                       msg->response_body->length,
+                                                       error);
+}
+
+int
+main (void)
+{
+       SoupSession *session;
+       const gchar *appid = "org.gnome.Software.desktop";
+       g_autoptr(GError) error = NULL;
+
+       session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, "FIXME", NULL);
+
+       /* get existing ratings */
+       if (!get_reviews_for_appid (session, appid, &error))
+               g_error ("failed to get reviews: %s", error->message);
+
+       /* add new review */
+       if (!add_review (session, &error))
+               g_error ("failed to add review: %s", error->message);
+
+       g_object_unref (session);
+
+       return 0;
+}


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