[libsocialweb: 2/7] smugmug: Implemented collections.



commit ad875cd14dc7316f367ee4e9081b6c23b277ea62
Author: Eitan Isaacson <eitan isaacson collabora co uk>
Date:   Thu Feb 10 17:41:50 2011 -0800

    smugmug: Implemented collections.

 services/smugmug/smugmug.c       |  348 ++++++++++++++++++++++++++++++++++++--
 services/smugmug/smugmug.keys.in |    2 +-
 2 files changed, 337 insertions(+), 13 deletions(-)
---
diff --git a/services/smugmug/smugmug.c b/services/smugmug/smugmug.c
index 11c68ff..1174775 100644
--- a/services/smugmug/smugmug.c
+++ b/services/smugmug/smugmug.c
@@ -58,9 +58,20 @@ G_DEFINE_TYPE_WITH_CODE (SwServiceSmugmug, sw_service_smugmug, SW_TYPE_SERVICE,
   (G_TYPE_INSTANCE_GET_PRIVATE ((o), SW_TYPE_SERVICE_SMUGMUG, SwServiceSmugmugPrivate))
 
 struct _SwServiceSmugmugPrivate {
-  RestProxy *proxy;
+  const gchar *api_key;
+  const gchar *api_secret;
+
+  RestProxy *rest_proxy;
+  RestProxy *upload_proxy;
+  RestProxy *auth_proxy;
 };
 
+enum {
+  COLLECTION = 1,
+  PHOTO = 2,
+  VIDEO = 4
+} typedef MediaType;
+
 static const char *
 get_name (SwService *service)
 {
@@ -87,7 +98,31 @@ got_tokens_cb (RestProxy *proxy, gboolean authorised, gpointer user_data)
 
   SW_DEBUG (SMUGMUG, "%sauthorized", authorised ? "" : "un");
 
-  g_object_set (G_OBJECT (priv->proxy), "url-format", REST_URL, NULL);
+  if (priv->rest_proxy != NULL)
+    g_object_unref (priv->rest_proxy);
+
+  if (priv->upload_proxy != NULL)
+    g_object_unref (priv->upload_proxy);
+
+  if (authorised) {
+    const gchar *token = oauth_proxy_get_token ((OAuthProxy *) proxy);
+    const gchar *token_secret =
+      oauth_proxy_get_token_secret ((OAuthProxy *) proxy);
+
+    priv->rest_proxy = oauth_proxy_new_with_token (priv->api_key,
+                                                   priv->api_secret,
+                                                   token,
+                                                   token_secret,
+                                                   REST_URL,
+                                                   FALSE);
+
+    priv->upload_proxy = oauth_proxy_new_with_token (priv->api_key,
+                                                     priv->api_secret,
+                                                     token,
+                                                     token_secret,
+                                                     UPLOAD_URL,
+                                                     FALSE);
+  }
 }
 
 static void
@@ -97,8 +132,7 @@ online_notify (gboolean online, gpointer user_data)
   SwServiceSmugmugPrivate *priv = self->priv;
 
   if (online) {
-    g_object_set (G_OBJECT (priv->proxy), "url-format", OAUTH_URL, NULL);
-    sw_keyfob_oauth ((OAuthProxy *)priv->proxy, got_tokens_cb, self);
+    sw_keyfob_oauth ((OAuthProxy *) priv->auth_proxy, got_tokens_cb, self);
   }
 }
 
@@ -129,18 +163,309 @@ sw_service_smugmug_dispose (GObject *object)
 {
   SwServiceSmugmugPrivate *priv = ((SwServiceSmugmug*)object)->priv;
 
-  if (priv->proxy) {
-    g_object_unref (priv->proxy);
-    priv->proxy = NULL;
+  if (priv->auth_proxy) {
+    g_object_unref (priv->auth_proxy);
+    priv->auth_proxy = NULL;
+  }
+
+  if (priv->rest_proxy) {
+    g_object_unref (priv->rest_proxy);
+    priv->rest_proxy = NULL;
+  }
+
+  if (priv->upload_proxy) {
+    g_object_unref (priv->upload_proxy);
+    priv->upload_proxy = NULL;
   }
 
   G_OBJECT_CLASS (sw_service_smugmug_parent_class)->dispose (object);
 }
 
+static RestXmlNode *
+node_from_call (RestProxyCall *call)
+{
+  static RestXmlParser *parser = NULL;
+  RestXmlNode *node;
+
+  if (call == NULL)
+    return NULL;
+
+  if (parser == NULL)
+    parser = rest_xml_parser_new ();
+
+  if (!SOUP_STATUS_IS_SUCCESSFUL (rest_proxy_call_get_status_code (call))) {
+    g_warning (G_STRLOC ": error from SmugMug: %s (%d)",
+               rest_proxy_call_get_status_message (call),
+               rest_proxy_call_get_status_code (call));
+    return NULL;
+  }
+
+  node = rest_xml_parser_parse_from_data (parser,
+                                          rest_proxy_call_get_payload (call),
+                                          rest_proxy_call_get_payload_length (call));
+  g_object_unref (call);
+
+  /* Invalid XML, or incorrect root */
+  if (node == NULL || !g_str_equal (node->name, "rsp")) {
+    g_warning (G_STRLOC ": cannot make SmugMug call");
+    /* TODO: display the payload if its short */
+    if (node) rest_xml_node_unref (node);
+    return NULL;
+  }
+
+  if (g_strcmp0 (rest_xml_node_get_attr (node, "stat"), "ok") != 0) {
+    RestXmlNode *err;
+    err = rest_xml_node_find (node, "err");
+    if (err)
+      g_warning (G_STRLOC ": cannot make SmugMug call: %s",
+                 rest_xml_node_get_attr (err, "msg"));
+    rest_xml_node_unref (node);
+    return NULL;
+  }
+
+  return node;
+}
+
+/* Collections Interface */
+
+static GValueArray *
+_extract_collection_details_from_xml (RestXmlNode *album)
+{
+  GValueArray *value_array;
+  GHashTable *attribs = g_hash_table_new (g_str_hash, g_str_equal);
+  GValue *value = NULL;
+  gint64 count = 0;
+  const gchar *count_string;
+
+  value_array = g_value_array_new (5);
+
+  value_array = g_value_array_append (value_array, NULL);
+  value = g_value_array_get_nth (value_array, 0);
+  g_value_init (value, G_TYPE_STRING);
+  g_value_take_string (value,
+                       g_strdup_printf ("%s_%s",
+                                        (gchar *) g_hash_table_lookup (album->attrs,
+                                                             "id"),
+                                        (gchar *) g_hash_table_lookup (album->attrs,
+                                                             "Key")));
+
+  value_array = g_value_array_append (value_array, NULL);
+  value = g_value_array_get_nth (value_array, 1);
+  g_value_init (value, G_TYPE_STRING);
+  g_value_set_static_string (value,
+                             g_hash_table_lookup (album->attrs, "Title"));
+
+  value_array = g_value_array_append (value_array, NULL);
+  value = g_value_array_get_nth (value_array, 2);
+  g_value_init (value, G_TYPE_STRING);
+  g_value_set_static_string (value, "");
+
+  value_array = g_value_array_append (value_array, NULL);
+  value = g_value_array_get_nth (value_array, 3);
+  g_value_init (value, G_TYPE_UINT);
+  g_value_set_uint (value, PHOTO | VIDEO);
+
+  if (g_hash_table_lookup_extended (album->attrs, "ImageCount",
+                                    NULL, (gpointer *) &count_string))
+    count = g_ascii_strtoll (count_string, NULL, 10);
+
+  value_array = g_value_array_append (value_array, NULL);
+  value = g_value_array_get_nth (value_array, 4);
+  g_value_init (value, G_TYPE_INT);
+  g_value_set_int (value, count);
+
+  g_hash_table_insert (attribs, "description",
+                       g_hash_table_lookup (album->attrs, "Description"));
+
+  g_hash_table_insert (attribs, "url",
+                       g_hash_table_lookup (album->attrs, "URL"));
+
+  value_array = g_value_array_append (value_array, NULL);
+  value = g_value_array_get_nth (value_array, 5);
+  g_value_init (value, dbus_g_type_get_map ("GHashTable",
+          G_TYPE_STRING,
+          G_TYPE_STRING));
+  g_value_take_boxed (value, attribs);
+
+  return value_array;
+}
+
+static void
+_list_albums_cb (RestProxyCall *call,
+                 const GError  *error,
+                 GObject       *weak_object,
+                 gpointer       user_data)
+{
+  DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+  RestXmlNode *root;
+  RestXmlNode *album;
+  GPtrArray *rv = g_ptr_array_new_with_free_func (
+      (GDestroyNotify )g_value_array_free);
+
+  root = node_from_call (call);
+
+  g_return_if_fail (root != NULL);
+
+  album = rest_xml_node_find (root, "Album");
+
+  while (album != NULL) {
+    GValueArray *collection_details =
+      _extract_collection_details_from_xml (album);
+    g_ptr_array_add (rv, collection_details);
+    album = album->next;
+  }
+
+  sw_collections_iface_return_from_get_list (context, rv);
+
+  g_ptr_array_free (rv, TRUE);
+  rest_xml_node_unref (root);
+}
+
+static void
+_smugmug_collections_get_list (SwCollectionsIface *self,
+                                DBusGMethodInvocation *context)
+{
+  SwServiceSmugmug *smugmug = SW_SERVICE_SMUGMUG (self);
+  SwServiceSmugmugPrivate *priv = smugmug->priv;
+  RestProxyCall *call;
+
+  g_return_if_fail (priv->rest_proxy != NULL);
+
+  call = rest_proxy_new_call (priv->rest_proxy);
+  rest_proxy_call_add_param (call, "method", "smugmug.albums.get");
+  rest_proxy_call_add_param (call, "Extras", "Description,URL,ImageCount");
+
+  rest_proxy_call_async (call,
+                         (RestProxyCallAsyncCallback) _list_albums_cb,
+                         (GObject *) smugmug,
+                         context,
+                         NULL);
+}
+
+static void
+_create_album_cb (RestProxyCall *call,
+    const GError  *error,
+    GObject       *weak_object,
+    gpointer       user_data)
+{
+  DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+  RestXmlNode *root = node_from_call (call);
+  RestXmlNode *album = rest_xml_node_find (root, "Album");
+  gchar *id;
+
+  id = g_strdup_printf ("%s_%s",
+                        (gchar *) g_hash_table_lookup (album->attrs, "id"),
+                        (gchar *) g_hash_table_lookup (album->attrs, "Key"));
+
+  sw_collections_iface_return_from_create (context, id);
+
+  g_free (id);
+
+  rest_xml_node_unref (root);
+}
+
+static void
+_smugmug_collections_create (SwCollectionsIface *self,
+    const gchar *collection_name,
+    MediaType supported_types,
+    const gchar *collection_parent,
+    GHashTable *extra_parameters,
+    DBusGMethodInvocation *context)
+{
+  SwServiceSmugmug *smugmug = SW_SERVICE_SMUGMUG (self);
+  SwServiceSmugmugPrivate *priv = smugmug->priv;
+  RestProxyCall *call;
+
+  g_return_if_fail (priv->rest_proxy != NULL);
+
+  if (strlen (collection_parent) != 0) {
+    GError error = {SW_SERVICE_ERROR,
+                    SW_SERVICE_ERROR_NOT_SUPPORTED,
+                    "SmugMug does not support nested albums."};
+    dbus_g_method_return_error (context, &error);
+    return;
+  }
+
+  call = rest_proxy_new_call (priv->rest_proxy);
+  rest_proxy_call_add_param (call, "method", "smugmug.albums.create");
+  rest_proxy_call_add_param (call, "Title", collection_name);
+  rest_proxy_call_set_method (call, "POST");
+
+  rest_proxy_call_async (call,
+                         (RestProxyCallAsyncCallback) _create_album_cb,
+                         (GObject *) smugmug,
+                         context,
+                         NULL);
+
+}
+
+static void
+_get_album_details_cb (RestProxyCall *call,
+                       const GError  *error,
+                       GObject       *weak_object,
+                       gpointer       user_data)
+{
+  DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data;
+  GValueArray *collection_details;
+  RestXmlNode *root = node_from_call (call);
+  RestXmlNode *album = rest_xml_node_find (root, "Album");
+
+  collection_details = _extract_collection_details_from_xml (album);
+
+  sw_collections_iface_return_from_get_details (context,
+      collection_details);
+
+  g_value_array_free (collection_details);
+
+  rest_xml_node_unref (root);
+}
+
+static void
+_smugmug_collections_get_details (SwCollectionsIface *self,
+    const gchar *collection_id,
+    DBusGMethodInvocation *context)
+{
+  SwServiceSmugmug *smugmug = SW_SERVICE_SMUGMUG (self);
+  SwServiceSmugmugPrivate *priv = smugmug->priv;
+  RestProxyCall *call;
+  gchar **id;
+
+  g_return_if_fail (priv->rest_proxy != NULL);
+
+  id = g_strsplit (collection_id, "_", 2);
+
+  if (g_strv_length (id) != 2) {
+    g_warning ("invalid collection id");
+    g_strfreev (id);
+    return;
+  }
+
+  call = rest_proxy_new_call (priv->rest_proxy);
+  rest_proxy_call_add_param (call, "method", "smugmug.albums.getInfo");
+  rest_proxy_call_add_param (call, "AlbumID", id[0]);
+  rest_proxy_call_add_param (call, "AlbumKey", id[1]);
+
+  rest_proxy_call_async (call,
+                         (RestProxyCallAsyncCallback) _get_album_details_cb,
+                         (GObject *) smugmug,
+                         context,
+                         NULL);
+}
+
 static void
 collections_iface_init (gpointer g_iface,
-                  gpointer iface_data)
+                        gpointer iface_data)
 {
+  SwCollectionsIfaceClass *klass = (SwCollectionsIfaceClass *) g_iface;
+
+  sw_collections_iface_implement_get_list (klass,
+                                           _smugmug_collections_get_list);
+
+  sw_collections_iface_implement_create (klass,
+                                         _smugmug_collections_create);
+
+  sw_collections_iface_implement_get_details (klass,
+                                              _smugmug_collections_get_details);
 }
 
 static void
@@ -162,14 +487,13 @@ static void
 sw_service_smugmug_init (SwServiceSmugmug *self)
 {
   SwServiceSmugmugPrivate *priv;
-  const gchar *key = NULL;
-  const gchar *secret = NULL;
 
   priv = self->priv = GET_PRIVATE (self);
 
-  sw_keystore_get_key_secret ("smugmug", &key, &secret);
+  sw_keystore_get_key_secret ("smugmug", &priv->api_key, &priv->api_secret);
 
-  priv->proxy = oauth_proxy_new (key, secret, REST_URL, FALSE);
+  priv->auth_proxy = oauth_proxy_new (priv->api_key, priv->api_secret,
+                                      OAUTH_URL, FALSE);
 
   sw_online_add_notify (online_notify, self);
 
diff --git a/services/smugmug/smugmug.keys.in b/services/smugmug/smugmug.keys.in
index a932e43..cc935e7 100644
--- a/services/smugmug/smugmug.keys.in
+++ b/services/smugmug/smugmug.keys.in
@@ -7,5 +7,5 @@ AuthType=oauth
 [OAuth]
 BaseURL=http://api.smugmug.com/services/oauth/
 RequestTokenFunction=getRequestToken.mg
-AuthoriseFunction=authorize.mg
+AuthoriseFunction=authorize.mg?Access=Full&Permissions=Add
 AccessTokenFunction=getAccessToken.mg



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