[gnome-software/wip/temp/ubuntu-xenial-rebased-corrected: 331/331] Resolve conflicts from rebase



commit 9651f292157eafc1f366420bd339821bb02d23b7
Author: William Hua <william hua canonical com>
Date:   Wed May 4 09:55:05 2016 -0400

    Resolve conflicts from rebase

 src/gs-plugin-loader.c                     |   12 -
 src/gs-plugin-loader.h                     |    3 +-
 src/gs-review-row.ui                       |   17 +-
 src/gs-self-test.c                         |    4 +
 src/gs-shell-details.c                     |   29 +-
 src/plugins/Makefile.am                    |   30 +-
 src/plugins/gs-plugin-appstream.c          |    6 +-
 src/plugins/gs-plugin-fwupd.c              |    5 +-
 src/plugins/gs-plugin-packagekit-refine.c  |    2 +-
 src/plugins/gs-plugin-packagekit-refresh.c |    2 +-
 src/plugins/gs-plugin-packagekit.c         |  133 ++----
 src/plugins/gs-plugin-provenance.c         |    1 +
 src/plugins/gs-plugin-systemd-updates.c    |    6 +-
 src/plugins/gs-plugin-ubuntu-reviews.c     |  699 +++++++++++++---------------
 14 files changed, 412 insertions(+), 537 deletions(-)
---
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index fe73929..db1e91f 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -50,8 +50,6 @@ typedef struct
 
        guint                    updates_changed_id;
        gboolean                 online; 
-
-       gboolean                 supports_reviews;
 } GsPluginLoaderPrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (GsPluginLoader, gs_plugin_loader, G_TYPE_OBJECT)
@@ -2674,9 +2672,6 @@ gs_plugin_loader_app_action_async (GsPluginLoader *plugin_loader,
        case GS_PLUGIN_LOADER_ACTION_UPDATE_CANCEL:
                state->function_name = "gs_plugin_update_cancel";
                break;
-       case GS_PLUGIN_LOADER_ACTION_SET_REVIEW:
-               state->function_name = "gs_plugin_app_set_review";
-               break;
        default:
                g_assert_not_reached ();
                break;
@@ -2924,7 +2919,6 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
        GsPluginGetDepsFunc order_before = NULL;
        GsPluginGetDepsFunc plugin_conflicts = NULL;
        GsPlugin *plugin = NULL;
-       gpointer set_review;
 
        module = g_module_open (filename, 0);
        if (module == NULL) {
@@ -2954,12 +2948,6 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
                         "gs_plugin_get_conflicts",
                         (gpointer *) &plugin_conflicts);
 
-       /* Check if this plugin can do reviews */
-       if (g_module_symbol (module,
-                            "gs_plugin_app_set_review",
-                            &set_review))
-               priv->supports_reviews = TRUE;
-
        /* print what we know */
        plugin = g_slice_new0 (GsPlugin);
        plugin->enabled = TRUE;
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 3905f1b..0c98485 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -60,8 +60,7 @@ typedef enum {
        GS_PLUGIN_LOADER_ACTION_UPGRADE_DOWNLOAD,
        GS_PLUGIN_LOADER_ACTION_UPGRADE_TRIGGER,
        GS_PLUGIN_LOADER_ACTION_LAUNCH,
-       GS_PLUGIN_LOADER_ACTION_OFFLINE_UPDATE_CANCEL,
-       GS_PLUGIN_LOADER_ACTION_SET_REVIEW,
+       GS_PLUGIN_LOADER_ACTION_UPDATE_CANCEL,
        GS_PLUGIN_LOADER_ACTION_LAST
 } GsPluginLoaderAction;
 
diff --git a/src/gs-review-row.ui b/src/gs-review-row.ui
index c74e0d8..feaae1e 100644
--- a/src/gs-review-row.ui
+++ b/src/gs-review-row.ui
@@ -50,7 +50,7 @@
           </packing>
         </child>
         <child>
-          <object class="GtkLabel" id="date_label">
+          <object class="GtkLabel" id="author_label">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="halign">start</property>
@@ -67,21 +67,6 @@
           </packing>
         </child>
         <child>
-          <object class="GtkLabel" id="author_label">
-            <property name="visible">True</property>
-            <property name="halign">start</property>
-            <style>
-              <class name="dim-label"/>
-            </style>
-          </object>
-          <packing>
-            <property name="left-attach">0</property>
-            <property name="top-attach">1</property>
-            <property name="width">3</property>
-            <property name="height">1</property>
-          </packing>
-        </child>
-        <child>
           <object class="GtkLabel" id="text_label">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index 8aa5ce7..1bfc56e 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -464,6 +464,7 @@ main (int argc, char **argv)
        g_autoptr(GsPluginLoader) plugin_loader = NULL;
        const gchar *whitelist[] = {
                "appstream",
+               "dpkg",
                "dummy",
                "epiphany",
                "hardcoded-blacklist",
@@ -578,6 +579,9 @@ main (int argc, char **argv)
        g_test_add_data_func ("/gnome-software/plugin-loader{distro-upgrades}",
                              plugin_loader,
                              (GTestDataFunc) gs_plugin_loader_distro_upgrades_func);
+       g_test_add_data_func ("/gnome-software/plugin-loader{dpkg}",
+                             plugin_loader,
+                             (GTestDataFunc) gs_plugin_loader_dpkg_func);
        return g_test_run ();
 }
 
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index e2ac370..35609b7 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -176,7 +176,7 @@ gs_shell_details_switch_to (GsPage *page, gboolean scroll_up)
        widget = GTK_WIDGET (gtk_builder_get_object (self->builder, "application_details_header"));
        gtk_widget_show (widget);
 
-       /* not set, perhaps filename-to-app */
+       /* not set, perhaps file-to-app */
        if (self->app == NULL)
                return;
 
@@ -259,8 +259,7 @@ gs_shell_details_switch_to (GsPage *page, gboolean scroll_up)
        case AS_APP_STATE_INSTALLED:
        case AS_APP_STATE_UPDATABLE:
        case AS_APP_STATE_UPDATABLE_LIVE:
-               if (gs_app_get_kind (self->app) == AS_APP_KIND_DESKTOP ||
-                   gs_app_get_kind (self->app) == AS_APP_KIND_WEB_APP) {
+               if (!gs_app_has_quirk (self->app, AS_APP_QUIRK_NOT_LAUNCHABLE)) {
                        gtk_widget_set_visible (self->button_details_launch, TRUE);
                } else {
                        gtk_widget_set_visible (self->button_details_launch, FALSE);
@@ -833,9 +832,10 @@ gs_shell_details_refresh_all (GsShellDetails *self)
 
        /* hide the kudo details for non-desktop software */
        switch (gs_app_get_kind (self->app)) {
-       case AS_APP_KIND_DESKTOP:
+       // Hidden on Ubuntu since don't have appropriate information
+       /*case AS_APP_KIND_DESKTOP:
                gtk_widget_set_visible (self->grid_details_kudo, TRUE);
-               break;
+               break;*/
        default:
                gtk_widget_set_visible (self->grid_details_kudo, FALSE);
                break;
@@ -849,7 +849,8 @@ gs_shell_details_refresh_all (GsShellDetails *self)
                break;
        default:
                gtk_widget_set_sensitive (self->button_history, history->len > 0);
-               gtk_widget_set_visible (self->button_history, TRUE);
+               // Disabled on Ubuntu as we don't have history support
+               gtk_widget_set_visible (self->button_history, FALSE);//TRUE);
                break;
        }
 
@@ -1178,12 +1179,12 @@ gs_shell_details_failed_response_cb (GtkDialog *dialog,
 }
 
 /**
- * gs_shell_details_filename_to_app_cb:
+ * gs_shell_details_filen_to_app_cb:
  **/
 static void
-gs_shell_details_filename_to_app_cb (GObject *source,
-                                    GAsyncResult *res,
-                                    gpointer user_data)
+gs_shell_details_file_to_app_cb (GObject *source,
+                                GAsyncResult *res,
+                                gpointer user_data)
 {
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
        GsShellDetails *self = GS_SHELL_DETAILS (user_data);
@@ -1197,9 +1198,9 @@ gs_shell_details_filename_to_app_cb (GObject *source,
        }
        /* save app */
        g_set_object (&self->app,
-                     gs_plugin_loader_file_to_app_finish(plugin_loader,
-                                                         res,
-                                                         &error));
+                     gs_plugin_loader_file_to_app_finish (plugin_loader,
+                                                          res,
+                                                          &error));
        if (self->app == NULL) {
                GtkWidget *dialog;
 
@@ -1262,7 +1263,7 @@ gs_shell_details_set_filename (GsShellDetails *self, const gchar *filename)
                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEW_RATINGS |
                                            GS_PLUGIN_REFINE_FLAGS_REQUIRE_REVIEWS,
                                            self->cancellable,
-                                           gs_shell_details_filename_to_app_cb,
+                                           gs_shell_details_file_to_app_cb,
                                            self);
 }
 
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 61d37a4..389ce16 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -202,13 +202,6 @@ libgs_plugin_hardcoded_blacklist_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 
 if HAVE_UBUNTU_REVIEWS
 libgs_plugin_ubuntu_reviews_la_SOURCES =               \
-       gs-plugin-ubuntu-reviews.c
-libgs_plugin_ubuntu_reviews_la_LIBADD = $(GS_PLUGIN_LIBS) $(SOUP_LIBS) $(JSON_GLIB_LIBS) $(SQLITE_LIBS)
-libgs_plugin_ubuntu_reviews_la_LDFLAGS = -module -avoid-version
-libgs_plugin_ubuntu_reviews_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
-endif
-
-libgs_plugin_ubuntu_reviews_la_SOURCES =               \
        gs-plugin-ubuntu-reviews.c                      \
        gs-ubuntuone.h                                  \
        gs-ubuntuone.c                                  \
@@ -225,6 +218,7 @@ libgs_plugin_ubuntu_reviews_la_LIBADD =                     \
        $(LIBSECRET_LIBS)
 libgs_plugin_ubuntu_reviews_la_LDFLAGS = -module -avoid-version
 libgs_plugin_ubuntu_reviews_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+endif
 
 libgs_plugin_packagekit_la_SOURCES =                   \
        gs-plugin-packagekit.c                          \
@@ -292,18 +286,18 @@ libgs_plugin_packagekit_proxy_la_LIBADD = $(GS_PLUGIN_LIBS)
 libgs_plugin_packagekit_proxy_la_LDFLAGS = -module -avoid-version
 libgs_plugin_packagekit_proxy_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 
-libgs_plugin_snappy_la_SOURCES =                       \
-       gs-plugin-snappy.c                              \
-       gs-ubuntuone.h                                  \
-       gs-ubuntuone.c                                  \
-       gs-ubuntuone-dialog.h                           \
-       gs-ubuntuone-dialog.c                           \
-       gs-ubuntu-snapd.h                               \
+libgs_plugin_snappy_la_SOURCES =                               \
+       gs-plugin-snappy.c                                      \
+       gs-ubuntuone.h                                          \
+       gs-ubuntuone.c                                          \
+       gs-ubuntuone-dialog.h                                   \
+       gs-ubuntuone-dialog.c                                   \
+       gs-ubuntu-snapd.h                                       \
        gs-ubuntu-snapd.c
-libgs_plugin_snappy_la_LIBADD =                                \
-       $(GS_PLUGIN_LIBS)                               \
-       $(SOUP_LIBS)                                    \
-       $(JSON_GLIB_LIBS)                               \
+libgs_plugin_snappy_la_LIBADD =                                        \
+       $(GS_PLUGIN_LIBS)                                       \
+       $(SOUP_LIBS)                                            \
+       $(JSON_GLIB_LIBS)                                       \
        $(LIBSECRET_LIBS)
 libgs_plugin_snappy_la_LDFLAGS = -module -avoid-version
 libgs_plugin_snappy_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index f7b0b8b..cd340b0 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -75,8 +75,10 @@ gs_plugin_refresh (GsPlugin              *plugin,
                   GError               **error)
 {
        if (flags & GS_PLUGIN_REFRESH_FLAGS_UI) {
-               gs_plugin_setup (plugin, cancellable, error);
-               gs_plugin_updates_changed (plugin);
+               if (gs_plugin_setup (plugin, cancellable, error))
+                       gs_plugin_updates_changed (plugin);
+               else
+                       return FALSE;
        }
 
        return TRUE;
diff --git a/src/plugins/gs-plugin-fwupd.c b/src/plugins/gs-plugin-fwupd.c
index 52c7fbc..1ae4e3e 100644
--- a/src/plugins/gs-plugin-fwupd.c
+++ b/src/plugins/gs-plugin-fwupd.c
@@ -919,6 +919,8 @@ gs_plugin_fwupd_install (GsPlugin *plugin,
        if (g_strcmp0 (gs_app_get_management_plugin (app), plugin->name) != 0)
                return TRUE;
 
+       filename = g_file_get_path (gs_app_get_local_file (app));
+
        /* not set */
        if (gs_app_get_local_file (app) == NULL) {
                g_set_error (error,
@@ -928,7 +930,6 @@ gs_plugin_fwupd_install (GsPlugin *plugin,
                             filename);
                return FALSE;
        }
-       filename = g_file_get_path (gs_app_get_local_file (app));
 
        /* limit to single device? */
        device_id = gs_app_get_metadata_item (app, "fwupd::DeviceID");
@@ -1034,9 +1035,9 @@ gs_plugin_file_to_app (GsPlugin *plugin,
        GVariant *val;
        GVariant *variant;
        const gchar *key;
+       g_autofree gchar *content_type = NULL;
        gint fd;
        gint retval;
-       g_autofree gchar *content_type = NULL;
        g_autoptr(AsIcon) icon = NULL;
        g_autoptr(GDBusConnection) conn = NULL;
        g_autoptr(GDBusMessage) message = NULL;
diff --git a/src/plugins/gs-plugin-packagekit-refine.c b/src/plugins/gs-plugin-packagekit-refine.c
index e85916a..c12e7d4 100644
--- a/src/plugins/gs-plugin-packagekit-refine.c
+++ b/src/plugins/gs-plugin-packagekit-refine.c
@@ -302,7 +302,7 @@ gs_plugin_packagekit_resolve_packages (GsPlugin *plugin,
        packages = pk_results_get_package_array (results);
        for (l = list; l != NULL; l = l->next) {
                app = GS_APP (l->data);
-               if (gs_app_get_metadata_item (app, "packagekit::local-filename") != NULL)
+               if (gs_app_get_local_file (app) != NULL)
                        continue;
                gs_plugin_packagekit_resolve_packages_app (plugin, packages, app);
        }
diff --git a/src/plugins/gs-plugin-packagekit-refresh.c b/src/plugins/gs-plugin-packagekit-refresh.c
index aad76d8..f5b2f53 100644
--- a/src/plugins/gs-plugin-packagekit-refresh.c
+++ b/src/plugins/gs-plugin-packagekit-refresh.c
@@ -367,7 +367,7 @@ gs_plugin_file_to_app (GsPlugin *plugin,
        else
                gs_app_set_name (app, GS_APP_QUALITY_LOWEST, split[PK_PACKAGE_ID_NAME]);
        gs_app_set_version (app, split[PK_PACKAGE_ID_VERSION]);
-       gs_app_set_metadata (app, "packagekit::local-filename", filename);
+       gs_app_set_local_file (app, file);
        gs_app_set_origin (app, basename);
        gs_app_add_source (app, split[PK_PACKAGE_ID_NAME]);
        gs_app_add_source_id (app, package_id);
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index 2ce848d..e2fd6a1 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  *
- * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013-2016 Richard Hughes <richard hughsie com>
  *
  * Licensed under the GNU General Public License Version 2
  *
@@ -152,7 +152,7 @@ gs_plugin_add_installed (GsPlugin *plugin,
                                          cancellable,
                                          gs_plugin_packagekit_progress_cb, &data,
                                          error);
-       if (results == NULL)
+       if (!gs_plugin_packagekit_results_valid (results, error))
                return FALSE;
 
        /* add results */
@@ -168,7 +168,6 @@ gs_plugin_add_sources_related (GsPlugin *plugin,
                               GCancellable *cancellable,
                               GError **error)
 {
-       GList *installed = NULL;
        GList *l;
        GsApp *app;
        GsApp *app_tmp;
@@ -176,6 +175,7 @@ gs_plugin_add_sources_related (GsPlugin *plugin,
        ProgressData data;
        const gchar *id;
        gboolean ret = TRUE;
+       g_autoptr(GsAppList) installed = NULL;
        g_autoptr(PkResults) results = NULL;
        g_autoptr(AsProfileTask) ptask = NULL;
 
@@ -194,16 +194,14 @@ gs_plugin_add_sources_related (GsPlugin *plugin,
                                           cancellable,
                                           gs_plugin_packagekit_progress_cb, &data,
                                           error);
-       if (results == NULL) {
-               ret = FALSE;
-               goto out;
-       }
+       if (!gs_plugin_packagekit_results_valid (results, error))
+               return FALSE;
        ret = gs_plugin_packagekit_add_results (plugin,
                                                &installed,
                                                results,
                                                error);
        if (!ret)
-               goto out;
+               return FALSE;
        for (l = installed; l != NULL; l = l->next) {
                g_auto(GStrv) split = NULL;
                app = GS_APP (l->data);
@@ -218,9 +216,7 @@ gs_plugin_add_sources_related (GsPlugin *plugin,
                        }
                }
        }
-out:
-       gs_plugin_list_free (installed);
-       return ret;
+       return TRUE;
 }
 
 /**
@@ -255,7 +251,7 @@ gs_plugin_add_sources (GsPlugin *plugin,
                                           cancellable,
                                           gs_plugin_packagekit_progress_cb, &data,
                                           error);
-       if (results == NULL)
+       if (!gs_plugin_packagekit_results_valid (results, error))
                return FALSE;
        hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
        array = pk_results_get_repo_detail_array (results);
@@ -264,7 +260,7 @@ gs_plugin_add_sources (GsPlugin *plugin,
                rd = g_ptr_array_index (array, i);
                id = pk_repo_detail_get_id (rd);
                app = gs_app_new (id);
-               gs_app_set_management_plugin (app, "PackageKit");
+               gs_app_set_management_plugin (app, plugin->name);
                gs_app_set_kind (app, AS_APP_KIND_SOURCE);
                gs_app_set_state (app, AS_APP_STATE_INSTALLED);
                gs_app_set_name (app,
@@ -308,7 +304,9 @@ gs_plugin_app_source_enable (GsPlugin *plugin,
                                         cancellable,
                                         gs_plugin_packagekit_progress_cb, &data,
                                         error);
-       return results != NULL;
+       if (!gs_plugin_packagekit_results_valid (results, error))
+               return FALSE;
+       return TRUE;
 }
 
 /**
@@ -325,7 +323,6 @@ gs_plugin_app_install (GsPlugin *plugin,
        ProgressData data;
        const gchar *package_id;
        guint i, j;
-       g_autoptr(PkError) error_code = NULL;
        g_autofree gchar *local_filename = NULL;
        g_auto(GStrv) package_ids = NULL;
        g_autoptr(GPtrArray) array_package_ids = NULL;
@@ -336,7 +333,7 @@ gs_plugin_app_install (GsPlugin *plugin,
        data.ptask = NULL;
 
        /* only process this app if was created by this plugin */
-       if (g_strcmp0 (gs_app_get_management_plugin (app), "PackageKit") != 0)
+       if (g_strcmp0 (gs_app_get_management_plugin (app), plugin->name) != 0)
                return TRUE;
 
        /* we enable the repo */
@@ -365,13 +362,16 @@ gs_plugin_app_install (GsPlugin *plugin,
                                                         gs_plugin_packagekit_progress_cb, &data,
                                                         error);
                if (results == NULL) {
-                       gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+                       gs_plugin_packagekit_convert_gerror (error);
+                       gs_app_set_state_recover (app);
                        return FALSE;
                }
 
+               /* state is known */
+               gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+
                /* no longer valid */
                gs_app_clear_source_ids (app);
-               gs_app_set_state (app, AS_APP_STATE_INSTALLED);
                return TRUE;
        }
 
@@ -431,8 +431,15 @@ gs_plugin_app_install (GsPlugin *plugin,
                                                         cancellable,
                                                         gs_plugin_packagekit_progress_cb, &data,
                                                         error);
-               if (results == NULL)
+               if (results == NULL) {
+                       gs_plugin_packagekit_convert_gerror (error);
+                       gs_app_set_state_recover (app);
                        return FALSE;
+               }
+
+               /* state is known */
+               gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+
                break;
        case AS_APP_STATE_AVAILABLE_LOCAL:
                if (gs_app_get_local_file (app) == NULL) {
@@ -450,8 +457,14 @@ gs_plugin_app_install (GsPlugin *plugin,
                                                      cancellable,
                                                      gs_plugin_packagekit_progress_cb, &data,
                                                      error);
-               if (results == NULL)
+               if (results == NULL) {
+                       gs_plugin_packagekit_convert_gerror (error);
+                       gs_app_set_state_recover (app);
                        return FALSE;
+               }
+
+               /* state is known */
+               gs_app_set_state (app, AS_APP_STATE_INSTALLED);
 
                /* get the new icon from the package */
                gs_app_set_local_file (app, NULL);
@@ -470,17 +483,6 @@ gs_plugin_app_install (GsPlugin *plugin,
        /* no longer valid */
        gs_app_clear_source_ids (app);
 
-       /* check error code */
-       error_code = pk_results_get_error_code (results);
-       if (error_code != NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "failed to install package: %s, %s",
-                            pk_error_enum_to_string (pk_error_get_code (error_code)),
-                            pk_error_get_details (error_code));
-               return FALSE;
-       }
        return TRUE;
 }
 
@@ -508,7 +510,9 @@ gs_plugin_app_source_disable (GsPlugin *plugin,
                                         cancellable,
                                         gs_plugin_packagekit_progress_cb, &data,
                                         error);
-       return results != NULL;
+       if (!gs_plugin_packagekit_results_valid (results, error))
+               return FALSE;
+       return TRUE;
 }
 
 /**
@@ -561,7 +565,6 @@ gs_plugin_app_remove (GsPlugin *plugin,
        ProgressData data;
        guint i;
        guint cnt = 0;
-       g_autoptr(PkError) error_code = NULL;
        g_autoptr(PkResults) results = NULL;
        g_auto(GStrv) package_ids = NULL;
 
@@ -570,7 +573,7 @@ gs_plugin_app_remove (GsPlugin *plugin,
        data.ptask = NULL;
 
        /* only process this app if was created by this plugin */
-       if (g_strcmp0 (gs_app_get_management_plugin (app), "PackageKit") != 0)
+       if (g_strcmp0 (gs_app_get_management_plugin (app), plugin->name) != 0)
                return TRUE;
 
        /* remove repo and all apps in it */
@@ -611,65 +614,21 @@ gs_plugin_app_remove (GsPlugin *plugin,
                                                cancellable,
                                                gs_plugin_packagekit_progress_cb, &data,
                                                error);
-       if (results == NULL)
+       if (!gs_plugin_packagekit_results_valid (results, error)) {
+               gs_app_set_state_recover (app);
                return FALSE;
+       }
+
+       /* state is not known: we don't know if we can re-install this app */
+       gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
 
        /* no longer valid */
        gs_app_clear_source_ids (app);
 
-       /* check error code */
-       error_code = pk_results_get_error_code (results);
-       if (error_code != NULL) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "failed to remove package: %s, %s",
-                            pk_error_enum_to_string (pk_error_get_code (error_code)),
-                            pk_error_get_details (error_code));
-               return FALSE;
-       }
        return TRUE;
 }
 
 /**
- * gs_plugin_app_upgrade_download:
- */
-gboolean
-gs_plugin_app_upgrade_download (GsPlugin *plugin,
-                               GsApp *app,
-                               GCancellable *cancellable,
-                               GError **error)
-{
-       ProgressData data;
-       g_autoptr(PkResults) results = NULL;
-
-       data.app = app;
-       data.plugin = plugin;
-       data.ptask = NULL;
-
-       /* check is distro-upgrade */
-       if (gs_app_get_kind (app) != AS_APP_KIND_OS_UPGRADE) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "app %s is not a distro upgrade",
-                            gs_app_get_id (app));
-               return FALSE;
-       }
-
-       /* ask PK to download enough packages to upgrade the system */
-       gs_app_set_state (app, AS_APP_STATE_INSTALLING);
-       results = pk_client_upgrade_system (PK_CLIENT (plugin->priv->task),
-                                           pk_bitfield_from_enums (PK_TRANSACTION_FLAG_ENUM_ONLY_DOWNLOAD, 
-1),
-                                           gs_app_get_version (app),
-                                           PK_UPGRADE_KIND_ENUM_COMPLETE,
-                                           cancellable,
-                                           gs_plugin_packagekit_progress_cb, &data,
-                                           error);
-       return results != NULL;
-}
-
-/**
  * gs_plugin_add_search_files:
  */
 gboolean
@@ -698,7 +657,7 @@ gs_plugin_add_search_files (GsPlugin *plugin,
                                          cancellable,
                                          gs_plugin_packagekit_progress_cb, &data,
                                          error);
-       if (results == NULL)
+       if (!gs_plugin_packagekit_results_valid (results, error))
                return FALSE;
 
        /* add results */
@@ -734,7 +693,7 @@ gs_plugin_add_search_what_provides (GsPlugin *plugin,
                                           cancellable,
                                           gs_plugin_packagekit_progress_cb, &data,
                                           error);
-       if (results == NULL)
+       if (!gs_plugin_packagekit_results_valid (results, error))
                return FALSE;
 
        /* add results */
@@ -751,7 +710,7 @@ gs_plugin_launch (GsPlugin *plugin,
                  GError **error)
 {
        /* only process this app if was created by this plugin */
-       if (g_strcmp0 (gs_app_get_management_plugin (app), "PackageKit") != 0)
+       if (g_strcmp0 (gs_app_get_management_plugin (app), plugin->name) != 0)
                return TRUE;
        return gs_plugin_app_launch (plugin, app, error);
 }
diff --git a/src/plugins/gs-plugin-provenance.c b/src/plugins/gs-plugin-provenance.c
index fd84567..a692345 100644
--- a/src/plugins/gs-plugin-provenance.c
+++ b/src/plugins/gs-plugin-provenance.c
@@ -161,6 +161,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
        g_debug ("prov: considering %s", gs_app_get_id (app));
        if (origin != NULL && gs_utils_strv_fnmatch (sources, origin)) {
                gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE);
+               g_debug ("prov: %s", gs_app_to_string (app));
                return TRUE;
        }
 
diff --git a/src/plugins/gs-plugin-systemd-updates.c b/src/plugins/gs-plugin-systemd-updates.c
index eb1b4ec..cf2a39e 100644
--- a/src/plugins/gs-plugin-systemd-updates.c
+++ b/src/plugins/gs-plugin-systemd-updates.c
@@ -157,8 +157,10 @@ gs_plugin_update (GsPlugin *plugin,
                /* only process this app if was created by this plugin */
                if (g_strcmp0 (gs_app_get_management_plugin (app), "packagekit") != 0)
                        continue;
-               return pk_offline_trigger (PK_OFFLINE_ACTION_REBOOT,
-                                          cancellable, error);
+               if (gs_app_get_state (app) == AS_APP_STATE_UPDATABLE) {
+                       return pk_offline_trigger (PK_OFFLINE_ACTION_REBOOT,
+                                                  cancellable, error);
+               }
        }
        return TRUE;
 }
diff --git a/src/plugins/gs-plugin-ubuntu-reviews.c b/src/plugins/gs-plugin-ubuntu-reviews.c
index 6f2e8e6..2086fe7 100644
--- a/src/plugins/gs-plugin-ubuntu-reviews.c
+++ b/src/plugins/gs-plugin-ubuntu-reviews.c
@@ -31,12 +31,17 @@
 #include <gs-plugin.h>
 #include <gs-utils.h>
 
+#include "gs-ubuntuone.h"
 #include "gs-os-release.h"
 
 struct GsPluginPrivate {
        gchar           *db_path;
        sqlite3         *db;
        gsize            db_loaded;
+       gchar           *consumer_key;
+       gchar           *consumer_secret;
+       gchar           *token_key;
+       gchar           *token_secret;
 };
 
 typedef struct {
@@ -85,6 +90,7 @@ const gchar **
 gs_plugin_order_after (GsPlugin *plugin)
 {
        static const gchar *deps[] = {
+               "odrs",
                "appstream",
                NULL };
        return deps;
@@ -107,6 +113,10 @@ gs_plugin_destroy (GsPlugin *plugin)
 {
        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_free (priv->db_path);
 }
@@ -361,381 +371,6 @@ parse_review_entries (GsPlugin *plugin, JsonParser *parser, GError **error)
        return TRUE;
 }
 
-static gboolean
-send_review_request (GsPlugin *plugin, const gchar *method, const gchar *path, JsonBuilder *request, 
JsonParser **result, GError **error)
-{
-       g_autofree gchar *uri = NULL;
-       g_autoptr(SoupMessage) msg = NULL;
-       guint status_code;
-
-       uri = g_strdup_printf ("%s%s",
-                              UBUNTU_REVIEWS_SERVER, path);
-       msg = soup_message_new (method, uri);
-
-       if (request != NULL) {
-               g_autoptr(JsonGenerator) generator = NULL;
-               gchar *data;
-               gsize length;
-
-               generator = json_generator_new ();
-               json_generator_set_root (generator, json_builder_get_root (request));
-               data = json_generator_to_data (generator, &length);
-               soup_message_set_request (msg, "application/json", SOUP_MEMORY_TAKE, data, length);
-       }
-
-       status_code = soup_session_send_message (plugin->soup_session, msg);
-       if (status_code != SOUP_STATUS_OK) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "Got status code %s from reviews.ubuntu.com",
-                            soup_status_get_phrase (status_code));
-               return FALSE;
-       }
-
-       if (result != NULL) {
-               g_autoptr(JsonParser) parser = NULL;
-               const gchar *content_type;
-
-               content_type = soup_message_headers_get_content_type (msg->response_headers, NULL);
-               if (g_strcmp0 (content_type, "application/json") != 0) {
-                       g_set_error (error,
-                                    GS_PLUGIN_ERROR,
-                                    GS_PLUGIN_ERROR_FAILED,
-                                    "Got unknown content type %s from reviews.ubuntu.com",
-                                    content_type);
-                       return FALSE;
-               }
-
-               parser = json_parser_new ();
-               if (!json_parser_load_from_data (parser, msg->response_body->data, -1, error)) {
-                       return FALSE;
-               }
-               *result = g_steal_pointer (&parser);
-       }
-
-       return TRUE;
-}
-
-static gboolean
-download_review_stats (GsPlugin *plugin, GError **error)
-{
-       g_autofree gchar *uri = NULL;
-       g_autoptr(SoupMessage) msg = NULL;
-       g_autoptr(JsonParser) result = NULL;
-
-       if (!send_review_request (plugin, SOUP_METHOD_GET, "/api/1.0/review-stats/any/any/", NULL, &result, 
error))
-               return FALSE;
-
-       /* Extract the stats from the data */
-       if (!parse_review_entries (plugin, result, error))
-               return FALSE;
-
-       /* Record the time we downloaded it */
-       return set_timestamp (plugin, "stats_mtime", error);
-}
-
-static gboolean
-load_database (GsPlugin *plugin, GError **error)
-{
-       const gchar *statement;
-       gboolean rebuild_ratings = FALSE;
-       char *error_msg = NULL;
-       gint result;
-       gint64 stats_mtime = 0;
-       gint64 now;
-       g_autoptr(GError) error_local = NULL;
-
-       g_debug ("trying to open database '%s'", plugin->priv->db_path);
-       if (!gs_mkdir_parent (plugin->priv->db_path, error))
-               return FALSE;
-       result = sqlite3_open (plugin->priv->db_path, &plugin->priv->db);
-       if (result != SQLITE_OK) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "Can't open Ubuntu review statistics database: %s",
-                            sqlite3_errmsg (plugin->priv->db));
-               return FALSE;
-       }
-
-       /* We don't need to keep doing fsync */
-       sqlite3_exec (plugin->priv->db, "PRAGMA synchronous=OFF",
-                     NULL, NULL, NULL);
-
-       /* Create a table to store the stats */
-       result = sqlite3_exec (plugin->priv->db, "SELECT * FROM review_stats LIMIT 1", NULL, NULL, 
&error_msg);
-       if (result != SQLITE_OK) {
-               g_debug ("creating table to repair: %s", error_msg);
-               sqlite3_free (error_msg);
-               statement = "CREATE TABLE review_stats ("
-                           "package_name TEXT PRIMARY KEY,"
-                           "one_star_count INTEGER DEFAULT 0,"
-                           "two_star_count INTEGER DEFAULT 0,"
-                           "three_star_count INTEGER DEFAULT 0,"
-                           "four_star_count INTEGER DEFAULT 0,"
-                           "five_star_count INTEGER DEFAULT 0);";
-               sqlite3_exec (plugin->priv->db, statement, NULL, NULL, NULL);
-               rebuild_ratings = TRUE;
-       }
-
-       /* Create a table to store local reviews */
-       result = sqlite3_exec (plugin->priv->db, "SELECT * FROM reviews LIMIT 1", NULL, NULL, &error_msg);
-       if (result != SQLITE_OK) {
-               g_debug ("creating table to repair: %s", error_msg);
-               sqlite3_free (error_msg);
-               statement = "CREATE TABLE reviews ("
-                           "package_name TEXT PRIMARY KEY,"
-                           "id TEXT,"
-                           "version TEXT,"
-                           "date TEXT,"
-                           "rating INTEGER,"
-                           "summary TEXT,"
-                           "text TEXT);";
-               sqlite3_exec (plugin->priv->db, statement, NULL, NULL, NULL);
-               rebuild_ratings = TRUE;
-       }
-
-       /* Create a table to store timestamps */
-       result = sqlite3_exec (plugin->priv->db,
-                              "SELECT value FROM timestamps WHERE key = 'stats_mtime' LIMIT 1",
-                              get_timestamp_sqlite_cb, &stats_mtime,
-                              &error_msg);
-       if (result != SQLITE_OK) {
-               g_debug ("creating table to repair: %s", error_msg);
-               sqlite3_free (error_msg);
-               statement = "CREATE TABLE timestamps ("
-                           "key TEXT PRIMARY KEY,"
-                           "value INTEGER DEFAULT 0);";
-               sqlite3_exec (plugin->priv->db, statement, NULL, NULL, NULL);
-
-               /* Set the time of database creation */
-               if (!set_timestamp (plugin, "stats_ctime", error))
-                       return FALSE;
-       }
-
-       /* Download data if we have none or it is out of date */
-       now = g_get_real_time () / G_USEC_PER_SEC;
-       if (stats_mtime == 0 || rebuild_ratings) {
-               g_debug ("No Ubuntu review statistics");
-               if (!download_review_stats (plugin, &error_local)) {
-                       g_warning ("Failed to get Ubuntu review statistics: %s",
-                                  error_local->message);
-                       return TRUE;
-               }
-       } else if (now - stats_mtime > REVIEW_STATS_AGE_MAX) {
-               g_debug ("Ubuntu review statistics was %" G_GINT64_FORMAT
-                        " days old, so regetting",
-                        (now - stats_mtime) / ( 60 * 60 * 24));
-               if (!download_review_stats (plugin, error))
-                       return FALSE;
-       } else {
-               g_debug ("Ubuntu review statistics %" G_GINT64_FORMAT
-                        " days old, so no need to redownload",
-                        (now - stats_mtime) / ( 60 * 60 * 24));
-       }
-       return TRUE;
-}
-
-static gint
-get_timestamp_sqlite_cb (void *data, gint argc,
-                        gchar **argv, gchar **col_name)
-{
-       gint64 *timestamp = (gint64 *) data;
-       *timestamp = g_ascii_strtoll (argv[0], NULL, 10);
-       return 0;
-}
-
-static gboolean
-set_package_stats (GsPlugin *plugin,
-                  const gchar *package_name,
-                  Histogram *histogram,
-                  GError **error)
-{
-       char *error_msg = NULL;
-       gint result;
-       g_autofree gchar *statement = NULL;
-
-       statement = g_strdup_printf ("INSERT OR REPLACE INTO review_stats (package_name, "
-                                    "one_star_count, two_star_count, three_star_count, "
-                                     "four_star_count, five_star_count) "
-                                    "VALUES ('%s', '%" G_GINT64_FORMAT "', '%" G_GINT64_FORMAT"', '%" 
G_GINT64_FORMAT "', '%" G_GINT64_FORMAT "', '%" G_GINT64_FORMAT "');",
-                                    package_name, histogram->one_star_count, histogram->two_star_count,
-                                    histogram->three_star_count, histogram->four_star_count, 
histogram->five_star_count);
-       result = sqlite3_exec (plugin->priv->db, statement, NULL, NULL, &error_msg);
-       if (result != SQLITE_OK) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "SQL error: %s", error_msg);
-               sqlite3_free (error_msg);
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static gboolean
-set_timestamp (GsPlugin *plugin,
-              const gchar *type,
-              GError **error)
-{
-       char *error_msg = NULL;
-       gint result;
-       g_autofree gchar *statement = NULL;
-
-       statement = g_strdup_printf ("INSERT OR REPLACE INTO timestamps (key, value) "
-                                    "VALUES ('%s', '%" G_GINT64_FORMAT "');",
-                                    type,
-                                    g_get_real_time () / G_USEC_PER_SEC);
-       result = sqlite3_exec (plugin->priv->db, statement, NULL, NULL, &error_msg);
-       if (result != SQLITE_OK) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "SQL error: %s", error_msg);
-               sqlite3_free (error_msg);
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static gint
-get_rating_sqlite_cb (void *data,
-                     gint argc,
-                     gchar **argv,
-                     gchar **col_name)
-{
-       Histogram *histogram = (Histogram *) data;
-       histogram->one_star_count = g_ascii_strtoll (argv[0], NULL, 10);
-       histogram->two_star_count = g_ascii_strtoll (argv[1], NULL, 10);
-       histogram->three_star_count = g_ascii_strtoll (argv[2], NULL, 10);
-       histogram->four_star_count = g_ascii_strtoll (argv[3], NULL, 10);
-       histogram->five_star_count = g_ascii_strtoll (argv[4], NULL, 10);
-       return 0;
-}
-
-static gboolean
-get_review_stats (GsPlugin *plugin,
-                 const gchar *package_name,
-                 gint *rating,
-                 guint *count1,
-                 guint *count2,
-                 guint *count3,
-                 guint *count4,
-                 guint *count5,
-                 GError **error)
-{
-       Histogram histogram = { 0, 0, 0, 0, 0 };
-       gchar *error_msg = NULL;
-       gint result, n_ratings;
-       g_autofree gchar *statement = NULL;
-
-       /* Get histogram from the database */
-       statement = g_strdup_printf ("SELECT one_star_count, two_star_count, three_star_count, 
four_star_count, five_star_count FROM review_stats "
-                                    "WHERE package_name = '%s'", package_name);
-       result = sqlite3_exec (plugin->priv->db,
-                              statement,
-                              get_rating_sqlite_cb,
-                              &histogram,
-                              &error_msg);
-       if (result != SQLITE_OK) {
-               g_set_error (error,
-                            GS_PLUGIN_ERROR,
-                            GS_PLUGIN_ERROR_FAILED,
-                            "SQL error: %s", error_msg);
-               sqlite3_free (error_msg);
-               return FALSE;
-       }
-
-       /* Convert to a rating */
-       // FIXME: Convert to a Wilson score
-       n_ratings = histogram.one_star_count + histogram.two_star_count + histogram.three_star_count + 
histogram.four_star_count + histogram.five_star_count;
-       if (n_ratings == 0)
-               *rating = -1;
-       else
-               *rating = ((histogram.one_star_count * 20) + (histogram.two_star_count * 40) + 
(histogram.three_star_count * 60) + (histogram.four_star_count * 80) + (histogram.five_star_count * 100)) / 
n_ratings;
-       *count1 = histogram.one_star_count;
-       *count2 = histogram.two_star_count;
-       *count3 = histogram.three_star_count;
-       *count4 = histogram.four_star_count;
-       *count5 = histogram.five_star_count;
-
-       return TRUE;
-}
-
-static gboolean
-parse_histogram (const gchar *text, Histogram *histogram)
-{
-       g_autoptr(JsonParser) parser = NULL;
-       JsonArray *array;
-
-       /* Histogram is a five element JSON array, e.g. "[1, 3, 5, 8, 4]" */
-       parser = json_parser_new ();
-       if (!json_parser_load_from_data (parser, text, -1, NULL))
-               return FALSE;
-       if (!JSON_NODE_HOLDS_ARRAY (json_parser_get_root (parser)))
-               return FALSE;
-       array = json_node_get_array (json_parser_get_root (parser));
-       if (json_array_get_length (array) != 5)
-               return FALSE;
-       histogram->one_star_count = json_array_get_int_element (array, 0);
-       histogram->two_star_count = json_array_get_int_element (array, 1);
-       histogram->three_star_count = json_array_get_int_element (array, 2);
-       histogram->four_star_count = json_array_get_int_element (array, 3);
-       histogram->five_star_count = json_array_get_int_element (array, 4);
-
-       return TRUE;
-}
-
-static gboolean
-parse_review_entry (JsonNode *node, const gchar **package_name, Histogram *histogram)
-{
-       JsonObject *object;
-       const gchar *name = NULL, *histogram_text = NULL;
-
-       if (!JSON_NODE_HOLDS_OBJECT (node))
-               return FALSE;
-
-       object = json_node_get_object (node);
-
-       name = json_object_get_string_member (object, "package_name");
-       histogram_text = json_object_get_string_member (object, "histogram");
-       if (!name || !histogram_text)
-               return FALSE;
-
-       if (!parse_histogram (histogram_text, histogram))
-               return FALSE;
-       *package_name = name;
-
-       return TRUE;
-}
-
-static gboolean
-parse_review_entries (GsPlugin *plugin, JsonParser *parser, GError **error)
-{
-       JsonArray *array;
-       guint i;
-
-       if (!JSON_NODE_HOLDS_ARRAY (json_parser_get_root (parser)))
-               return FALSE;
-       array = json_node_get_array (json_parser_get_root (parser));
-       for (i = 0; i < json_array_get_length (array); i++) {
-               const gchar *package_name;
-               Histogram histogram;
-
-               /* Read in from JSON... (skip bad entries) */
-               if (!parse_review_entry (json_array_get_element (array, i), &package_name, &histogram))
-                       continue;
-
-               /* ...write into the database (abort everything if can't write) */
-               if (!set_package_stats (plugin, package_name, &histogram, error))
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-
 static void
 sign_message (SoupMessage *message, OAuthMethod method,
              const gchar *consumer_key, const gchar *consumer_secret,
@@ -898,8 +533,8 @@ load_database (GsPlugin *plugin, GError **error)
                            "version TEXT,"
                            "date TEXT,"
                            "rating INTEGER,"
-                            "summary TEXT,"
-                            "text TEXT);";
+                           "summary TEXT,"
+                           "text TEXT);";
                sqlite3_exec (plugin->priv->db, statement, NULL, NULL, NULL);
                rebuild_ratings = TRUE;
        }
@@ -1053,8 +688,8 @@ download_reviews (GsPlugin *plugin, GsApp *app, const gchar *package_name, gint
        /* Get the review stats using HTTP */
        // FIXME: This will only get the first page of reviews
        language = get_language (plugin);
-       path = g_strdup_printf ("/api/1.0/reviews/filter/%s/any/any/any/%s/", language, package_name);
-       if (!send_review_request (plugin, SOUP_METHOD_GET, path, NULL, &result, error))
+       path = g_strdup_printf ("/api/1.0/reviews/filter/%s/any/any/any/%s/page/%d/", language, package_name, 
page_number + 1);
+       if (!send_review_request (plugin, SOUP_METHOD_GET, path, NULL, FALSE, &result, error))
                return FALSE;
 
        /* Extract the stats from the data */
@@ -1108,7 +743,7 @@ refine_rating (GsPlugin *plugin, GsApp *app, GError **error)
                }
        }
 
-       return ret;
+       return TRUE;
 }
 
 static gboolean
@@ -1190,3 +825,307 @@ gs_plugin_refine_app (GsPlugin *plugin,
 
        return TRUE;
 }
+
+static void
+add_string_member (JsonBuilder *builder, const gchar *name, const gchar *value)
+{
+       json_builder_set_member_name (builder, name);
+       json_builder_add_string_value (builder, value);
+}
+
+static void
+add_int_member (JsonBuilder *builder, const gchar *name, gint64 value)
+{
+       json_builder_set_member_name (builder, name);
+       json_builder_add_int_value (builder, value);
+}
+
+static gboolean
+set_package_review (GsPlugin *plugin,
+                   GsReview *review,
+                   const gchar *package_name,
+                   GError **error)
+{
+       gint rating;
+       gint n_stars;
+       g_autofree gchar *os_id = NULL, *os_ubuntu_codename = NULL, *language = NULL, *architecture = NULL;
+       g_autoptr(JsonBuilder) request = NULL;
+
+       /* Ubuntu reviews require a summary and description - just make one up for now */
+       rating = gs_review_get_rating (review);
+       if (rating > 80)
+               n_stars = 5;
+       else if (rating > 60)
+               n_stars = 4;
+       else if (rating > 40)
+               n_stars = 3;
+       else if (rating > 20)
+               n_stars = 2;
+       else
+               n_stars = 1;
+
+       os_id = gs_os_release_get_id (error);
+       if (os_id == NULL)
+               return FALSE;
+       os_ubuntu_codename = gs_os_release_get ("UBUNTU_CODENAME", error);
+       if (os_ubuntu_codename == NULL)
+               return FALSE;
+
+       language = get_language (plugin);
+
+       // FIXME: Need to get Apt::Architecture configuration value from APT
+       architecture = g_strdup ("amd64");
+
+       /* Create message for reviews.ubuntu.com */
+       request = json_builder_new ();
+       json_builder_begin_object (request);
+       add_string_member (request, "package_name", package_name);
+       add_string_member (request, "summary", gs_review_get_summary (review));
+       add_string_member (request, "review_text", gs_review_get_text (review));
+       add_string_member (request, "language", language);
+       add_string_member (request, "origin", os_id);
+       add_string_member (request, "distroseries", os_ubuntu_codename);
+       add_string_member (request, "version", gs_review_get_version (review));
+       add_int_member (request, "rating", n_stars);
+       add_string_member (request, "arch_tag", architecture);
+       json_builder_end_object (request);
+
+       return send_review_request (plugin, SOUP_METHOD_POST, "/api/1.0/reviews/", request, TRUE, NULL, 
error);
+}
+
+static gboolean
+set_review_usefulness (GsPlugin *plugin,
+                      const gchar *review_id,
+                      gboolean is_useful,
+                      GError **error)
+{
+       g_autofree gchar *path = NULL;
+
+       if (!get_ubuntuone_credentials (plugin, TRUE, error))
+               return FALSE;
+
+       /* Create message for reviews.ubuntu.com */
+       path = g_strdup_printf ("/api/1.0/reviews/%s/recommendations/?useful=%s", review_id, is_useful ? 
"True" : "False");
+       return send_review_request (plugin, SOUP_METHOD_POST, path, NULL, TRUE, NULL, error);
+}
+
+static gboolean
+report_review (GsPlugin *plugin,
+              const gchar *review_id,
+              const gchar *reason,
+              const gchar *text,
+              GError **error)
+{
+       g_autofree gchar *path = NULL;
+
+       if (!get_ubuntuone_credentials (plugin, TRUE, error))
+               return FALSE;
+
+       /* Create message for reviews.ubuntu.com */
+       // FIXME: escape reason / text properly
+       path = g_strdup_printf ("/api/1.0/reviews/%s/recommendations/?reason=%s&text=%s", review_id, reason, 
text);
+       return send_review_request (plugin, SOUP_METHOD_POST, path, NULL, TRUE, NULL, error);
+}
+
+static gboolean
+remove_review (GsPlugin *plugin,
+              const gchar *review_id,
+              GError **error)
+{
+       g_autofree gchar *path = NULL;
+
+       if (!get_ubuntuone_credentials (plugin, TRUE, error))
+               return FALSE;
+
+       /* Create message for reviews.ubuntu.com */
+       path = g_strdup_printf ("/api/1.0/reviews/delete/%s/", review_id);
+       return send_review_request (plugin, SOUP_METHOD_POST, path, NULL, TRUE, NULL, error);
+}
+
+gboolean
+gs_plugin_review_submit (GsPlugin *plugin,
+                        GsApp *app,
+                        GsReview *review,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       /* Load database once */
+       if (g_once_init_enter (&plugin->priv->db_loaded)) {
+               gboolean ret = load_database (plugin, error);
+               g_once_init_leave (&plugin->priv->db_loaded, TRUE);
+               if (!ret)
+                       return FALSE;
+       }
+
+       if (!get_ubuntuone_credentials (plugin, TRUE, error))
+               return FALSE;
+
+       return set_package_review (plugin,
+                                  review,
+                                  gs_app_get_source_default (app),
+                                  error);
+}
+
+gboolean
+gs_plugin_review_report (GsPlugin *plugin,
+                        GsApp *app,
+                        GsReview *review,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       const gchar *review_id;
+
+       /* Can only modify Ubuntu reviews */
+       review_id = gs_review_get_metadata_item (review, "ubuntu-id");
+       if (review_id == NULL)
+               return TRUE;
+
+       if (!report_review (plugin, review_id, "FIXME: gnome-software", "FIXME: gnome-software", error))
+               return FALSE;
+       gs_review_add_flags (review, GS_REVIEW_FLAG_VOTED);
+       return TRUE;
+}
+
+gboolean
+gs_plugin_review_upvote (GsPlugin *plugin,
+                        GsApp *app,
+                        GsReview *review,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       const gchar *review_id;
+
+       /* Can only modify Ubuntu reviews */
+       review_id = gs_review_get_metadata_item (review, "ubuntu-id");
+       if (review_id == NULL)
+               return TRUE;
+
+       if (!set_review_usefulness (plugin, review_id, TRUE, error))
+               return FALSE;
+       gs_review_add_flags (review, GS_REVIEW_FLAG_VOTED);
+       return TRUE;
+}
+
+gboolean
+gs_plugin_review_downvote (GsPlugin *plugin,
+                          GsApp *app,
+                          GsReview *review,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       const gchar *review_id;
+
+       /* Can only modify Ubuntu reviews */
+       review_id = gs_review_get_metadata_item (review, "ubuntu-id");
+       if (review_id == NULL)
+               return TRUE;
+
+       if (!set_review_usefulness (plugin, review_id, FALSE, error))
+               return FALSE;
+       gs_review_add_flags (review, GS_REVIEW_FLAG_VOTED);
+       return TRUE;
+}
+
+gboolean
+gs_plugin_review_remove (GsPlugin *plugin,
+                        GsApp *app,
+                        GsReview *review,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+       const gchar *review_id;
+
+       /* Can only modify Ubuntu reviews */
+       review_id = gs_review_get_metadata_item (review, "ubuntu-id");
+       if (review_id == NULL)
+               return TRUE;
+
+       return remove_review (plugin, review_id, error);
+}
+
+typedef struct {
+       gchar           *package_name;
+       gint             rating;
+} PopularEntry;
+
+static gint
+popular_sqlite_cb (void *data,
+                  gint argc,
+                  gchar **argv,
+                  gchar **col_name)
+{
+       GList **list = data;
+       PopularEntry *entry;
+
+       entry = g_slice_new (PopularEntry);
+       entry->package_name = g_strdup (argv[0]);
+       entry->rating = get_rating (g_ascii_strtoll (argv[1], NULL, 10), g_ascii_strtoll (argv[2], NULL, 10), 
g_ascii_strtoll (argv[3], NULL, 10), g_ascii_strtoll (argv[4], NULL, 10), g_ascii_strtoll (argv[5], NULL, 
10));
+       *list = g_list_prepend (*list, entry);
+
+       return 0;
+}
+
+static gint
+compare_popular_entry (gconstpointer a, gconstpointer b)
+{
+       PopularEntry *ea = a, *eb = b;
+       return eb->rating - ea->rating;
+}
+
+static void
+free_popular_entry (gpointer data)
+{
+       PopularEntry *entry = data;
+       g_free (entry->package_name);
+       g_slice_free (PopularEntry, entry);
+}
+
+gboolean
+gs_plugin_add_popular (GsPlugin *plugin,
+                      GList **list,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       gint result;
+       GList *entries = NULL, *link;
+       char *error_msg = NULL;
+
+       /* Load database once */
+       if (g_once_init_enter (&plugin->priv->db_loaded)) {
+               gboolean ret = load_database (plugin, error);
+               g_once_init_leave (&plugin->priv->db_loaded, TRUE);
+               if (!ret)
+                       return FALSE;
+       }
+
+       result = sqlite3_exec (plugin->priv->db,
+                              "SELECT package_name, one_star_count, two_star_count, three_star_count, 
four_star_count, five_star_count FROM review_stats",
+                              popular_sqlite_cb,
+                              &entries,
+                              &error_msg);
+       if (result != SQLITE_OK) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "SQL error: %s", error_msg);
+               sqlite3_free (error_msg);
+               return FALSE;
+       }
+
+       entries = g_list_sort (entries, compare_popular_entry);
+       for (link = entries; link; link = link->next) {
+               PopularEntry *entry = link->data;
+               g_autoptr(GsApp) app = NULL;
+
+               /* Need four stars to show */
+               if (entry->rating < 80)
+                       break;
+
+               app = gs_app_new (NULL);
+               gs_app_add_source (app, entry->package_name);
+               gs_plugin_add_app (list, app);
+       }
+       g_list_free_full (entries, free_popular_entry);
+
+       return TRUE;
+}



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