From d10155034b0fa2e43e2889e55157798ce073f807 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 20 Apr 2017 11:50:09 +0100 Subject: tasks: Re-add ISO 8601 formatting workaround for Tasks service This partially reverts commit 684f95e8845be4f9efc434ea6456bee99b2303ac for the Tasks service only, since it is the only service which currently requires a formatting workaround for ISO 8601 date timezones. https://bugzilla.gnome.org/show_bug.cgi?id=780067 Signed-off-by: Philip Withnall --- gdata/gdata-parser.c | 31 ++++++++++++++++++ gdata/gdata-parser.h | 1 + gdata/services/tasks/gdata-tasks-query.c | 10 +++--- gdata/services/tasks/gdata-tasks-task.c | 49 +++++++++++++++++++++++++--- gdata/services/tasks/gdata-tasks-tasklist.c | 50 +++++++++++++++++++++++++++++ gdata/tests/tasks.c | 34 ++++++++++---------- 6 files changed, 148 insertions(+), 27 deletions(-) diff --git a/gdata/gdata-parser.c b/gdata/gdata-parser.c index a43c2ecf..ef10a479 100644 --- a/gdata/gdata-parser.c +++ b/gdata/gdata-parser.c @@ -248,6 +248,37 @@ gdata_parser_int64_to_iso8601 (gint64 _time) return g_time_val_to_iso8601 (&time_val); } +gchar * +gdata_parser_int64_to_iso8601_numeric_timezone (gint64 _time) +{ + GTimeVal time_val; + gchar *iso8601; + gchar **date_time_components; + gchar *retval; + + time_val.tv_sec = _time; + time_val.tv_usec = 0; + + iso8601 = g_time_val_to_iso8601 (&time_val); + + /* FIXME: Work around for Google's incorrect ISO 8601 implementation. + * They appear to not like dates in the format ‘2014-08-09T21:07:05Z’ + * which specify a timezone using ‘Z’ and no microseconds. This varies + * between services. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=732809 + * https://bugzilla.gnome.org/show_bug.cgi?id=780067 + * https://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=3595 + * http://stackoverflow.com/a/17630320/2931197 */ + date_time_components = g_strsplit (iso8601, "Z", 2); + retval = g_strjoinv (".000001+00:00", date_time_components); + g_strfreev (date_time_components); + + g_free (iso8601); + + return retval; +} + gboolean gdata_parser_int64_from_iso8601 (const gchar *date, gint64 *_time) { diff --git a/gdata/gdata-parser.h b/gdata/gdata-parser.h index bc7a15a7..6f0303f7 100644 --- a/gdata/gdata-parser.h +++ b/gdata/gdata-parser.h @@ -46,6 +46,7 @@ gdata_parser_error_from_json_error (JsonReader *reader, gboolean gdata_parser_int64_from_date (const gchar *date, gint64 *_time); gchar *gdata_parser_date_from_int64 (gint64 _time) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC; gchar *gdata_parser_int64_to_iso8601 (gint64 _time) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC; +gchar *gdata_parser_int64_to_iso8601_numeric_timezone (gint64 _time) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC; gboolean gdata_parser_int64_from_iso8601 (const gchar *date, gint64 *_time); /* diff --git a/gdata/services/tasks/gdata-tasks-query.c b/gdata/services/tasks/gdata-tasks-query.c index 627dc862..80ff7022 100644 --- a/gdata/services/tasks/gdata-tasks-query.c +++ b/gdata/services/tasks/gdata-tasks-query.c @@ -288,7 +288,7 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo APPEND_SEP g_string_append (query_uri, "updatedMin="); - updated_min = gdata_parser_int64_to_iso8601 (gdata_query_get_updated_min (GDATA_QUERY (self))); + updated_min = gdata_parser_int64_to_iso8601_numeric_timezone (gdata_query_get_updated_min (GDATA_QUERY (self))); g_string_append (query_uri, updated_min); g_free (updated_min); } @@ -298,7 +298,7 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo APPEND_SEP g_string_append (query_uri, "completedMin="); - completed_min = gdata_parser_int64_to_iso8601 (priv->completed_min); + completed_min = gdata_parser_int64_to_iso8601_numeric_timezone (priv->completed_min); g_string_append (query_uri, completed_min); g_free (completed_min); } @@ -308,7 +308,7 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo APPEND_SEP g_string_append (query_uri, "completedMax="); - completed_max = gdata_parser_int64_to_iso8601 (priv->completed_max); + completed_max = gdata_parser_int64_to_iso8601_numeric_timezone (priv->completed_max); g_string_append (query_uri, completed_max); g_free (completed_max); } @@ -318,7 +318,7 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo APPEND_SEP g_string_append (query_uri, "dueMin="); - due_min = gdata_parser_int64_to_iso8601 (priv->due_min); + due_min = gdata_parser_int64_to_iso8601_numeric_timezone (priv->due_min); g_string_append (query_uri, due_min); g_free (due_min); } @@ -328,7 +328,7 @@ get_query_uri (GDataQuery *self, const gchar *feed_uri, GString *query_uri, gboo APPEND_SEP g_string_append (query_uri, "dueMax="); - due_max = gdata_parser_int64_to_iso8601 (priv->due_max); + due_max = gdata_parser_int64_to_iso8601_numeric_timezone (priv->due_max); g_string_append (query_uri, due_max); g_free (due_max); } diff --git a/gdata/services/tasks/gdata-tasks-task.c b/gdata/services/tasks/gdata-tasks-task.c index 00490b89..568c8288 100644 --- a/gdata/services/tasks/gdata-tasks-task.c +++ b/gdata/services/tasks/gdata-tasks-task.c @@ -333,11 +333,50 @@ get_json (GDataParsable *parsable, JsonBuilder *builder) { gchar *due; gchar *completed; - + GList *i; + GDataLink *_link; + GDataEntry *entry = GDATA_ENTRY (parsable); GDataTasksTaskPrivate *priv = GDATA_TASKS_TASK (parsable)->priv; - /* Chain up to the parent class */ - GDATA_PARSABLE_CLASS (gdata_tasks_task_parent_class)->get_json (parsable, builder); + /* Add all the general JSON. We can’t chain up to #GDataEntry here + * because Google Tasks uses a different date format. */ + json_builder_set_member_name (builder, "title"); + json_builder_add_string_value (builder, gdata_entry_get_title (entry)); + + if (gdata_entry_get_id (entry)) { + json_builder_set_member_name (builder, "id"); + json_builder_add_string_value (builder, gdata_entry_get_id (entry)); + } + + if (gdata_entry_get_updated (entry) != -1) { + gchar *updated = gdata_parser_int64_to_iso8601_numeric_timezone (gdata_entry_get_updated (entry)); + json_builder_set_member_name (builder, "updated"); + json_builder_add_string_value (builder, updated); + g_free (updated); + } + + /* If we have a "kind" category, add that. */ + for (i = gdata_entry_get_categories (entry); i != NULL; i = i->next) { + GDataCategory *category = GDATA_CATEGORY (i->data); + + if (g_strcmp0 (gdata_category_get_scheme (category), "http://schemas.google.com/g/2005#kind") == 0) { + json_builder_set_member_name (builder, "kind"); + json_builder_add_string_value (builder, gdata_category_get_term (category)); + } + } + + /* Add the ETag, if available. */ + if (gdata_entry_get_etag (entry) != NULL) { + json_builder_set_member_name (builder, "etag"); + json_builder_add_string_value (builder, gdata_entry_get_etag (entry)); + } + + /* Add the self-link. */ + _link = gdata_entry_look_up_link (GDATA_ENTRY (parsable), GDATA_LINK_SELF); + if (_link != NULL) { + json_builder_set_member_name (builder, "selfLink"); + json_builder_add_string_value (builder, gdata_link_get_uri (_link)); + } /* Add all the task specific JSON */ @@ -358,13 +397,13 @@ get_json (GDataParsable *parsable, JsonBuilder *builder) json_builder_add_string_value (builder, priv->status); } if (priv->due != -1) { - due = gdata_parser_int64_to_iso8601 (priv->due); + due = gdata_parser_int64_to_iso8601_numeric_timezone (priv->due); json_builder_set_member_name (builder, "due"); json_builder_add_string_value (builder, due); g_free (due); } if (priv->completed != -1) { - completed = gdata_parser_int64_to_iso8601 (priv->completed); + completed = gdata_parser_int64_to_iso8601_numeric_timezone (priv->completed); json_builder_set_member_name (builder, "completed"); json_builder_add_string_value (builder, completed); g_free (completed); diff --git a/gdata/services/tasks/gdata-tasks-tasklist.c b/gdata/services/tasks/gdata-tasks-tasklist.c index 1690c232..2fbc470e 100644 --- a/gdata/services/tasks/gdata-tasks-tasklist.c +++ b/gdata/services/tasks/gdata-tasks-tasklist.c @@ -40,6 +40,7 @@ #include "gdata-private.h" #include "gdata-types.h" +static void get_json (GDataParsable *parsable, JsonBuilder *builder); static const gchar *get_content_type (void); G_DEFINE_TYPE (GDataTasksTasklist, gdata_tasks_tasklist, GDATA_TYPE_ENTRY) @@ -50,6 +51,7 @@ gdata_tasks_tasklist_class_init (GDataTasksTasklistClass *klass) GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass); GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass); + parsable_class->get_json = get_json; parsable_class->get_content_type = get_content_type; entry_class->kind_term = "tasks#taskList"; @@ -61,6 +63,54 @@ gdata_tasks_tasklist_init (GDataTasksTasklist *self) /* Empty */ } +static void +get_json (GDataParsable *parsable, JsonBuilder *builder) +{ + GList *i; + GDataLink *_link; + GDataEntry *entry = GDATA_ENTRY (parsable); + + /* Add all the general JSON. We can’t chain up to #GDataEntry here + * because Google Tasks uses a different date format. */ + json_builder_set_member_name (builder, "title"); + json_builder_add_string_value (builder, gdata_entry_get_title (entry)); + + if (gdata_entry_get_id (entry)) { + json_builder_set_member_name (builder, "id"); + json_builder_add_string_value (builder, gdata_entry_get_id (entry)); + } + + if (gdata_entry_get_updated (entry) != -1) { + gchar *updated = gdata_parser_int64_to_iso8601_numeric_timezone (gdata_entry_get_updated (entry)); + json_builder_set_member_name (builder, "updated"); + json_builder_add_string_value (builder, updated); + g_free (updated); + } + + /* If we have a "kind" category, add that. */ + for (i = gdata_entry_get_categories (entry); i != NULL; i = i->next) { + GDataCategory *category = GDATA_CATEGORY (i->data); + + if (g_strcmp0 (gdata_category_get_scheme (category), "http://schemas.google.com/g/2005#kind") == 0) { + json_builder_set_member_name (builder, "kind"); + json_builder_add_string_value (builder, gdata_category_get_term (category)); + } + } + + /* Add the ETag, if available. */ + if (gdata_entry_get_etag (entry) != NULL) { + json_builder_set_member_name (builder, "etag"); + json_builder_add_string_value (builder, gdata_entry_get_etag (entry)); + } + + /* Add the self-link. */ + _link = gdata_entry_look_up_link (GDATA_ENTRY (parsable), GDATA_LINK_SELF); + if (_link != NULL) { + json_builder_set_member_name (builder, "selfLink"); + json_builder_add_string_value (builder, gdata_link_get_uri (_link)); + } +} + static const gchar * get_content_type (void) { diff --git a/gdata/tests/tasks.c b/gdata/tests/tasks.c index 2e9a03ef..7ea4fd47 100644 --- a/gdata/tests/tasks.c +++ b/gdata/tests/tasks.c @@ -125,11 +125,11 @@ test_query_uri (void) "?updated-min=1970-01-01T01:53:09Z" "&max-results=10" "&maxResults=10" - "&updatedMin=1970-01-01T01:53:09Z" - "&completedMin=1970-01-01T01:34:38Z" - "&completedMax=1970-01-01T00:20:34Z" - "&dueMin=1970-01-01T00:39:05Z" - "&dueMax=1970-01-01T00:57:36Z" + "&updatedMin=1970-01-01T01:53:09.000001+00:00" + "&completedMin=1970-01-01T01:34:38.000001+00:00" + "&completedMax=1970-01-01T00:20:34.000001+00:00" + "&dueMin=1970-01-01T00:39:05.000001+00:00" + "&dueMax=1970-01-01T00:57:36.000001+00:00" "&showCompleted=true" "&showDeleted=true" "&showHidden=true"); @@ -153,11 +153,11 @@ test_query_uri (void) "?updated-min=1970-01-01T01:53:09Z" "&max-results=10" "&maxResults=10" - "&updatedMin=1970-01-01T01:53:09Z" - "&completedMin=1970-01-01T01:34:38Z" - "&completedMax=1970-01-01T00:20:34Z" - "&dueMin=1970-01-01T00:39:05Z" - "&dueMax=1970-01-01T00:57:36Z" + "&updatedMin=1970-01-01T01:53:09.000001+00:00" + "&completedMin=1970-01-01T01:34:38.000001+00:00" + "&completedMax=1970-01-01T00:20:34.000001+00:00" + "&dueMin=1970-01-01T00:39:05.000001+00:00" + "&dueMax=1970-01-01T00:57:36.000001+00:00" "&showCompleted=false" "&showDeleted=false" "&showHidden=false"); @@ -322,8 +322,8 @@ test_task_properties (void) "\"title\": \"some-other-title\"," "\"notes\": \"more-notes\"," "\"status\": \"completed\"," - "\"due\": \"2014-08-30T17:20:00Z\"," - "\"completed\": \"2014-08-30T17:20:00Z\"," + "\"due\": \"2014-08-30T17:20:00.000001+00:00\"," + "\"completed\": \"2014-08-30T17:20:00.000001+00:00\"," "\"deleted\": true," "\"hidden\": false" "}"); @@ -337,8 +337,8 @@ test_task_properties (void) "\"title\": \"some-other-title\"," "\"notes\": \"more-notes\"," "\"status\": \"completed\"," - "\"due\": \"2014-08-30T17:20:00Z\"," - "\"completed\": \"2014-08-30T17:20:00Z\"," + "\"due\": \"2014-08-30T17:20:00.000001+00:00\"," + "\"completed\": \"2014-08-30T17:20:00.000001+00:00\"," "\"deleted\": false," "\"hidden\": false" "}"); @@ -501,14 +501,14 @@ test_task_parser_normal (void) "\"id\": \"some-id\"," "\"etag\": \"some-etag\"," "\"title\": \"some-title \\\"with quotes\\\"\"," - "\"updated\": \"2014-08-30T19:40:00Z\"," + "\"updated\": \"2014-08-30T19:40:00.000001+00:00\"," "\"selfLink\": \"http://some-uri/\"," "\"parent\": \"some-parent-id\"," "\"position\": \"some-position\"," "\"notes\": \"Some notes!\"," "\"status\": \"needsAction\"," - "\"due\": \"2014-08-30T20:00:00Z\"," - "\"completed\": \"2014-08-30T20:10:05Z\"," + "\"due\": \"2014-08-30T20:00:00.000001+00:00\"," + "\"completed\": \"2014-08-30T20:10:05.000001+00:00\"," "\"deleted\": false," "\"hidden\": true," /* Unhandled for the moment: */ -- cgit v1.2.1