Blame src/goabackend/goatodoistprovider.c

Packit Service c6b9b0
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
Packit Service c6b9b0
/*
Packit Service c6b9b0
 * Copyright © 2017 Ekta Nandwani
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * This library is free software; you can redistribute it and/or
Packit Service c6b9b0
 * modify it under the terms of the GNU Lesser General Public
Packit Service c6b9b0
 * License as published by the Free Software Foundation; either
Packit Service c6b9b0
 * version 2 of the License, or (at your option) any later version.
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * This library is distributed in the hope that it will be useful,
Packit Service c6b9b0
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service c6b9b0
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service c6b9b0
 * Lesser General Public License for more details.
Packit Service c6b9b0
 *
Packit Service c6b9b0
 * You should have received a copy of the GNU Lesser General
Packit Service c6b9b0
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit Service c6b9b0
 */
Packit Service c6b9b0
Packit Service c6b9b0
#include "config.h"
Packit Service c6b9b0
#include <glib/gi18n-lib.h>
Packit Service c6b9b0
Packit Service c6b9b0
#include <rest/rest-proxy.h>
Packit Service c6b9b0
#include <json-glib/json-glib.h>
Packit Service c6b9b0
Packit Service c6b9b0
#include "goaprovider.h"
Packit Service c6b9b0
#include "goaprovider-priv.h"
Packit Service c6b9b0
#include "goaoauth2provider.h"
Packit Service c6b9b0
#include "goaoauth2provider-priv.h"
Packit Service c6b9b0
#include "goatodoistprovider.h"
Packit Service c6b9b0
#include "goaobjectskeletonutils.h"
Packit Service c6b9b0
#include "goarestproxy.h"
Packit Service c6b9b0
Packit Service c6b9b0
Packit Service c6b9b0
struct _GoaTodoistProvider
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaOAuth2Provider parent_instance;
Packit Service c6b9b0
};
Packit Service c6b9b0
Packit Service c6b9b0
G_DEFINE_TYPE_WITH_CODE (GoaTodoistProvider, goa_todoist_provider, GOA_TYPE_OAUTH2_PROVIDER,
Packit Service c6b9b0
                         goa_provider_ensure_extension_points_registered ();
Packit Service c6b9b0
                         g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
Packit Service c6b9b0
                                                         g_define_type_id,
Packit Service c6b9b0
                                                         GOA_TODOIST_NAME,
Packit Service c6b9b0
                                                         0));
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_provider_type (GoaProvider *provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return GOA_TODOIST_NAME;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gchar *
Packit Service c6b9b0
get_provider_name (GoaProvider *provider,
Packit Service c6b9b0
                   GoaObject   *object)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return g_strdup (_("Todoist"));
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static GoaProviderGroup
Packit Service c6b9b0
get_provider_group (GoaProvider *provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return GOA_PROVIDER_GROUP_BRANDED;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static GoaProviderFeatures
Packit Service c6b9b0
get_provider_features (GoaProvider *provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return GOA_PROVIDER_FEATURE_TODO;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_authorization_uri (GoaOAuth2Provider *oauth2_provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return "https://todoist.com/oauth/authorize";
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_scope (GoaOAuth2Provider *oauth2_provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return "data:read_write,data:delete,task:add,project:delete";
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_redirect_uri (GoaOAuth2Provider *oauth2_provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return "https://localhost";
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_client_id (GoaOAuth2Provider *oauth2_provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return GOA_TODOIST_CLIENT_ID;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_client_secret (GoaOAuth2Provider *oauth2_provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return GOA_TODOIST_CLIENT_SECRET;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static const gchar *
Packit Service c6b9b0
get_token_uri (GoaOAuth2Provider *oauth2_provider)
Packit Service c6b9b0
{
Packit Service c6b9b0
  return "https://todoist.com/oauth/access_token";
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static gchar *
Packit Service c6b9b0
build_authorization_uri (GoaOAuth2Provider  *oauth2_provider,
Packit Service c6b9b0
                         const gchar        *authorization_uri,
Packit Service c6b9b0
                         const gchar        *escaped_redirect_uri,
Packit Service c6b9b0
                         const gchar        *escaped_client_id,
Packit Service c6b9b0
                         const gchar        *escaped_scope)
Packit Service c6b9b0
{
Packit Service c6b9b0
  gchar *state;
Packit Service c6b9b0
  gchar *uri;
Packit Service c6b9b0
Packit Service c6b9b0
  state = g_uuid_string_random ();
Packit Service c6b9b0
  uri = g_strdup_printf ("%s"
Packit Service c6b9b0
                         "?response_type=token"
Packit Service c6b9b0
                         "&client_id=%s"
Packit Service c6b9b0
                         "&scope=%s"
Packit Service c6b9b0
                         "&state=%s",
Packit Service c6b9b0
                         authorization_uri,
Packit Service c6b9b0
                         escaped_client_id,
Packit Service c6b9b0
                         escaped_scope,
Packit Service c6b9b0
                         state);
Packit Service c6b9b0
Packit Service c6b9b0
  g_free (state);
Packit Service c6b9b0
  return uri;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
Packit Service c6b9b0
{
Packit Service c6b9b0
  gboolean ret = FALSE;
Packit Service c6b9b0
  gchar *element_type = NULL;
Packit Service c6b9b0
  gchar *id = NULL;
Packit Service c6b9b0
  gchar *name = NULL;
Packit Service c6b9b0
Packit Service c6b9b0
  g_object_get (element, "type", &element_type, NULL);
Packit Service c6b9b0
  if (g_strcmp0 (element_type, "email") != 0)
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
Packit Service c6b9b0
  id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (element));
Packit Service c6b9b0
  if (g_strcmp0 (id, "email") != 0)
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
Packit Service c6b9b0
  ret = TRUE;
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_free (element_type);
Packit Service c6b9b0
  g_free (id);
Packit Service c6b9b0
  g_free (name);
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static gchar *
Packit Service c6b9b0
get_identity_sync (GoaOAuth2Provider  *oauth2_provider,
Packit Service c6b9b0
                   const gchar        *access_token,
Packit Service c6b9b0
                   gchar             **out_presentation_identity,
Packit Service c6b9b0
                   GCancellable       *cancellable,
Packit Service c6b9b0
                   GError            **error)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GError *identity_error = NULL;
Packit Service c6b9b0
  RestProxy *proxy = NULL;
Packit Service c6b9b0
  RestProxyCall *call = NULL;
Packit Service c6b9b0
  JsonObject *json_object;
Packit Service c6b9b0
  JsonObject *json_object_user;
Packit Service c6b9b0
  JsonParser *parser = NULL;
Packit Service c6b9b0
  gchar *email = NULL;
Packit Service c6b9b0
  gchar *ret = NULL;
Packit Service c6b9b0
Packit Service c6b9b0
  proxy = goa_rest_proxy_new ("https://todoist.com/API/v7/sync", FALSE);
Packit Service c6b9b0
  call = rest_proxy_new_call (proxy);
Packit Service c6b9b0
  rest_proxy_call_set_method (call, "GET");
Packit Service c6b9b0
  rest_proxy_call_add_param (call, "token", access_token);
Packit Service c6b9b0
  rest_proxy_call_add_param (call, "sync_token", "*");
Packit Service c6b9b0
  rest_proxy_call_add_param (call, "resource_types", "[\"user\"]");
Packit Service c6b9b0
Packit Service c6b9b0
  if (!rest_proxy_call_sync (call, error))
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
  if (rest_proxy_call_get_status_code (call) != 200)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_set_error (error,
Packit Service c6b9b0
                   GOA_ERROR,
Packit Service c6b9b0
                   GOA_ERROR_FAILED,
Packit Service c6b9b0
                   _("Expected status 200 when requesting your identity, instead got status %d (%s)"),
Packit Service c6b9b0
                   rest_proxy_call_get_status_code (call),
Packit Service c6b9b0
                   rest_proxy_call_get_status_message (call));
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  parser = json_parser_new ();
Packit Service c6b9b0
  if (!json_parser_load_from_data (parser,
Packit Service c6b9b0
                                   rest_proxy_call_get_payload (call),
Packit Service c6b9b0
                                   rest_proxy_call_get_payload_length (call),
Packit Service c6b9b0
                                   &identity_error))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("json_parser_load_from_data() failed: %s (%s, %d)",
Packit Service c6b9b0
                 identity_error->message,
Packit Service c6b9b0
                 g_quark_to_string (identity_error->domain),
Packit Service c6b9b0
                 identity_error->code);
Packit Service c6b9b0
      g_set_error (error,
Packit Service c6b9b0
                   GOA_ERROR,
Packit Service c6b9b0
                   GOA_ERROR_FAILED,
Packit Service c6b9b0
                   _("Could not parse response"));
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  json_object = json_node_get_object (json_parser_get_root (parser));
Packit Service c6b9b0
  if (!json_object_has_member (json_object, "user"))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Did not find user in JSON data");
Packit Service c6b9b0
      g_set_error (error,
Packit Service c6b9b0
                   GOA_ERROR,
Packit Service c6b9b0
                   GOA_ERROR_FAILED,
Packit Service c6b9b0
                   _("Could not parse response"));
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  json_object_user = json_object_get_object_member (json_object, "user");
Packit Service c6b9b0
  if (!json_object_has_member (json_object_user, "email"))
Packit Service c6b9b0
    {
Packit Service c6b9b0
      g_warning ("Did not find user.email in JSON data");
Packit Service c6b9b0
      g_set_error (error,
Packit Service c6b9b0
                   GOA_ERROR,
Packit Service c6b9b0
                   GOA_ERROR_FAILED,
Packit Service c6b9b0
                   _("Could not parse response"));
Packit Service c6b9b0
      goto out;
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  email = g_strdup (json_object_get_string_member (json_object_user, "email"));
Packit Service c6b9b0
Packit Service c6b9b0
  ret = email;
Packit Service c6b9b0
  email = NULL;
Packit Service c6b9b0
  if (out_presentation_identity != NULL)
Packit Service c6b9b0
    *out_presentation_identity = g_strdup (ret);
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_clear_object (&parser);
Packit Service c6b9b0
  g_clear_error (&identity_error);
Packit Service c6b9b0
  g_clear_object (&call);
Packit Service c6b9b0
  g_clear_object (&proxy);
Packit Service c6b9b0
  g_free (email);
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static gboolean
Packit Service c6b9b0
build_object (GoaProvider         *provider,
Packit Service c6b9b0
              GoaObjectSkeleton   *object,
Packit Service c6b9b0
              GKeyFile            *key_file,
Packit Service c6b9b0
              const gchar         *group,
Packit Service c6b9b0
              GDBusConnection     *connection,
Packit Service c6b9b0
              gboolean             just_added,
Packit Service c6b9b0
              GError             **error)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaAccount *account = NULL;
Packit Service c6b9b0
  gboolean todo_enabled;
Packit Service c6b9b0
  gboolean ret = FALSE;
Packit Service c6b9b0
Packit Service c6b9b0
  /* Chain up */
Packit Service c6b9b0
  if (!GOA_PROVIDER_CLASS (goa_todoist_provider_parent_class)->build_object (provider,
Packit Service c6b9b0
                                                                             object,
Packit Service c6b9b0
                                                                             key_file,
Packit Service c6b9b0
                                                                             group,
Packit Service c6b9b0
                                                                             connection,
Packit Service c6b9b0
                                                                             just_added,
Packit Service c6b9b0
                                                                             error))
Packit Service c6b9b0
    goto out;
Packit Service c6b9b0
Packit Service c6b9b0
  account = goa_object_get_account (GOA_OBJECT (object));
Packit Service c6b9b0
Packit Service c6b9b0
  /* Todo */
Packit Service c6b9b0
  todo_enabled = g_key_file_get_boolean (key_file, group, "TodoEnabled", NULL);
Packit Service c6b9b0
  goa_object_skeleton_attach_todo (object, todo_enabled);
Packit Service c6b9b0
Packit Service c6b9b0
  if (just_added)
Packit Service c6b9b0
    {
Packit Service c6b9b0
      goa_account_set_todo_disabled (account, !todo_enabled);
Packit Service c6b9b0
Packit Service c6b9b0
      g_signal_connect (account,
Packit Service c6b9b0
                        "notify::todo-disabled",
Packit Service c6b9b0
                        G_CALLBACK (goa_util_account_notify_property_cb),
Packit Service c6b9b0
                        (gpointer) "TodoEnabled");
Packit Service c6b9b0
    }
Packit Service c6b9b0
Packit Service c6b9b0
  ret = TRUE;
Packit Service c6b9b0
Packit Service c6b9b0
 out:
Packit Service c6b9b0
  g_clear_object (&account);
Packit Service c6b9b0
  return ret;
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
add_account_key_values (GoaOAuth2Provider *oauth2_provider,
Packit Service c6b9b0
                        GVariantBuilder   *builder)
Packit Service c6b9b0
{
Packit Service c6b9b0
  g_variant_builder_add (builder, "{ss}", "TodoEnabled", "true");
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
/* ---------------------------------------------------------------------------------------------------- */
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_todoist_provider_init (GoaTodoistProvider *self)
Packit Service c6b9b0
{
Packit Service c6b9b0
}
Packit Service c6b9b0
Packit Service c6b9b0
static void
Packit Service c6b9b0
goa_todoist_provider_class_init (GoaTodoistProviderClass *klass)
Packit Service c6b9b0
{
Packit Service c6b9b0
  GoaProviderClass *provider_class;
Packit Service c6b9b0
  GoaOAuth2ProviderClass *oauth2_class;
Packit Service c6b9b0
Packit Service c6b9b0
  provider_class = GOA_PROVIDER_CLASS (klass);
Packit Service c6b9b0
  provider_class->get_provider_type          = get_provider_type;
Packit Service c6b9b0
  provider_class->get_provider_name          = get_provider_name;
Packit Service c6b9b0
  provider_class->get_provider_group         = get_provider_group;
Packit Service c6b9b0
  provider_class->get_provider_features      = get_provider_features;
Packit Service c6b9b0
  provider_class->build_object               = build_object;
Packit Service c6b9b0
Packit Service c6b9b0
  oauth2_class = GOA_OAUTH2_PROVIDER_CLASS (klass);
Packit Service c6b9b0
  oauth2_class->get_authorization_uri     = get_authorization_uri;
Packit Service c6b9b0
  oauth2_class->build_authorization_uri   = build_authorization_uri;
Packit Service c6b9b0
  oauth2_class->get_redirect_uri          = get_redirect_uri;
Packit Service c6b9b0
  oauth2_class->get_client_id             = get_client_id;
Packit Service c6b9b0
  oauth2_class->get_token_uri             = get_token_uri;
Packit Service c6b9b0
  oauth2_class->get_client_secret         = get_client_secret;
Packit Service c6b9b0
  oauth2_class->get_scope                 = get_scope;
Packit Service c6b9b0
  oauth2_class->get_identity_sync         = get_identity_sync;
Packit Service c6b9b0
  oauth2_class->is_identity_node          = is_identity_node;
Packit Service c6b9b0
  oauth2_class->add_account_key_values    = add_account_key_values;
Packit Service c6b9b0
}