From 6d65a2e9b24e1367aba8c5de0b02a9356177c889 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 13 Sep 2020 14:56:04 +0200 Subject: [PATCH 01/16] Added folder for common files usable for all parts of GSuite --- gsuite_base/Readme.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 gsuite_base/Readme.md diff --git a/gsuite_base/Readme.md b/gsuite_base/Readme.md new file mode 100644 index 0000000..e69de29 From 46a103db289a3014b8c133fb7c83e3371adac51c Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 13 Sep 2020 15:31:19 +0200 Subject: [PATCH 02/16] Added folder for calendar --- calendar/Readme.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 calendar/Readme.md diff --git a/calendar/Readme.md b/calendar/Readme.md new file mode 100644 index 0000000..e69de29 From f8f943515d2694ea01c7c655af3ed0e78be5f9d2 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 20 Sep 2020 10:51:34 +0200 Subject: [PATCH 03/16] First version of Calendar API with some adjustments to sheet implemenation as a first step to a generalization --- calendar/test/eg_calendar_api.e | 88 +++++++ calendar/test/test.ecf | 43 ++++ calendar/test/test_calendar_api.e | 379 ++++++++++++++++++++++++++++++ sheets/src/eg_sheets_api.e | 10 +- sheets/test/application_flow.e | 13 +- sheets/test/test.ecf | 8 +- sheets/test/test_sheets_api.e | 12 +- 7 files changed, 538 insertions(+), 15 deletions(-) create mode 100644 calendar/test/eg_calendar_api.e create mode 100644 calendar/test/test.ecf create mode 100644 calendar/test/test_calendar_api.e diff --git a/calendar/test/eg_calendar_api.e b/calendar/test/eg_calendar_api.e new file mode 100644 index 0000000..e34545d --- /dev/null +++ b/calendar/test/eg_calendar_api.e @@ -0,0 +1,88 @@ +note + description: "Summary description for {EG_CALENDAR_API}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + EG_CALENDAR_API + +inherit + EG_SHEETS_API + rename + endpoint_sheets_url as endpoint_calendar_url + redefine + endpoint_calendar_url + end + +create + make + + feature list_calendars : detachable STRING + do + api_get_call ("https://www.googleapis.com/calendar/v3/users/me/calendarList" , Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + feature list_primary_calendar : detachable STRING + do + api_get_call ("https://www.googleapis.com/calendar/v3/calendars/primary" , Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + feature list_primary_calendar_events : detachable STRING + do + api_get_call ("https://www.googleapis.com/calendar/v3/calendars/primary/events" , Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + feature create_calendar( name_of_calendar : STRING) : detachable STRING + local + parameter_table : STRING_TABLE[STRING] + + do + create parameter_table.make (1) + parameter_table.put (name_of_calendar,"summary") + api_post_call ("https://www.googleapis.com/calendar/v3/calendars" , parameter_table , payload_create_calendar, Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + + + endpoint_calendar_url: STRING + do + Result := "https://www.googleapis.com" + end + + + payload_create_calendar: STRING + local + l_res: JSON_OBJECT + do + create l_res.make_with_capacity (5) + l_res.put_string ("BSharpABTODO", "summary") + Result := l_res.representation + end + + +end diff --git a/calendar/test/test.ecf b/calendar/test/test.ecf new file mode 100644 index 0000000..57f7959 --- /dev/null +++ b/calendar/test/test.ecf @@ -0,0 +1,43 @@ + + + + + /CVS$ + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e new file mode 100644 index 0000000..49e4746 --- /dev/null +++ b/calendar/test/test_calendar_api.e @@ -0,0 +1,379 @@ +note + description: "Summary description for {TEST_SHEETS_WITH_API_KEY}." + date: "$Date$" + revision: "$Revision$" + +class + TEST_CALENDAR_API + +inherit + + APPLICATION_FLOW + + redefine + Token_file_path_s, + google_auth_path_path_s + end + +create + make + +feature -- {NONE} + + make + do + -- TODO improve this code so we can select which integration test we want to run. + logger.write_information ("make-> ======================> Starting application") + + set_from_json_credentials_file_path (create {PATH}.make_from_string (CREDENTIALS_PATH)) + retrieve_access_token + + test_list_calendars + test_create_calendar +-- test_list_primary_calendar +-- test_list_primary_calendar_events + test_list_calendars + + end + + +feature -- Tests + + Token_file_path_s: STRING + do + Result := "/home/anders/token.access" + end + + google_auth_path_path_s: STRING + do + Result := "https://www.googleapis.com/auth/calendar" + end + + test_list_calendars + require + token_is_valid + local + l_esapi: EG_CALENDAR_API + do + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + create l_esapi.make (last_token.token) + if attached l_esapi.list_calendars as l_calendars then + if l_esapi.has_error then +-- debug ("test_create_sheet") + logger.write_error ("test_create_sheet-> Error" ) + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") +-- end + check + cannot_create_the_spreedsheet: False + end + else + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end +-- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end +-- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end +-- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end +-- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. +-- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") +-- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + + test_list_primary_calendar + require + token_is_valid + local + l_esapi: EG_CALENDAR_API + do + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + create l_esapi.make (last_token.token) + if attached l_esapi.list_primary_calendar as l_calendars then + if l_esapi.has_error then +-- debug ("test_create_sheet") + logger.write_error ("test_create_sheet-> Error" ) + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") +-- end + check + cannot_create_the_spreedsheet: False + end + else + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end +-- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end +-- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end +-- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end +-- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. +-- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") +-- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + + test_list_primary_calendar_events + require + token_is_valid + local + l_esapi: EG_CALENDAR_API + do + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + create l_esapi.make (last_token.token) + if attached l_esapi.list_primary_calendar_events as l_calendars then + if l_esapi.has_error then +-- debug ("test_create_sheet") + logger.write_error ("test_create_sheet-> Error" ) + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") +-- end + check + cannot_create_the_spreedsheet: False + end + else + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end +-- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end +-- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end +-- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end +-- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. +-- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") +-- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + + test_create_calendar + require + token_is_valid + local + l_esapi: EG_CALENDAR_API + do + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + create l_esapi.make (last_token.token) + if attached l_esapi.create_calendar("BSharpABTODO") as l_calendars then + if l_esapi.has_error then +-- debug ("test_create_sheet") + logger.write_error ("test_create_calendar-> Error" ) + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") +-- end + check + cannot_create_the_spreedsheet: False + end + else + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end +-- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end +-- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end +-- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end +-- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. +-- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") +-- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + + + + + test_get_sheet (a_sheet_id: attached like {EG_SHEETS_API}.spreadsheet_id) + local + l_esapi: EG_SHEETS_API + do +-- create l_esapi.make (last_token.token) +-- if attached l_esapi.get_from_id (a_sheet_id, Void) as l_spreedsheet_get_result then +-- if l_esapi.has_error then +---- debug ("test_create_sheet") +-- print ("test_create_sheet-> Error %N" ) +-- print ("test_create_sheet-> Error: msg:" + l_esapi.error_message) +-- print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") +-- print ("%N") +---- end +-- check +-- cannot_create_the_spreedsheet: False +-- end +-- else +-- check Json_Field_spreadsheetId: l_spreedsheet_get_result.has_substring ("spreadsheetId") end +-- check Json_Field_properties: l_spreedsheet_get_result.has_substring ("properties") end +-- check Json_Field_sheets: l_spreedsheet_get_result.has_substring ("sheets") end +-- check Json_Field_spreadsheetUrl: l_spreedsheet_get_result.has_substring ("spreadsheetUrl") end +-- -- developerMetadata and namedRanges are optional. +---- debug ("test_create_sheet") +-- logger.write_debug ("test_get_sheet-> success. Result:%N") +-- logger.write_debug (l_spreedsheet_get_result + "%N") +-- logger.write_debug ("test_get_sheet-> success. ") +---- end +---- else +---- check Json_Field_spreadsheetId: l_spreedsheet_get_result.has_substring ("spreadsheetId") end +---- check Json_Field_properties: l_spreedsheet_get_result.has_substring ("properties") end +---- check Json_Field_sheets: l_spreedsheet_get_result.has_substring ("sheets") end +---- check Json_Field_spreadsheetUrl: l_spreedsheet_get_result.has_substring ("spreadsheetUrl") end +---- -- developerMetadata and namedRanges are optional. +------ debug ("test_create_sheet") +---- logger.write_debug ("test_get_sheet-> success. Result:%N") +---- logger.write_debug (l_spreedsheet_get_result + "%N") +---- logger.write_debug ("test_get_sheet-> success. ") +------ end +---- end +---- else +---- -- Bad scope. no connection, etc +---- check Unexptected_Behavior: False end +-- end + end + + test_append_sheet (a_sheet_id: attached like {EG_SHEETS_API}.spreadsheet_id; a_data: STRING) + local + l_esapi: EG_SHEETS_API + l_range: STRING + do + create l_esapi.make (last_token.token) + l_range := "Sheet1" + "!A1:A" + + if attached l_esapi.append_with_id_raw (a_sheet_id, l_range, a_data) as l_spreedsheet_get_result then + if l_esapi.has_error then +-- debug ("test_create_sheet") + print ("test_append_sheet-> Error %N" ) + print ("test_append_sheet-> Error: msg:" + l_esapi.error_message) + print ("test_append_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") +-- end + check + cannot_create_the_spreedsheet: False + end + else + check Json_Field_spreadsheetId: l_spreedsheet_get_result.has_substring ("spreadsheetId") end + check Json_Field_properties: l_spreedsheet_get_result.has_substring ("properties") end + check Json_Field_sheets: l_spreedsheet_get_result.has_substring ("sheets") end + check Json_Field_spreadsheetUrl: l_spreedsheet_get_result.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. +-- debug ("test_create_sheet") + print ("test_append_sheet-> success. Result:%N") + print (l_spreedsheet_get_result + "%N") +-- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + + test_create_sheet_json + local + l_esapi: EG_SHEETS_JSON + do + create l_esapi.make (last_token.token) + end + + +feature {NONE} -- Implementations + + CREDENTIALS_PATH: STRING="/home/anders/credentials.json" -- get this file from https://console.developers.google.com/ + -- Credentials path to json file. + + + impl_append_post_data_sample: STRING + local + l_res: JSON_OBJECT + l_jsa_main, + l_jsa_line: JSON_ARRAY + j_array: JSON_ARRAY + +--{ +-- "range": string, +-- "majorDimension": enum (Dimension), +-- "values": [ +-- array +-- ] +--} +--// "values": [ +-- // [ +-- // "Item", +-- // "Cost" +-- // ], +-- // [ +-- // "Wheel", +-- // "$20.50" +-- // ], +-- // [ +-- // "Door", +-- // "$15" +-- // ], +-- // [ +-- // "Engine", +-- // "$100" +-- // ], +-- // [ +-- // "Totals", +-- // "$135.50" +-- // ] +-- // ] + + do + create l_res.make_with_capacity (5) + l_res.put_string ("Sheet1!A1:B5", "range") + l_res.put_string ("ROWS", "majorDimension") -- "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" + + create l_jsa_main.make (10) + + create j_array.make (1) + create l_jsa_line.make (2) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Item")) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Cost")) + j_array.add (l_jsa_line) + + create l_jsa_line.make (2) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Wheel")) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$20.50")) + j_array.add (l_jsa_line) + + create l_jsa_line.make (2) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Door")) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$15")) + j_array.add (l_jsa_line) + + create l_jsa_line.make (2) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Engine")) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$100")) + j_array.add (l_jsa_line) + + create l_jsa_line.make (2) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Totals")) + l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$135.50")) + j_array.add (l_jsa_line) + + + l_res.put (j_array, "values") + + Result := l_res.representation + logger.write_debug ("impl_append_body-> Result: '" + Result.out + "'") + end + +end diff --git a/sheets/src/eg_sheets_api.e b/sheets/src/eg_sheets_api.e index 3379197..2671f1a 100644 --- a/sheets/src/eg_sheets_api.e +++ b/sheets/src/eg_sheets_api.e @@ -62,7 +62,7 @@ feature -- Spreedsheets Operations then Result := l_body end - end + end get_from_id (a_spreadsheet_id: attached like spreadsheet_id; a_params: detachable EG_SPREADSHEET_PARAMETERS): detachable like last_response.body -- POST /spreadsheets/`a_spreadsheet_id' @@ -402,7 +402,7 @@ feature {NONE} -- Implementation require a_query_attached: a_query /= Void do - create Result.make_from_string (endpooint_sheets_url) + create Result.make_from_string (endpoint_sheets_url) Result.append ("/") Result.append (version) Result.append ("/") @@ -506,8 +506,10 @@ feature {NONE} -- Implementation feature -- Service Endpoint - endpooint_sheets_url: STRING = "https://sheets.googleapis.com" - -- base URL that specifies the network address of an API service. + endpoint_sheets_url: STRING + do + Result := "https://sheets.googleapis.com" -- base URL that specifies the network address of an API service. + end feature {NONE} -- Implementation diff --git a/sheets/test/application_flow.e b/sheets/test/application_flow.e index 0d879fd..13836fa 100644 --- a/sheets/test/application_flow.e +++ b/sheets/test/application_flow.e @@ -85,7 +85,7 @@ feature {NONE} -- Initialization create Result.make_empty create config.make_default (l_api_key, l_api_secret) config.set_callback ("urn:ietf:wg:oauth:2.0:oob") - config.set_scope ("https://www.googleapis.com/auth/spreadsheets") + config.set_scope ( google_auth_path_path_s ) create google api_service := google.create_service (config) logger.write_debug ("%N===Google OAuth Workflow ===%N") @@ -154,7 +154,16 @@ feature {NONE} -- Initialization feature -- Access - Token_file_path_s: STRING = "token.access" + Token_file_path_s: STRING + do + Result := "token.access" + end + + google_auth_path_path_s: STRING + do + Result := "https://www.googleapis.com/auth/spreadsheets" + end + feature -- Status Setting diff --git a/sheets/test/test.ecf b/sheets/test/test.ecf index 46d1006..5aa8d4e 100644 --- a/sheets/test/test.ecf +++ b/sheets/test/test.ecf @@ -1,5 +1,5 @@ - + /CVS$ @@ -7,7 +7,7 @@ /\.git$ /\.svn$ - @@ -24,7 +24,7 @@ - @@ -32,7 +32,7 @@ - diff --git a/sheets/test/test_sheets_api.e b/sheets/test/test_sheets_api.e index 9bf3199..1b3b87e 100644 --- a/sheets/test/test_sheets_api.e +++ b/sheets/test/test_sheets_api.e @@ -10,6 +10,7 @@ inherit APPLICATION_FLOW + create make @@ -20,13 +21,14 @@ feature -- {NONE} -- TODO improve this code so we can select which integration test we want to run. logger.write_information ("make-> ======================> Starting application") set_from_json_credentials_file_path (create {PATH}.make_from_string (credentials_path)) + retrieve_access_token test_create_sheet ---- test_get_sheet ("1v1N4nRa6mmLcP9rUuyQPiCnLuUcBQFDEC7E0CDg3ASI") --- test_append_sheet ("19cKCmQBWJoMePX0Iy6LueHRw0sS2bMcyP1Auzbkvj6M", impl_append_post_data_sample) --pg + test_append_sheet ("19cKCmQBWJoMePX0Iy6LueHRw0sS2bMcyP1Auzbkvj6M", impl_append_post_data_sample) --pg -- --test_append_sheet ("1j5CTkpgOc6Y5qgYdA_klZYjNhmN2KYocoZAdM4Y61tw") --jv ----- set_from_json_credentials_file_path (create {PATH}.make_from_string (CREDENTIALS_PATH)) +---- set_from_json_credentials_file_path (create {PATH}.make_from_string (CREDENTIALS_PATH)) -- retrieve_access_token -- test_get_sheet ("1v1N4nRa6mmLcP9rUuyQPiCnLuUcBQFDEC7E0CDg3ASI") end @@ -34,7 +36,8 @@ feature -- {NONE} feature -- Tests - test_create_sheet + + test_create_sheet require token_is_valid local @@ -151,11 +154,10 @@ feature -- Tests feature {NONE} -- Implementations - CREDENTIALS_PATH: STRING="credentials.json" -- get this file from https://console.developers.google.com/ + CREDENTIALS_PATH: STRING="credentials.json" -- get this file from https://console.developers.google.com/ -- Credentials path to json file. - impl_append_post_data_sample: STRING local l_res: JSON_OBJECT From 4ea51f79b2a185d4dfefe2c4e3532378dba28462 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 20 Sep 2020 12:23:49 +0200 Subject: [PATCH 04/16] Would appriociate with help to create the payload code for payload_create_calendar_event --- calendar/test/eg_calendar_api.e | 46 +++++++++++++++++++++++++++---- calendar/test/test_calendar_api.e | 7 +++-- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/calendar/test/eg_calendar_api.e b/calendar/test/eg_calendar_api.e index e34545d..e1d1f4d 100644 --- a/calendar/test/eg_calendar_api.e +++ b/calendar/test/eg_calendar_api.e @@ -52,13 +52,20 @@ create end feature create_calendar( name_of_calendar : STRING) : detachable STRING - local - parameter_table : STRING_TABLE[STRING] + do + api_post_call ("https://www.googleapis.com/calendar/v3/calendars" , Void , payload_create_calendar, Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + feature create_calendar_event( name_of_calendar : STRING; title_of_event : STRING) : detachable STRING do - create parameter_table.make (1) - parameter_table.put (name_of_calendar,"summary") - api_post_call ("https://www.googleapis.com/calendar/v3/calendars" , parameter_table , payload_create_calendar, Void) + api_post_call ("https://www.googleapis.com/calendar/v3/calendars/" + name_of_calendar + "/events", Void , payload_create_calendar_event, Void) if attached last_response as l_response and then attached l_response.body as l_body @@ -85,4 +92,33 @@ create end + payload_create_calendar_event: STRING + note + EIS:"name=calendar event", "src=https://developers.google.com/calendar/v3/reference/events#resource" + local + l_res: JSON_OBJECT + do + + create l_res.make_with_capacity (5) + -- Add the required parameters in the paylod: "start" and "end" + --https://developers.google.com/calendar/v3/reference/events/insert + +-- "start": { +-- "date": date, +-- "dateTime": datetime, +-- "timeZone": string +-- }, +-- "end": { +-- "date": date, +-- "dateTime": datetime, +-- "timeZone": string +-- } + + + --????????????? + + Result := l_res.representation + end + + end diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index 49e4746..ac4b16a 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -29,10 +29,13 @@ feature -- {NONE} retrieve_access_token test_list_calendars - test_create_calendar +-- test_create_calendar -- test_list_primary_calendar -- test_list_primary_calendar_events - test_list_calendars +-- test_list_calendars + + + end From 6b067099463e07ed9bf310953999fcd8a0b3c6f1 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 20 Sep 2020 19:45:58 +0200 Subject: [PATCH 05/16] Added calendar_event_payload class to show how my intentiion with the calendar API --- calendar/test/calendar_event_payload.e | 16 ++++++++++++++++ calendar/test/eg_calendar_api.e | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 calendar/test/calendar_event_payload.e diff --git a/calendar/test/calendar_event_payload.e b/calendar/test/calendar_event_payload.e new file mode 100644 index 0000000..38c857a --- /dev/null +++ b/calendar/test/calendar_event_payload.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {CALENDAR_EVENT_PAYLOD}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CALENDAR_EVENT_PAYLOAD + +feature + + start: detachable STRING + ending: detachable STRING + + +end diff --git a/calendar/test/eg_calendar_api.e b/calendar/test/eg_calendar_api.e index e1d1f4d..eadfe4b 100644 --- a/calendar/test/eg_calendar_api.e +++ b/calendar/test/eg_calendar_api.e @@ -63,7 +63,11 @@ create end - feature create_calendar_event( name_of_calendar : STRING; title_of_event : STRING) : detachable STRING + feature create_calendar_event( name_of_calendar : STRING; payload : CALENDAR_EVENT_PAYLOAD) : detachable STRING + require + start_date_exists: attached payload.start + ending_date_exists: attached payload.ending + do api_post_call ("https://www.googleapis.com/calendar/v3/calendars/" + name_of_calendar + "/events", Void , payload_create_calendar_event, Void) if From 052486d12267d4baad9c5dc69b92628bf6767177 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Fri, 25 Sep 2020 19:57:15 -0300 Subject: [PATCH 06/16] Extracted common code to gsuite_base library. Refactored calendar with src and test folders. Cleaned code, fixed code style. Updated GSheets to use the gsuite_base library. --- calendar/escalendar.ecf | 28 ++ calendar/src/calendar_event_payload.e | 16 + calendar/src/eg_calendar_api.e | 170 +++++++++ calendar/test/eg_calendar_api.e | 128 ------- calendar/test/test.ecf | 18 +- calendar/test/test_calendar_api.e | 338 ++++++----------- .../test => gsuite_base}/application_flow.e | 37 +- gsuite_base/eg_base.ecf | 31 ++ gsuite_base/eg_common_api.e | 359 ++++++++++++++++++ {sheets/src => gsuite_base}/logger/loggable.e | 0 sheets/esheets.ecf | 6 +- sheets/src/eg_sheets_api.e | 318 ++-------------- sheets/test/test.ecf | 2 +- 13 files changed, 786 insertions(+), 665 deletions(-) create mode 100644 calendar/escalendar.ecf create mode 100644 calendar/src/calendar_event_payload.e create mode 100644 calendar/src/eg_calendar_api.e delete mode 100644 calendar/test/eg_calendar_api.e rename {sheets/test => gsuite_base}/application_flow.e (92%) create mode 100644 gsuite_base/eg_base.ecf create mode 100644 gsuite_base/eg_common_api.e rename {sheets/src => gsuite_base}/logger/loggable.e (100%) diff --git a/calendar/escalendar.ecf b/calendar/escalendar.ecf new file mode 100644 index 0000000..88e5391 --- /dev/null +++ b/calendar/escalendar.ecf @@ -0,0 +1,28 @@ + + + + + + /CVS$ + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + + diff --git a/calendar/src/calendar_event_payload.e b/calendar/src/calendar_event_payload.e new file mode 100644 index 0000000..38c857a --- /dev/null +++ b/calendar/src/calendar_event_payload.e @@ -0,0 +1,16 @@ +note + description: "Summary description for {CALENDAR_EVENT_PAYLOD}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CALENDAR_EVENT_PAYLOAD + +feature + + start: detachable STRING + ending: detachable STRING + + +end diff --git a/calendar/src/eg_calendar_api.e b/calendar/src/eg_calendar_api.e new file mode 100644 index 0000000..ec2ca37 --- /dev/null +++ b/calendar/src/eg_calendar_api.e @@ -0,0 +1,170 @@ +note + description: "Summary description for {EG_CALENDAR_API}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + EG_CALENDAR_API + +inherit + EG_COMMON_API + +create + make + +feature {NONE} -- Initialization + + make (a_access_token: READABLE_STRING_32) + do + -- Using a code verifier + access_token := a_access_token + enable_version_3 + default_scope + end + + default_scope + do + create {ARRAYED_LIST [STRING_8]} scopes.make (5) + add_scope ("https://www.googleapis.com/auth/calendar") + end + + enable_version_3 + -- Enable Google Calendar version v3. + do + version := "v3" + ensure + version_set: version.same_string ("v3") + end + +feature -- Access + + list_calendars: detachable STRING + do + api_get_call (calendar_url("users/me/calendarList", Void), Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + list_primary_calendar: detachable STRING + do + api_get_call (calendar_url("calendars/primary", Void), Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + list_primary_calendar_events: detachable STRING + do + api_get_call (calendar_url ("calendars/primary/events", Void), Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + create_calendar (name_of_calendar: STRING): detachable STRING + do + api_post_call (calendar_url ("calendars", Void), Void, payload_create_calendar, Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + create_calendar_event (name_of_calendar: STRING; payload: CALENDAR_EVENT_PAYLOAD): detachable STRING + require + start_date_exists: attached payload.start + ending_date_exists: attached payload.ending + + do + api_post_call (calendar_url("calendars/" + name_of_calendar + "/events", Void), Void, payload_create_calendar_event, Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + +feature -- Calenader URL + + calendar_url (a_query: STRING; a_params: detachable STRING): STRING + -- Calenader url endpoint + --| TODO, check if a_params is really neeed. + note + eis: "name=Calendaer service endpoint", "src=https://developers.google.com/calendar/v3/reference", "protocol=uri" + require + a_query_attached: a_query /= Void + do + create Result.make_from_string (endpoint_url) + Result.append ("/") + Result.append (version) + Result.append ("/") + Result.append (a_query) + if attached a_params then + Result.append_character ('?') + Result.append (a_params) + end + ensure + Result_attached: Result /= Void + end + + +feature -- Access + + endpoint_url: STRING + -- + do + Result := "https://www.googleapis.com/calendar" + end + + payload_create_calendar: STRING + local + l_res: JSON_OBJECT + do + create l_res.make_with_capacity (5) + l_res.put_string ("BSharpABTODO", "summary") + Result := l_res.representation + end + + payload_create_calendar_event: STRING + note + EIS: "name=calendar event", "src=https://developers.google.com/calendar/v3/reference/events#resource" + local + l_res: JSON_OBJECT + do + + create l_res.make_with_capacity (5) + -- Add the required parameters in the paylod: "start" and "end" + --https://developers.google.com/calendar/v3/reference/events/insert + + -- "start": { + -- "date": date, + -- "dateTime": datetime, + -- "timeZone": string + -- }, + -- "end": { + -- "date": date, + -- "dateTime": datetime, + -- "timeZone": string + -- } + + --????????????? + + Result := l_res.representation + end + +end diff --git a/calendar/test/eg_calendar_api.e b/calendar/test/eg_calendar_api.e deleted file mode 100644 index eadfe4b..0000000 --- a/calendar/test/eg_calendar_api.e +++ /dev/null @@ -1,128 +0,0 @@ -note - description: "Summary description for {EG_CALENDAR_API}." - author: "" - date: "$Date$" - revision: "$Revision$" - -class - EG_CALENDAR_API - -inherit - EG_SHEETS_API - rename - endpoint_sheets_url as endpoint_calendar_url - redefine - endpoint_calendar_url - end - -create - make - - feature list_calendars : detachable STRING - do - api_get_call ("https://www.googleapis.com/calendar/v3/users/me/calendarList" , Void) - if - attached last_response as l_response and then - attached l_response.body as l_body - then - Result := l_body - end - end - - feature list_primary_calendar : detachable STRING - do - api_get_call ("https://www.googleapis.com/calendar/v3/calendars/primary" , Void) - if - attached last_response as l_response and then - attached l_response.body as l_body - then - Result := l_body - end - end - - feature list_primary_calendar_events : detachable STRING - do - api_get_call ("https://www.googleapis.com/calendar/v3/calendars/primary/events" , Void) - if - attached last_response as l_response and then - attached l_response.body as l_body - then - Result := l_body - end - end - - feature create_calendar( name_of_calendar : STRING) : detachable STRING - do - api_post_call ("https://www.googleapis.com/calendar/v3/calendars" , Void , payload_create_calendar, Void) - if - attached last_response as l_response and then - attached l_response.body as l_body - then - Result := l_body - end - end - - - feature create_calendar_event( name_of_calendar : STRING; payload : CALENDAR_EVENT_PAYLOAD) : detachable STRING - require - start_date_exists: attached payload.start - ending_date_exists: attached payload.ending - - do - api_post_call ("https://www.googleapis.com/calendar/v3/calendars/" + name_of_calendar + "/events", Void , payload_create_calendar_event, Void) - if - attached last_response as l_response and then - attached l_response.body as l_body - then - Result := l_body - end - end - - - - endpoint_calendar_url: STRING - do - Result := "https://www.googleapis.com" - end - - - payload_create_calendar: STRING - local - l_res: JSON_OBJECT - do - create l_res.make_with_capacity (5) - l_res.put_string ("BSharpABTODO", "summary") - Result := l_res.representation - end - - - payload_create_calendar_event: STRING - note - EIS:"name=calendar event", "src=https://developers.google.com/calendar/v3/reference/events#resource" - local - l_res: JSON_OBJECT - do - - create l_res.make_with_capacity (5) - -- Add the required parameters in the paylod: "start" and "end" - --https://developers.google.com/calendar/v3/reference/events/insert - --- "start": { --- "date": date, --- "dateTime": datetime, --- "timeZone": string --- }, --- "end": { --- "date": date, --- "dateTime": datetime, --- "timeZone": string --- } - - - --????????????? - - Result := l_res.representation - end - - -end diff --git a/calendar/test/test.ecf b/calendar/test/test.ecf index 57f7959..cb49343 100644 --- a/calendar/test/test.ecf +++ b/calendar/test/test.ecf @@ -1,5 +1,5 @@ - + /CVS$ @@ -17,27 +17,17 @@ - + - - + + - - - - - - - - diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index ac4b16a..2751d51 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -10,10 +10,10 @@ inherit APPLICATION_FLOW - redefine - Token_file_path_s, - google_auth_path_path_s - end + redefine +-- Token_file_path_s, + google_auth_path_path_s + end create make @@ -22,67 +22,63 @@ feature -- {NONE} make do - -- TODO improve this code so we can select which integration test we want to run. + -- TODO improve this code so we can select which integration test we want to run. logger.write_information ("make-> ======================> Starting application") set_from_json_credentials_file_path (create {PATH}.make_from_string (CREDENTIALS_PATH)) retrieve_access_token test_list_calendars --- test_create_calendar --- test_list_primary_calendar --- test_list_primary_calendar_events --- test_list_calendars - - - + -- test_create_calendar + -- test_list_primary_calendar + -- test_list_primary_calendar_events + -- test_list_calendars end - feature -- Tests - Token_file_path_s: STRING - do - Result := "/home/anders/token.access" - end +-- Token_file_path_s: STRING +-- do +-- Result := "/home/anders/token.access" +-- end google_auth_path_path_s: STRING - do - Result := "https://www.googleapis.com/auth/calendar" - end + do + Result := "https://www.googleapis.com/auth/calendar" + end - test_list_calendars + test_list_calendars require token_is_valid local l_esapi: EG_CALENDAR_API do - -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets create l_esapi.make (last_token.token) if attached l_esapi.list_calendars as l_calendars then if l_esapi.has_error then --- debug ("test_create_sheet") - logger.write_error ("test_create_sheet-> Error" ) - print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") - print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") - print ("%N") --- end + -- debug ("test_create_sheet") + logger.write_error ("test_create_sheet-> Error") + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") + -- end check cannot_create_the_spreedsheet: False end else - check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end --- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end --- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end --- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end --- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end + -- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end + -- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end + -- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end + -- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end -- developerMetadata and namedRanges are optional. --- debug ("test_create_sheet") - print ("Listed Calendars%N") - print (l_calendars) - print ("%N") --- end + -- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") + -- end end else -- Bad scope. no connection, etc @@ -90,37 +86,37 @@ feature -- Tests end end - test_list_primary_calendar + test_list_primary_calendar require token_is_valid local l_esapi: EG_CALENDAR_API do - -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets create l_esapi.make (last_token.token) if attached l_esapi.list_primary_calendar as l_calendars then if l_esapi.has_error then --- debug ("test_create_sheet") - logger.write_error ("test_create_sheet-> Error" ) - print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") - print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") - print ("%N") --- end + -- debug ("test_create_sheet") + logger.write_error ("test_create_sheet-> Error") + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") + -- end check cannot_create_the_spreedsheet: False end else - check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end --- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end --- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end --- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end --- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end + -- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end + -- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end + -- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end + -- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end -- developerMetadata and namedRanges are optional. --- debug ("test_create_sheet") - print ("Listed Calendars%N") - print (l_calendars) - print ("%N") --- end + -- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") + -- end end else -- Bad scope. no connection, etc @@ -128,37 +124,37 @@ feature -- Tests end end - test_list_primary_calendar_events + test_list_primary_calendar_events require token_is_valid local l_esapi: EG_CALENDAR_API do - -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets create l_esapi.make (last_token.token) if attached l_esapi.list_primary_calendar_events as l_calendars then if l_esapi.has_error then --- debug ("test_create_sheet") - logger.write_error ("test_create_sheet-> Error" ) - print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") - print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") - print ("%N") --- end + -- debug ("test_create_sheet") + logger.write_error ("test_create_sheet-> Error") + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") + -- end check cannot_create_the_spreedsheet: False end else - check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end --- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end --- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end --- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end --- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end + -- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end + -- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end + -- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end + -- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end -- developerMetadata and namedRanges are optional. --- debug ("test_create_sheet") - print ("Listed Calendars%N") - print (l_calendars) - print ("%N") --- end + -- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") + -- end end else -- Bad scope. no connection, etc @@ -166,121 +162,37 @@ feature -- Tests end end - test_create_calendar + test_create_calendar require token_is_valid local l_esapi: EG_CALENDAR_API do - -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets - create l_esapi.make (last_token.token) - if attached l_esapi.create_calendar("BSharpABTODO") as l_calendars then - if l_esapi.has_error then --- debug ("test_create_sheet") - logger.write_error ("test_create_calendar-> Error" ) - print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") - print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") - print ("%N") --- end - check - cannot_create_the_spreedsheet: False - end - else - check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end --- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end --- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end --- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end --- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end - -- developerMetadata and namedRanges are optional. --- debug ("test_create_sheet") - print ("Listed Calendars%N") - print (l_calendars) - print ("%N") --- end - end - else - -- Bad scope. no connection, etc - check Unexptected_Behavior: False end - end - end - - - - - test_get_sheet (a_sheet_id: attached like {EG_SHEETS_API}.spreadsheet_id) - local - l_esapi: EG_SHEETS_API - do --- create l_esapi.make (last_token.token) --- if attached l_esapi.get_from_id (a_sheet_id, Void) as l_spreedsheet_get_result then --- if l_esapi.has_error then ----- debug ("test_create_sheet") --- print ("test_create_sheet-> Error %N" ) --- print ("test_create_sheet-> Error: msg:" + l_esapi.error_message) --- print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") --- print ("%N") ----- end --- check --- cannot_create_the_spreedsheet: False --- end --- else --- check Json_Field_spreadsheetId: l_spreedsheet_get_result.has_substring ("spreadsheetId") end --- check Json_Field_properties: l_spreedsheet_get_result.has_substring ("properties") end --- check Json_Field_sheets: l_spreedsheet_get_result.has_substring ("sheets") end --- check Json_Field_spreadsheetUrl: l_spreedsheet_get_result.has_substring ("spreadsheetUrl") end --- -- developerMetadata and namedRanges are optional. ----- debug ("test_create_sheet") --- logger.write_debug ("test_get_sheet-> success. Result:%N") --- logger.write_debug (l_spreedsheet_get_result + "%N") --- logger.write_debug ("test_get_sheet-> success. ") ----- end ----- else ----- check Json_Field_spreadsheetId: l_spreedsheet_get_result.has_substring ("spreadsheetId") end ----- check Json_Field_properties: l_spreedsheet_get_result.has_substring ("properties") end ----- check Json_Field_sheets: l_spreedsheet_get_result.has_substring ("sheets") end ----- check Json_Field_spreadsheetUrl: l_spreedsheet_get_result.has_substring ("spreadsheetUrl") end ----- -- developerMetadata and namedRanges are optional. ------- debug ("test_create_sheet") ----- logger.write_debug ("test_get_sheet-> success. Result:%N") ----- logger.write_debug (l_spreedsheet_get_result + "%N") ----- logger.write_debug ("test_get_sheet-> success. ") ------- end ----- end ----- else ----- -- Bad scope. no connection, etc ----- check Unexptected_Behavior: False end --- end - end - - test_append_sheet (a_sheet_id: attached like {EG_SHEETS_API}.spreadsheet_id; a_data: STRING) - local - l_esapi: EG_SHEETS_API - l_range: STRING - do + -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets create l_esapi.make (last_token.token) - l_range := "Sheet1" + "!A1:A" - - if attached l_esapi.append_with_id_raw (a_sheet_id, l_range, a_data) as l_spreedsheet_get_result then + if attached l_esapi.create_calendar ("BSharpABTODO") as l_calendars then if l_esapi.has_error then --- debug ("test_create_sheet") - print ("test_append_sheet-> Error %N" ) - print ("test_append_sheet-> Error: msg:" + l_esapi.error_message) - print ("test_append_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") - print ("%N") --- end + -- debug ("test_create_sheet") + logger.write_error ("test_create_calendar-> Error") + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") + -- end check cannot_create_the_spreedsheet: False end else - check Json_Field_spreadsheetId: l_spreedsheet_get_result.has_substring ("spreadsheetId") end - check Json_Field_properties: l_spreedsheet_get_result.has_substring ("properties") end - check Json_Field_sheets: l_spreedsheet_get_result.has_substring ("sheets") end - check Json_Field_spreadsheetUrl: l_spreedsheet_get_result.has_substring ("spreadsheetUrl") end + check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end + -- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end + -- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end + -- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end + -- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end -- developerMetadata and namedRanges are optional. --- debug ("test_create_sheet") - print ("test_append_sheet-> success. Result:%N") - print (l_spreedsheet_get_result + "%N") --- end + -- debug ("test_create_sheet") + print ("Listed Calendars%N") + print (l_calendars) + print ("%N") + -- end end else -- Bad scope. no connection, etc @@ -288,56 +200,49 @@ feature -- Tests end end - test_create_sheet_json - local - l_esapi: EG_SHEETS_JSON - do - create l_esapi.make (last_token.token) - end - feature {NONE} -- Implementations - CREDENTIALS_PATH: STRING="/home/anders/credentials.json" -- get this file from https://console.developers.google.com/ +-- CREDENTIALS_PATH: STRING = "/home/anders/credentials.json" -- get this file from https://console.developers.google.com/ + CREDENTIALS_PATH: STRING = "credentials.json" -- get this file from https://console.developers.google.com/ -- Credentials path to json file. - impl_append_post_data_sample: STRING local l_res: JSON_OBJECT l_jsa_main, - l_jsa_line: JSON_ARRAY + l_jsa_line: JSON_ARRAY j_array: JSON_ARRAY ---{ --- "range": string, --- "majorDimension": enum (Dimension), --- "values": [ --- array --- ] ---} ---// "values": [ --- // [ --- // "Item", --- // "Cost" --- // ], --- // [ --- // "Wheel", --- // "$20.50" --- // ], --- // [ --- // "Door", --- // "$15" --- // ], --- // [ --- // "Engine", --- // "$100" --- // ], --- // [ --- // "Totals", --- // "$135.50" --- // ] --- // ] + --{ + -- "range": string, + -- "majorDimension": enum (Dimension), + -- "values": [ + -- array + -- ] + --} + --// "values": [ + -- // [ + -- // "Item", + -- // "Cost" + -- // ], + -- // [ + -- // "Wheel", + -- // "$20.50" + -- // ], + -- // [ + -- // "Door", + -- // "$15" + -- // ], + -- // [ + -- // "Engine", + -- // "$100" + -- // ], + -- // [ + -- // "Totals", + -- // "$135.50" + -- // ] + -- // ] do create l_res.make_with_capacity (5) @@ -372,7 +277,6 @@ feature {NONE} -- Implementations l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$135.50")) j_array.add (l_jsa_line) - l_res.put (j_array, "values") Result := l_res.representation diff --git a/sheets/test/application_flow.e b/gsuite_base/application_flow.e similarity index 92% rename from sheets/test/application_flow.e rename to gsuite_base/application_flow.e index 13836fa..4dcecd9 100644 --- a/sheets/test/application_flow.e +++ b/gsuite_base/application_flow.e @@ -11,7 +11,6 @@ inherit LOGGABLE - feature {NONE} -- Initialization retrieve_access_token @@ -37,7 +36,7 @@ feature {NONE} -- Initialization token: OAUTH_TOKEN l_date_file: DATE_TIME l_date_now: DATE_TIME - l_diff: INTEGER_64 + l_diff: INTEGER_64 do create {PLAIN_TEXT_FILE} file.make_with_name (Token_file_path_s) if file.exists then @@ -81,11 +80,11 @@ feature {NONE} -- Initialization attached api_key as l_api_key attached api_secret as l_api_secret then - logger.write_debug ("get_token_from_url-> api_key:'" + l_api_key + "' secret:'" + l_api_secret + "'" ) + logger.write_debug ("get_token_from_url-> api_key:'" + l_api_key + "' secret:'" + l_api_secret + "'") create Result.make_empty create config.make_default (l_api_key, l_api_secret) config.set_callback ("urn:ietf:wg:oauth:2.0:oob") - config.set_scope ( google_auth_path_path_s ) + config.set_scope (google_auth_path_path_s) create google api_service := google.create_service (config) logger.write_debug ("%N===Google OAuth Workflow ===%N") @@ -112,10 +111,10 @@ feature {NONE} -- Initialization refresh_access_token (a_token: OAUTH_TOKEN): OAUTH_TOKEN -- https://developers.google.com/identity/protocols/oauth2/limited-input-device#offline - --client_id=your_client_id& - --client_secret=your_client_secret& - --refresh_token=refresh_token& - --grant_type=refresh_token + --client_id=your_client_id& + --client_secret=your_client_secret& + --refresh_token=refresh_token& + --grant_type=refresh_token require attached api_key attached api_secret @@ -130,10 +129,10 @@ feature {NONE} -- Initialization attached api_key as l_api_key attached api_secret as l_api_secret then - logger.write_debug ("refresh_access_token-> api_key:'" + l_api_key + "' secret:'" + l_api_secret + "'" ) + logger.write_debug ("refresh_access_token-> api_key:'" + l_api_key + "' secret:'" + l_api_secret + "'") create Result.make_empty create google - create request.make ("POST", google.access_token_endpoint ) + create request.make ("POST", google.access_token_endpoint) request.add_body_parameter ("client_id", l_api_key) request.add_body_parameter ("client_secret", l_api_secret) request.add_body_parameter ("refresh_token", if attached a_token.refresh_token as l_token then l_token else "" end) @@ -155,15 +154,14 @@ feature {NONE} -- Initialization feature -- Access Token_file_path_s: STRING - do - Result := "token.access" - end + do + Result := "token.access" + end google_auth_path_path_s: STRING - do - Result := "https://www.googleapis.com/auth/spreadsheets" - end - + do + Result := "https://www.googleapis.com/auth/spreadsheets" + end feature -- Status Setting @@ -186,9 +184,9 @@ feature -- Status Setting check valid_main_object: attached {JSON_OBJECT} l_json_parser.parsed_json_value as l_main_json_o then + -- Installed check - valid_installed: attached {JSON_OBJECT} l_main_json_o.item ("installed") as l_installed_jso - then + valid_installed: attached {JSON_OBJECT} l_main_json_o.item ("installed") as l_installed_jso then check has_client_id: attached {JSON_STRING} l_installed_jso.item ("client_id") as l_client_id_js_s then @@ -269,4 +267,5 @@ feature {NONE} -- Implementation api_key: detachable STRING api_secret: detachable STRING empty_token: detachable OAUTH_TOKEN + end diff --git a/gsuite_base/eg_base.ecf b/gsuite_base/eg_base.ecf new file mode 100644 index 0000000..1adaa04 --- /dev/null +++ b/gsuite_base/eg_base.ecf @@ -0,0 +1,31 @@ + + + + + + /CVS$ + /EIFGENs$ + /\.git$ + /\.svn$ + + + + + + + + + + + + + + + + + + + + diff --git a/gsuite_base/eg_common_api.e b/gsuite_base/eg_common_api.e new file mode 100644 index 0000000..fd635cd --- /dev/null +++ b/gsuite_base/eg_common_api.e @@ -0,0 +1,359 @@ +note + description: "Common abstraction to access (read/write Google API data)" + date: "$Date$" + revision: "$Revision$" + +deferred class + EG_COMMON_API + +inherit + + LOGGABLE + +feature -- Reset + + reset + do + create access_token.make_empty + end + +feature -- Access + + access_token: STRING_32 + -- Google OAuth2 access token. + + http_status: INTEGER + -- Contains the last HTTP status code returned. + + last_api_call: detachable STRING + -- Contains the last API call. + + last_response: detachable OAUTH_RESPONSE + -- Cointains the last API response. + + version: STRING_8 + -- Google API version. + + scopes: LIST [STRING_8] + --Lists of Authorization Scopes. + +feature -- Scopes + + add_scope (a_scope: STRING_8) + -- Add an scope `a_scope` to the list of scopes. + do + scopes.force (a_scope) + end + + clear_scopes + -- Remove all items. + do + scopes.wipe_out + ensure + scopes.is_empty + end + +feature -- Query Parameters Factory + + query_parameters (a_params: detachable STRING_TABLE [STRING] ): detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]] + -- @JV please add a call example + local + l_result: like query_parameters + l_tuple : like query_parameters.item + i: INTEGER + do + if attached a_params then + i := 1 + create l_result.make_filled (Void, 1, a_params.count) + across a_params as ic + loop + create l_tuple.default_create + l_tuple.put (ic.key, 1) + l_tuple.put (ic.item, 2) + l_result.force (l_tuple, i) + i := i + 1 + end + Result := l_result + end + end + +feature -- Error Report + + parse_last_response + require + attached last_response + local + l_json_parser: JSON_PARSER + do + check + attached last_response as l_response + then + if l_response.status = {HTTP_STATUS_CODE}.unauthorized then + logger.write_error ("parse_last_response->Unauthorized status, review your authorization credentials") + end + if attached l_response.body as l_body then + logger.write_debug ("parse_last_response->body:" + l_body) + create l_json_parser.make_with_string (l_body) + l_json_parser.parse_content + if l_json_parser.is_valid then + if attached {JSON_OBJECT} l_json_parser.parsed_json_value as l_main_jso then + if attached {JSON_OBJECT} l_main_jso.item ("error") as l_error_jso then + if attached {JSON_NUMBER} l_error_jso.item ("code") as l_jso then + print ("parse_last_response-> error code:" + l_jso.representation + "%N") + end + if attached {JSON_STRING} l_error_jso.item ("message") as l_jso then + print ("parse_last_response-> error message:" + l_jso.unescaped_string_8 + "%N") + end + if attached {JSON_STRING} l_error_jso.item ("status") as l_jso then + print ("parse_last_response-> error status:" + l_jso.unescaped_string_8 + "%N") + end + end + end + else + print ("parse_last_response-> Error: Invalid json body content:" + l_body + "%N") + end + end + end + end + + has_error: BOOLEAN + -- Last api call raise an error? + do + if attached last_response as l_response then + Result := l_response.status /= 200 + else + Result := False + end + end + + error_message: STRING + -- Last api call error message. + require + has_error: has_error + do + if + attached last_response as l_response + then + if + attached l_response.error_message as l_error_message + then + Result := l_error_message + else + Result := l_response.status.out + end + else + Result := "Unknown Error" + end + end + +feature {NONE} -- Implementation + + api_post_call (a_api_url: STRING; a_query_params: detachable STRING_TABLE [STRING]; a_payload: detachable STRING; a_upload_data: detachable TUPLE[data:PATH; content_type: STRING]) + note + eis: "name=payload_body", "src=https://tools.ietf.org/html/draft-ietf-httpbis-p3-payload-14#section-3.2", "protocol=https://tools.ietf.org/html/draft-ietf-httpbis-p3-payload-14#section-3.2" + -- POST REST API call for `a_api_url' + do + internal_api_call (a_api_url, "POST", a_query_params, a_payload, a_upload_data) + end + + api_delete_call (a_api_url: STRING; a_query_params: detachable STRING_TABLE [STRING]) + -- DELETE REST API call for `a_api_url' + do + internal_api_call (a_api_url, "DELETE", a_query_params, Void, Void) + end + + api_get_call (a_api_url: STRING; a_query_params: detachable STRING_TABLE [STRING]) + -- GET REST API call for `a_api_url' + do + internal_api_call (a_api_url, "GET", a_query_params, Void, Void) + end + + internal_api_call (a_api_url: STRING; a_method: STRING; a_query_params: detachable STRING_TABLE [STRING]; a_payload: detachable STRING; a_upload_data: detachable TUPLE[filename:PATH; content_type: STRING]) + note + EIS:"name=access token", "src=https://developers.google.com/identity/protocols/oauth2", "protocol=uri" + local + request: OAUTH_REQUEST + l_access_token: detachable OAUTH_TOKEN + api_service: OAUTH_20_SERVICE + config: OAUTH_CONFIG + do + logger.write_debug ("internal_api_call-> a_api_url:" + a_api_url + " method:" + a_method) + -- TODO improve this, so we can check the required scopes before we + -- do an api call. + -- TODO add a class with the valid scopes. + create config.make_default ("", "") + + -- Add scopes + if scopes.is_empty then + -- Don't add scopes if the list is empty. + else + config.set_scope (build_scope) + end + + -- Initialization + + create api_service.make (create {OAUTH_20_GOOGLE_API}, config) + --| TODO improve cypress service creation procedure to make configuration optional. + + --| TODO rewrite prints as logs + logger.write_debug ("%N===Google OAuth Workflow using OAuth access token for the owner of the application ===%N") + + -- Create the access token that will identifies the user making the request. + create l_access_token.make_token_secret (access_token, "NOT_NEEDED") + --| Todo improve access_token to create a token without a secret. + check attached l_access_token as ll_access_token then + logger.write_information ("internal_api_call->Got the Access Token:" + ll_access_token.token); + + --Now let's go and check if the request is signed correcty + logger.write_information ("internal_api_call->Now we're going to verify our credentials...%N"); + -- Build the request and authorize it with OAuth. + create request.make (a_method, a_api_url) + + -- Workaorund to make it work with Google API + -- in other case it return HTTP 411 Length Required. + -- https://tools.ietf.org/html/rfc7231#section-6.5.10 + -- + -- + -- https://tools.ietf.org/html/rfc7230#section-3.3.2 + -- + upload_data (a_method, request, a_upload_data) + add_parameters (a_method, request, a_query_params) + -- adding payload + if attached a_payload then + request.add_header ("Content-length", a_payload.count.out) + request.add_header ("Content-Type", "application/json; charset=UTF-8") + request.add_payload (a_payload) + else + request.add_header ("Content-length", "0") + end + + api_service.sign_request (ll_access_token, request) + + logger.write_debug ("internal_api_call->uri:'" + request.uri + "'") + if attached request.upload_file as l_s then + logger.write_debug ("internal_api_call->upload file:'" + l_s.out + "'") + end + if attached {OAUTH_RESPONSE} request.execute as l_response then + last_response := l_response + end + end + last_api_call := a_api_url.string + end + + + url (a_base_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]]): STRING + -- url for `a_base_url' and `a_parameters' + require + a_base_url_attached: a_base_url /= Void + do + create Result.make_from_string (a_base_url) + append_parameters_to_url (Result, a_parameters) + end + + append_parameters_to_url (a_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]]) + -- Append parameters `a_parameters' to `a_url' + require + a_url_attached: a_url /= Void + local + i: INTEGER + l_first_param: BOOLEAN + do + if a_parameters /= Void and then a_parameters.count > 0 then + if a_url.index_of ('?', 1) > 0 then + l_first_param := False + elseif a_url.index_of ('&', 1) > 0 then + l_first_param := False + else + l_first_param := True + end + from + i := a_parameters.lower + until + i > a_parameters.upper + loop + if attached a_parameters[i] as a_param then + if l_first_param then + a_url.append_character ('?') + else + a_url.append_character ('&') + end + a_url.append_string (a_param.name) + a_url.append_character ('=') + a_url.append_string (a_param.value) + l_first_param := False + end + i := i + 1 + end + end + end + + add_parameters (a_method: STRING; request: OAUTH_REQUEST; a_params: detachable STRING_TABLE [STRING]) + -- add parameters 'a_params' (with key, value) to the oauth request 'request'. + --| at the moment all params are added to the query_string. + do + --| TODO check if we need to call add_body_parameters if the method is PUT or POST + add_query_parameters (request, a_params) + end + + add_query_parameters (request:OAUTH_REQUEST; a_params: detachable STRING_TABLE [STRING]) + do + if attached a_params then + across a_params as ic + loop + request.add_query_string_parameter (ic.key.as_string_8, ic.item) + end + end + end + + add_body_parameters (request:OAUTH_REQUEST; a_params: detachable STRING_TABLE [STRING]) + do + if attached a_params then + across a_params as ic + loop + request.add_body_parameter (ic.key.as_string_8, ic.item) + end + end + end + + upload_data (a_method: STRING; request:OAUTH_REQUEST; a_upload_data: detachable TUPLE[file_name:PATH; content_type: STRING]) + local + l_raw_file: RAW_FILE + do + if a_method.is_case_insensitive_equal_general ("POST") and then attached a_upload_data as l_upload_data then + create l_raw_file.make_open_read (l_upload_data.file_name.absolute_path.name) + if l_raw_file.exists then + logger.write_debug ("upload_data-> Content-type: '" + l_upload_data.content_type + "'") + logger.write_debug ("upload_data-> upload file name: '" + l_upload_data.file_name.absolute_path.name.out + "'") + request.add_header ("Content-Type", l_upload_data.content_type) + request.set_upload_filename (l_upload_data.file_name.absolute_path.name) + request.add_form_parameter("source", l_upload_data.file_name.name.as_string_32) + end + end + end + + + build_scope: STRING + -- Create an string as list of space- delimited, case-sensitive strings. + -- https://tools.ietf.org/html/rfc6749#section-3.3 + do + if scopes.is_empty then + Result := "" + else + Result := "" + across scopes as ic loop + Result.append (ic.item) + Result.append_character (' ') + end + Result.adjust + end + end + +feature -- Service Endpoint + + endpoint_url: STRING + -- base URL that specifies the network address of an API service. + deferred + end + +end + diff --git a/sheets/src/logger/loggable.e b/gsuite_base/logger/loggable.e similarity index 100% rename from sheets/src/logger/loggable.e rename to gsuite_base/logger/loggable.e diff --git a/sheets/esheets.ecf b/sheets/esheets.ecf index ddf095d..a2c5b8d 100644 --- a/sheets/esheets.ecf +++ b/sheets/esheets.ecf @@ -18,13 +18,11 @@ - - - - + + diff --git a/sheets/src/eg_sheets_api.e b/sheets/src/eg_sheets_api.e index 2671f1a..d8ddef4 100644 --- a/sheets/src/eg_sheets_api.e +++ b/sheets/src/eg_sheets_api.e @@ -5,8 +5,13 @@ note class EG_SHEETS_API + inherit - LOGGABLE + + EG_COMMON_API + rename + endpoint_url as endpoint_sheets_url + end create make @@ -18,33 +23,17 @@ feature {NONE} -- Initialization -- Using a code verifier access_token := a_access_token enable_version_4 + default_scope end -feature -- Reset - - reset + default_scope do - create access_token.make_empty + create {ARRAYED_LIST [STRING_8]} scopes.make (5) + add_scope ("https://www.googleapis.com/auth/spreadsheets") end -feature -- Access - - access_token: STRING_32 - -- Google OAuth2 access token. - - http_status: INTEGER - -- Contains the last HTTP status code returned. - - last_api_call: detachable STRING - -- Contains the last API call. - - last_response: detachable OAUTH_RESPONSE - -- Cointains the last API response. - - version: STRING_8 - -- Google Sheets version - feature -- Spreedsheets + spreadsheet_id: detachable STRING @@ -211,189 +200,7 @@ feature -- Spreedsheets Operations end end -feature -- Parameters Factory - - parameters (a_params: detachable STRING_TABLE [STRING] ): detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]] - -- @JV please add a call example - local - l_result: like parameters - l_tuple : like parameters.item - i: INTEGER - do - if attached a_params then - i := 1 - create l_result.make_filled (Void, 1, a_params.count) - across a_params as ic - loop - create l_tuple.default_create - l_tuple.put (ic.key, 1) - l_tuple.put (ic.item, 2) - l_result.force (l_tuple, i) - i := i + 1 - end - Result := l_result - end - end - -feature -- Error Report - - parse_last_response - require - attached last_response - local - l_json_parser: JSON_PARSER - do - check - attached last_response as l_response - then - if l_response.status = {HTTP_STATUS_CODE}.unauthorized then - logger.write_error ("parse_last_response->Unauthorized status, review your authorization credentials") - end - if attached l_response.body as l_body then - logger.write_debug ("parse_last_response->body:" + l_body) - create l_json_parser.make_with_string (l_body) - l_json_parser.parse_content - if l_json_parser.is_valid then - if attached {JSON_OBJECT} l_json_parser.parsed_json_value as l_main_jso then - if attached {JSON_OBJECT} l_main_jso.item ("error") as l_error_jso then - if attached {JSON_NUMBER} l_error_jso.item ("code") as l_jso then - print ("parse_last_response-> error code:" + l_jso.representation + "%N") - end - if attached {JSON_STRING} l_error_jso.item ("message") as l_jso then - print ("parse_last_response-> error message:" + l_jso.unescaped_string_8 + "%N") - end - if attached {JSON_STRING} l_error_jso.item ("status") as l_jso then - print ("parse_last_response-> error status:" + l_jso.unescaped_string_8 + "%N") - end - end - end - else - print ("parse_last_response-> Error: Invalid json body content:" + l_body + "%N") - end - end - end - end - - has_error: BOOLEAN - -- Last api call raise an error? - do - if attached last_response as l_response then - Result := l_response.status /= 200 - else - Result := False - end - end - - error_message: STRING - -- Last api call error message. - require - has_error: has_error - do - if - attached last_response as l_response - then - if - attached l_response.error_message as l_error_message - then - Result := l_error_message - else - Result := l_response.status.out - end - else - Result := "Unknown Error" - end - end - -feature -- Versions - - enable_version_4 - -- Enable Google sheets version v4. - do - version := "v4" - ensure - version_set: version.same_string ("v4") - end - -feature {NONE} -- Implementation - - api_post_call (a_api_url: STRING; a_params: detachable STRING_TABLE [STRING]; a_payload: detachable STRING; a_upload_data: detachable TUPLE[data:PATH; content_type: STRING]) - -- POST REST API call for `a_api_url' - do - internal_api_call (a_api_url, "POST", a_params, a_payload, a_upload_data) - end - - api_delete_call (a_api_url: STRING; a_params: detachable STRING_TABLE [STRING]) - -- DELETE REST API call for `a_api_url' - do - internal_api_call (a_api_url, "DELETE", a_params, Void, Void) - end - - api_get_call (a_api_url: STRING; a_params: detachable STRING_TABLE [STRING]) - -- GET REST API call for `a_api_url' - do - internal_api_call (a_api_url, "GET", a_params, Void, Void) - end - - internal_api_call (a_api_url: STRING; a_method: STRING; a_params: detachable STRING_TABLE [STRING]; a_payload: detachable STRING; a_upload_data: detachable TUPLE[filename:PATH; content_type: STRING]) - note - EIS:"name=access token", "src=https://developers.google.com/identity/protocols/oauth2", "protocol=uri" - local - request: OAUTH_REQUEST - l_access_token: detachable OAUTH_TOKEN - api_service: OAUTH_20_SERVICE - config: OAUTH_CONFIG - do - logger.write_debug ("internal_api_call-> a_api_url:" + a_api_url + " method:" + a_method) - -- TODO improve this, so we can check the required scopes before we - -- do an api call. - -- TODO add a class with the valid scopes. - create config.make_default ("", "") - config.set_scope ("https://www.googleapis.com/auth/spreadsheets") - - -- Initialization - - create api_service.make (create {OAUTH_20_GOOGLE_API}, config) - --| TODO improve cypress service creation procedure to make configuration optional. - - --| TODO rewrite prints as logs - logger.write_debug ("%N===Google OAuth Workflow using OAuth access token for the owner of the application ===%N") - - -- Create the access token that will identifies the user making the request. - create l_access_token.make_token_secret (access_token, "NOT_NEEDED") - --| Todo improve access_token to create a token without a secret. - check attached l_access_token as ll_access_token then - logger.write_information ("internal_api_call->Got the Access Token:" + ll_access_token.token); - - --Now let's go and check if the request is signed correcty - logger.write_information ("internal_api_call->Now we're going to verify our credentials...%N"); - -- Build the request and authorize it with OAuth. - create request.make (a_method, a_api_url) - -- Workaorund to make it work with Google API - -- in other case it return HTTP 411 Length Required. - -- Todo check. - upload_data (a_method, request, a_upload_data) - add_parameters (a_method, request, a_params) - -- adding payload - if attached a_payload then - request.add_header ("Content-length", a_payload.count.out) - request.add_header ("Content-Type", "application/json; charset=UTF-8") - request.add_payload (a_payload) - else - request.add_header ("Content-length", "0") - end - - api_service.sign_request (ll_access_token, request) - - logger.write_debug ("internal_api_call->uri:'" + request.uri + "'") - if attached request.upload_file as l_s then - logger.write_debug ("internal_api_call->upload file:'" + l_s.out + "'") - end - if attached {OAUTH_RESPONSE} request.execute as l_response then - last_response := l_response - end - end - last_api_call := a_api_url.string - end +feature -- SpreedSheet URL sheets_url (a_query: STRING; a_params: detachable STRING): STRING -- Sheet url endpoint @@ -415,101 +222,48 @@ feature {NONE} -- Implementation Result_attached: Result /= Void end - url (a_base_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]]): STRING - -- url for `a_base_url' and `a_parameters' - require - a_base_url_attached: a_base_url /= Void - do - create Result.make_from_string (a_base_url) - append_parameters_to_url (Result, a_parameters) - end +feature -- Parameters Factory - append_parameters_to_url (a_url: STRING; a_parameters: detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]]) - -- Append parameters `a_parameters' to `a_url' - require - a_url_attached: a_url /= Void + parameters (a_params: detachable STRING_TABLE [STRING] ): detachable ARRAY [detachable TUPLE [name: STRING; value: STRING]] + -- @JV please add a call example local + l_result: like parameters + l_tuple : like parameters.item i: INTEGER - l_first_param: BOOLEAN - do - if a_parameters /= Void and then a_parameters.count > 0 then - if a_url.index_of ('?', 1) > 0 then - l_first_param := False - elseif a_url.index_of ('&', 1) > 0 then - l_first_param := False - else - l_first_param := True - end - from - i := a_parameters.lower - until - i > a_parameters.upper - loop - if attached a_parameters[i] as a_param then - if l_first_param then - a_url.append_character ('?') - else - a_url.append_character ('&') - end - a_url.append_string (a_param.name) - a_url.append_character ('=') - a_url.append_string (a_param.value) - l_first_param := False - end - i := i + 1 - end - end - end - - add_parameters (a_method: STRING; request:OAUTH_REQUEST; a_params: detachable STRING_TABLE [STRING]) - -- add parameters 'a_params' (with key, value) to the oauth request 'request'. - --| at the moment all params are added to the query_string. - do - add_query_parameters (request, a_params) - end - - add_query_parameters (request:OAUTH_REQUEST; a_params: detachable STRING_TABLE [STRING]) do if attached a_params then + i := 1 + create l_result.make_filled (Void, 1, a_params.count) across a_params as ic loop - request.add_query_string_parameter (ic.key.as_string_8, ic.item) + create l_tuple.default_create + l_tuple.put (ic.key, 1) + l_tuple.put (ic.item, 2) + l_result.force (l_tuple, i) + i := i + 1 end + Result := l_result end end - add_body_parameters (request:OAUTH_REQUEST; a_params: detachable STRING_TABLE [STRING]) - do - if attached a_params then - across a_params as ic - loop - request.add_body_parameter (ic.key.as_string_8, ic.item) - end - end - end +feature -- Versions - upload_data (a_method: STRING; request:OAUTH_REQUEST; a_upload_data: detachable TUPLE[file_name:PATH; content_type: STRING]) - local - l_raw_file: RAW_FILE + enable_version_4 + -- Enable Google sheets version v4. do - if a_method.is_case_insensitive_equal_general ("POST") and then attached a_upload_data as l_upload_data then - create l_raw_file.make_open_read (l_upload_data.file_name.absolute_path.name) - if l_raw_file.exists then - logger.write_debug ("upload_data-> Content-type: '" + l_upload_data.content_type + "'") - logger.write_debug ("upload_data-> upload file name: '" + l_upload_data.file_name.absolute_path.name.out + "'") - request.add_header ("Content-Type", l_upload_data.content_type) - request.set_upload_filename (l_upload_data.file_name.absolute_path.name) - request.add_form_parameter("source", l_upload_data.file_name.name.as_string_32) - end - end + version := "v4" + ensure + version_set: version.same_string ("v4") end + feature -- Service Endpoint endpoint_sheets_url: STRING - do - Result := "https://sheets.googleapis.com" -- base URL that specifies the network address of an API service. - end + -- + do + Result := "https://sheets.googleapis.com" + end feature {NONE} -- Implementation diff --git a/sheets/test/test.ecf b/sheets/test/test.ecf index 5aa8d4e..743dea7 100644 --- a/sheets/test/test.ecf +++ b/sheets/test/test.ecf @@ -20,7 +20,7 @@ - + From 5b560e044b4effca3dca98d824b6f3bad43a96b0 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Tue, 8 Dec 2020 17:19:16 +0100 Subject: [PATCH 07/16] Added payload creation --- calendar/escalendar.ecf | 8 +- calendar/src/calendar_date.e | 35 ++++++++ calendar/src/calendar_date_payload.e | 102 +++++++++++++++++++++ calendar/src/calendar_event.e | 28 ++++++ calendar/src/calendar_event_payload.e | 71 ++++++++++++++- calendar/src/eg_calendar_api.e | 8 +- calendar/test/calendar_event_payload.e | 16 ---- calendar/test/calendar_test_set.e | 119 +++++++++++++++++++++++++ calendar/test/test.ecf | 17 ++-- calendar/test/test_calendar_api.e | 16 ++-- 10 files changed, 378 insertions(+), 42 deletions(-) create mode 100644 calendar/src/calendar_date.e create mode 100644 calendar/src/calendar_date_payload.e create mode 100644 calendar/src/calendar_event.e delete mode 100644 calendar/test/calendar_event_payload.e create mode 100644 calendar/test/calendar_test_set.e diff --git a/calendar/escalendar.ecf b/calendar/escalendar.ecf index 88e5391..a8b847d 100644 --- a/calendar/escalendar.ecf +++ b/calendar/escalendar.ecf @@ -1,5 +1,5 @@ - + @@ -8,20 +8,22 @@ /\.git$ /\.svn$ - - + + + diff --git a/calendar/src/calendar_date.e b/calendar/src/calendar_date.e new file mode 100644 index 0000000..a19d889 --- /dev/null +++ b/calendar/src/calendar_date.e @@ -0,0 +1,35 @@ +note + description: "Summary description for {CALENDAR_DATE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CALENDAR_DATE + + create + make + + feature + + make(d:DATE; dt: DATE_TIME; tz: STRING) +local + tools :DATE_TIME_TOOLS + do + a_date := d + + + + + + a_date_time := dt + a_time_zone := tz + + end + + a_date:DATE + a_date_time : DATE_TIME + a_time_zone : STRING + + +end diff --git a/calendar/src/calendar_date_payload.e b/calendar/src/calendar_date_payload.e new file mode 100644 index 0000000..e492cbc --- /dev/null +++ b/calendar/src/calendar_date_payload.e @@ -0,0 +1,102 @@ +note + description: "Summary description for {CALENDAR_START_PAYLOAD}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CALENDAR_DATE_PAYLOAD + + inherit + JSON_SERIALIZABLE + undefine + default_create + redefine + json_out, + eiffel_date_to_json_string, + eiffel_date_time_to_json_string + end + +create + make_with_date, + default_create + + +feature + +make_with_date(d: CALENDAR_DATE) +do + date := d.a_date + datetime := d.a_date_time + timezone := d.a_time_zone + end + + +default_create +do + create date.make_now + create datetime.make_now + create timezone.make_empty + end + + date: DATE + -- What is the `date' of the Event? + attribute + create Result.make_now + end + + datetime: DATE_TIME + -- What is the `datetime' of the Event? + attribute + create Result.make_now + end + + timeZone: STRING + -- What `timezone' is the Event in? + attribute + create Result.make_empty + end +feature -- Implementation + + eiffel_date_to_json_string (a_key: STRING; a_date: DATE): JSON_STRING + -- Convert `a_date' to JSON_STRING with `a_key' + do + create Result.make_from_string_32 (a_date.formatted_out ("YYYY-[0]MM-[0]DD")) + end + + + eiffel_date_time_to_json_string (a_key: STRING; a_date_time: DATE_TIME): JSON_STRING + -- Convert `a_date_time' to JSON_STRING with `a_key' + do + create Result.make_from_string_32 (a_date_time.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi")) + end + + + + json_out: STRING + -- + -- Convert `end_event' to "end", `datetime' to "dateTime", `timezone' to "timeZone" per Google. + do + Result := Precursor + Result.replace_substring_all ("ending", "end") + Result.replace_substring_all ("datetime", "dateTime") + Result.replace_substring_all ("timezone", "timeZone") + end + + metadata_refreshed (a_current: ANY): ARRAY [JSON_METADATA] + do + Result := << + create {JSON_METADATA}.make_text_default + >> + end + + convertible_features (a_object: ANY): ARRAY [STRING] + -- + once + Result := <<"date","datetime","timezone">> +-- Result := <<"date","dateTime","timeZone">> + end + + + +end diff --git a/calendar/src/calendar_event.e b/calendar/src/calendar_event.e new file mode 100644 index 0000000..2c45679 --- /dev/null +++ b/calendar/src/calendar_event.e @@ -0,0 +1,28 @@ +note + description: "Summary description for {CALENDAR_EVENT}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + CALENDAR_EVENT + + create + make + + feature + + make(start_date, end_date : CALENDAR_DATE) +local + tools :DATE_TIME_TOOLS + do + sd := start_date + ed := end_date + + end + + sd:CALENDAR_DATE + ed:CALENDAR_DATE + + +end diff --git a/calendar/src/calendar_event_payload.e b/calendar/src/calendar_event_payload.e index 38c857a..675ef0d 100644 --- a/calendar/src/calendar_event_payload.e +++ b/calendar/src/calendar_event_payload.e @@ -7,10 +7,77 @@ note class CALENDAR_EVENT_PAYLOAD + inherit + JSON_SERIALIZABLE + undefine + default_create + redefine + json_out + end + +create + make, + default_create + + feature - start: detachable STRING - ending: detachable STRING +make (ce: CALENDAR_EVENT ) +do + create start.make_with_date (ce.sd) + create ending.make_with_date (ce.ed) +end + +default_create +do + create start + create ending +end + + + start: CALENDAR_DATE_PAYLOAD + ending: CALENDAR_DATE_PAYLOAD + + + +feature {NONE} -- Implementation: Representation Constants + +-- current_representation: STRING +-- do +-- Result := "{" + +-- "%"start%":%"" + start + "%"," + +-- "%"end%":%"" + ending + "%"" + +-- "}" + +-- end + +feature -- Implementation: Mock Features + + + + +feature -- Implementation + json_out: STRING + -- + -- Convert `end_event' to "end", `datetime' to "dateTime", `timezone' to "timeZone" per Google. + do + Result := Precursor + Result.replace_substring_all ("ending", "end") + Result.replace_substring_all ("datetime", "dateTime") + Result.replace_substring_all ("timezone", "timeZone") + end + metadata_refreshed (a_current: ANY): ARRAY [JSON_METADATA] + do + Result := << + create {JSON_METADATA}.make_text_default + >> + end + convertible_features (a_object: ANY): ARRAY [STRING] + -- + once +-- Result := <<"start">> + Result := <<"start", "ending">> + end end diff --git a/calendar/src/eg_calendar_api.e b/calendar/src/eg_calendar_api.e index ec2ca37..0360f46 100644 --- a/calendar/src/eg_calendar_api.e +++ b/calendar/src/eg_calendar_api.e @@ -74,7 +74,7 @@ feature -- Access create_calendar (name_of_calendar: STRING): detachable STRING do - api_post_call (calendar_url ("calendars", Void), Void, payload_create_calendar, Void) + api_post_call (calendar_url ("calendars", Void), Void, payload_create_calendar(name_of_calendar), Void) if attached last_response as l_response and then attached l_response.body as l_body @@ -131,12 +131,12 @@ feature -- Access Result := "https://www.googleapis.com/calendar" end - payload_create_calendar: STRING + payload_create_calendar(name:STRING): STRING local l_res: JSON_OBJECT do create l_res.make_with_capacity (5) - l_res.put_string ("BSharpABTODO", "summary") + l_res.put_string (name, "summary") Result := l_res.representation end @@ -145,6 +145,8 @@ feature -- Access EIS: "name=calendar event", "src=https://developers.google.com/calendar/v3/reference/events#resource" local l_res: JSON_OBJECT + l_jsa_start: JSON_STRING + l_jsa_end: JSON_ARRAY do create l_res.make_with_capacity (5) diff --git a/calendar/test/calendar_event_payload.e b/calendar/test/calendar_event_payload.e deleted file mode 100644 index 38c857a..0000000 --- a/calendar/test/calendar_event_payload.e +++ /dev/null @@ -1,16 +0,0 @@ -note - description: "Summary description for {CALENDAR_EVENT_PAYLOD}." - author: "" - date: "$Date$" - revision: "$Revision$" - -class - CALENDAR_EVENT_PAYLOAD - -feature - - start: detachable STRING - ending: detachable STRING - - -end diff --git a/calendar/test/calendar_test_set.e b/calendar/test/calendar_test_set.e new file mode 100644 index 0000000..a4881b0 --- /dev/null +++ b/calendar/test/calendar_test_set.e @@ -0,0 +1,119 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + CALENDAR_TEST_SET + +inherit + EQA_TEST_SET + rename + assert as assert_old + redefine + on_prepare, + on_clean + end + + EQA_COMMONLY_USED_ASSERTIONS + undefine + default_create + end + + +feature {NONE} -- Events + + on_prepare + -- + do +-- assert ("not_implemented", False) + end + + on_clean + -- + do +-- assert ("not_implemented", False) + end + +feature -- Test routines + + test_calendar_event_payload + -- New test routine + local + + calendar_event_p : CALENDAR_EVENT_PAYLOAD + calendar_event : CALENDAR_EVENT + start_date : CALENDAR_DATE + end_date : CALENDAR_DATE + + d: DATE + dt: DATE_TIME + tz : STRING + cd : CALENDAR_DATE + expected_json : STRING + + do + create d.make_now + create dt.make_now + tz := "CET" + create start_date.make (d, dt, tz) + create end_date.make (d, dt, tz) + + + create calendar_event.make (start_date, end_date) + create calendar_event_p.make (calendar_event) + + expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi") + + "%",%"timeZone%":%"" + tz + "%"}" + ",%"end%":" + + "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi") + + "%",%"timeZone%":%"" + tz + "%"}" + "}" + + + assert_strings_equal ("Simple test of attributes", expected_json, calendar_event_p.json_out) + + end + + + test_calendar_date_payload + -- New test routine + local + + calendar_date : CALENDAR_DATE_PAYLOAD + d: DATE + dt: DATE_TIME + tz : STRING + cd : CALENDAR_DATE + expected_json : STRING + do + create d.make_now + create dt.make_now + tz := "CET" + create cd.make (d, dt, tz) + + + create calendar_date.make_with_date (cd) + + expected_json := "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi") + + "%",%"timeZone%":%"" + tz + "%"}" + assert_strings_equal ("Simple test of calendar date", expected_json, calendar_date.json_out) + + end + + +feature {NONE} + +simple_start_end_json : STRING = "[ +{"start":"test","end":"test"} +]" + +simple_start_json : STRING = "[ +{"start":"test"} +]" + +end + + diff --git a/calendar/test/test.ecf b/calendar/test/test.ecf index cb49343..4e9d9da 100644 --- a/calendar/test/test.ecf +++ b/calendar/test/test.ecf @@ -1,6 +1,7 @@ - - + + + /CVS$ /EIFGENs$ @@ -12,22 +13,18 @@ + - + - - - - - + + diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index 2751d51..a002f19 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -11,7 +11,7 @@ inherit APPLICATION_FLOW redefine --- Token_file_path_s, + Token_file_path_s, google_auth_path_path_s end @@ -29,7 +29,7 @@ feature -- {NONE} retrieve_access_token test_list_calendars - -- test_create_calendar + test_create_calendar -- test_list_primary_calendar -- test_list_primary_calendar_events -- test_list_calendars @@ -38,10 +38,10 @@ feature -- {NONE} feature -- Tests --- Token_file_path_s: STRING --- do --- Result := "/home/anders/token.access" --- end + Token_file_path_s: STRING + do + Result := "/home/anders/token.access" + end google_auth_path_path_s: STRING do @@ -203,8 +203,8 @@ feature -- Tests feature {NONE} -- Implementations --- CREDENTIALS_PATH: STRING = "/home/anders/credentials.json" -- get this file from https://console.developers.google.com/ - CREDENTIALS_PATH: STRING = "credentials.json" -- get this file from https://console.developers.google.com/ + CREDENTIALS_PATH: STRING = "/home/anders/credentials.json" -- get this file from https://console.developers.google.com/ +-- CREDENTIALS_PATH: STRING = "credentials.json" -- get this file from https://console.developers.google.com/ -- Credentials path to json file. impl_append_post_data_sample: STRING From 5c6c7d9c3668aa0432563be1f0f070990900b4b5 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Wed, 9 Dec 2020 21:45:55 +0100 Subject: [PATCH 08/16] Now possible to create an event --- calendar/src/calendar_date_payload.e | 4 +- calendar/src/calendar_event_payload.e | 14 +- calendar/src/eg_calendar_api.e | 2 +- calendar/test/calendar_test_set.e | 6 +- calendar/test/test_calendar_api.e | 211 ++++++++++++++++---------- gsuite_base/eg_common_api.e | 2 + 6 files changed, 152 insertions(+), 87 deletions(-) diff --git a/calendar/src/calendar_date_payload.e b/calendar/src/calendar_date_payload.e index e492cbc..c9c9f98 100644 --- a/calendar/src/calendar_date_payload.e +++ b/calendar/src/calendar_date_payload.e @@ -68,7 +68,7 @@ feature -- Implementation eiffel_date_time_to_json_string (a_key: STRING; a_date_time: DATE_TIME): JSON_STRING -- Convert `a_date_time' to JSON_STRING with `a_key' do - create Result.make_from_string_32 (a_date_time.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi")) + create Result.make_from_string_32 (a_date_time.formatted_out ("YYYY-[0]MM-[0]DD") + "T" + a_date_time.formatted_out ("[0]hh:[0]mi")+ ":00") end @@ -93,7 +93,7 @@ feature -- Implementation convertible_features (a_object: ANY): ARRAY [STRING] -- once - Result := <<"date","datetime","timezone">> + Result := <<"datetime","timezone">> -- Result := <<"date","dateTime","timeZone">> end diff --git a/calendar/src/calendar_event_payload.e b/calendar/src/calendar_event_payload.e index 675ef0d..a5b0075 100644 --- a/calendar/src/calendar_event_payload.e +++ b/calendar/src/calendar_event_payload.e @@ -24,17 +24,22 @@ feature make (ce: CALENDAR_EVENT ) do + kind:= "calendar#event" + summary := "test from Wunderlist replacer" create start.make_with_date (ce.sd) create ending.make_with_date (ce.ed) -end + end default_create do + kind:= "" + summary:="" create start create ending end - + kind: STRING + summary: STRING start: CALENDAR_DATE_PAYLOAD ending: CALENDAR_DATE_PAYLOAD @@ -66,6 +71,8 @@ feature -- Implementation Result.replace_substring_all ("datetime", "dateTime") Result.replace_substring_all ("timezone", "timeZone") end + + metadata_refreshed (a_current: ANY): ARRAY [JSON_METADATA] do Result := << @@ -76,8 +83,7 @@ feature -- Implementation convertible_features (a_object: ANY): ARRAY [STRING] -- once --- Result := <<"start">> - Result := <<"start", "ending">> + Result := <<"summary","kind","start", "ending">> end end diff --git a/calendar/src/eg_calendar_api.e b/calendar/src/eg_calendar_api.e index 0360f46..a297e8a 100644 --- a/calendar/src/eg_calendar_api.e +++ b/calendar/src/eg_calendar_api.e @@ -89,7 +89,7 @@ feature -- Access ending_date_exists: attached payload.ending do - api_post_call (calendar_url("calendars/" + name_of_calendar + "/events", Void), Void, payload_create_calendar_event, Void) + api_post_call (calendar_url("calendars/" + name_of_calendar + "/events", Void), Void, payload.json_out, Void) if attached last_response as l_response and then attached l_response.body as l_body diff --git a/calendar/test/calendar_test_set.e b/calendar/test/calendar_test_set.e index a4881b0..1d4be98 100644 --- a/calendar/test/calendar_test_set.e +++ b/calendar/test/calendar_test_set.e @@ -67,9 +67,9 @@ feature -- Test routines create calendar_event.make (start_date, end_date) create calendar_event_p.make (calendar_event) - expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi") + + expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + "%",%"timeZone%":%"" + tz + "%"}" + ",%"end%":" + - "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi") + + "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + "%",%"timeZone%":%"" + tz + "%"}" + "}" @@ -97,7 +97,7 @@ feature -- Test routines create calendar_date.make_with_date (cd) - expected_json := "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD:[0]hh:[0]mi") + + expected_json := "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T" + dt.formatted_out ("[0]hh:[0]mi") + "%",%"timeZone%":%"" + tz + "%"}" assert_strings_equal ("Simple test of calendar date", expected_json, calendar_date.json_out) diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index a002f19..f8a89fe 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -28,8 +28,8 @@ feature -- {NONE} set_from_json_credentials_file_path (create {PATH}.make_from_string (CREDENTIALS_PATH)) retrieve_access_token - test_list_calendars - test_create_calendar +-- test_list_calendars + test_create_calendar_event -- test_list_primary_calendar -- test_list_primary_calendar_events -- test_list_calendars @@ -200,6 +200,63 @@ feature -- Tests end end + test_create_calendar_event + require + token_is_valid + local + payload: CALENDAR_EVENT_PAYLOAD + l_esapi: EG_CALENDAR_API + ce: CALENDAR_EVENT + start_date, end_date: CALENDAR_DATE + d: DATE + dt: DATE_TIME +de: DATE + dte: DATE_TIME + + do + create d.make_now + create dt.make_now + create start_date.make (d, dt, "Europe/Zurich") + + create de.make_now + create dte.make_now + dte.minute_add (20) + + create end_date.make (de, dte, "Europe/Zurich") + create ce.make (start_date, end_date) + create payload.make (ce) + + create l_esapi.make (last_token.token) + if attached l_esapi.create_calendar_event ("primary", payload) as l_calendar_event then + if l_esapi.has_error then + -- debug ("test_create_sheet") + logger.write_error ("test_create_calendar event-> Error") + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") + -- end + check + cannot_create_the_calednar_event: False + end + else +-- check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end + -- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end + -- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end + -- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end + -- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. + -- debug ("test_create_sheet") + print ("Created Calednar Event%N") + print (l_calendar_event) + print ("%N") + -- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + feature {NONE} -- Implementations @@ -207,80 +264,80 @@ feature {NONE} -- Implementations -- CREDENTIALS_PATH: STRING = "credentials.json" -- get this file from https://console.developers.google.com/ -- Credentials path to json file. - impl_append_post_data_sample: STRING - local - l_res: JSON_OBJECT - l_jsa_main, - l_jsa_line: JSON_ARRAY - j_array: JSON_ARRAY - - --{ - -- "range": string, - -- "majorDimension": enum (Dimension), - -- "values": [ - -- array - -- ] - --} - --// "values": [ - -- // [ - -- // "Item", - -- // "Cost" - -- // ], - -- // [ - -- // "Wheel", - -- // "$20.50" - -- // ], - -- // [ - -- // "Door", - -- // "$15" - -- // ], - -- // [ - -- // "Engine", - -- // "$100" - -- // ], - -- // [ - -- // "Totals", - -- // "$135.50" - -- // ] - -- // ] - - do - create l_res.make_with_capacity (5) - l_res.put_string ("Sheet1!A1:B5", "range") - l_res.put_string ("ROWS", "majorDimension") -- "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" - - create l_jsa_main.make (10) - - create j_array.make (1) - create l_jsa_line.make (2) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Item")) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Cost")) - j_array.add (l_jsa_line) - - create l_jsa_line.make (2) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Wheel")) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$20.50")) - j_array.add (l_jsa_line) - - create l_jsa_line.make (2) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Door")) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$15")) - j_array.add (l_jsa_line) - - create l_jsa_line.make (2) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Engine")) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$100")) - j_array.add (l_jsa_line) - - create l_jsa_line.make (2) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Totals")) - l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$135.50")) - j_array.add (l_jsa_line) - - l_res.put (j_array, "values") - - Result := l_res.representation - logger.write_debug ("impl_append_body-> Result: '" + Result.out + "'") - end +-- impl_append_post_data_sample: STRING +-- local +-- l_res: JSON_OBJECT +-- l_jsa_main, +-- l_jsa_line: JSON_ARRAY +-- j_array: JSON_ARRAY + +-- --{ +-- -- "range": string, +-- -- "majorDimension": enum (Dimension), +-- -- "values": [ +-- -- array +-- -- ] +-- --} +-- --// "values": [ +-- -- // [ +-- -- // "Item", +-- -- // "Cost" +-- -- // ], +-- -- // [ +-- -- // "Wheel", +-- -- // "$20.50" +-- -- // ], +-- -- // [ +-- -- // "Door", +-- -- // "$15" +-- -- // ], +-- -- // [ +-- -- // "Engine", +-- -- // "$100" +-- -- // ], +-- -- // [ +-- -- // "Totals", +-- -- // "$135.50" +-- -- // ] +-- -- // ] + +-- do +-- create l_res.make_with_capacity (5) +-- l_res.put_string ("Sheet1!A1:B5", "range") +-- l_res.put_string ("ROWS", "majorDimension") -- "DIMENSION_UNSPECIFIED", "ROWS", "COLUMNS" + +-- create l_jsa_main.make (10) + +-- create j_array.make (1) +-- create l_jsa_line.make (2) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Item")) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Cost")) +-- j_array.add (l_jsa_line) + +-- create l_jsa_line.make (2) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Wheel")) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$20.50")) +-- j_array.add (l_jsa_line) + +-- create l_jsa_line.make (2) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Door")) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$15")) +-- j_array.add (l_jsa_line) + +-- create l_jsa_line.make (2) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Engine")) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$100")) +-- j_array.add (l_jsa_line) + +-- create l_jsa_line.make (2) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("Totals")) +-- l_jsa_line.extend (create {JSON_STRING}.make_from_string ("$135.50")) +-- j_array.add (l_jsa_line) + +-- l_res.put (j_array, "values") + +-- Result := l_res.representation +-- logger.write_debug ("impl_append_body-> Result: '" + Result.out + "'") +-- end end diff --git a/gsuite_base/eg_common_api.e b/gsuite_base/eg_common_api.e index fd635cd..1440af1 100644 --- a/gsuite_base/eg_common_api.e +++ b/gsuite_base/eg_common_api.e @@ -223,6 +223,8 @@ feature {NONE} -- Implementation request.add_header ("Content-length", a_payload.count.out) request.add_header ("Content-Type", "application/json; charset=UTF-8") request.add_payload (a_payload) + logger.write_debug ("internal_api_call->payload:'" + a_payload + "'") + else request.add_header ("Content-length", "0") end From 56f555d5e7f92d28c3aebc3f8997bd0854c145fb Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Thu, 10 Dec 2020 21:37:30 +0100 Subject: [PATCH 09/16] Unit test cases adapted to the Event json --- calendar/test/calendar_test_set.e | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/calendar/test/calendar_test_set.e b/calendar/test/calendar_test_set.e index 1d4be98..a443a30 100644 --- a/calendar/test/calendar_test_set.e +++ b/calendar/test/calendar_test_set.e @@ -67,10 +67,11 @@ feature -- Test routines create calendar_event.make (start_date, end_date) create calendar_event_p.make (calendar_event) - expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + +-- Removed date might be temporary expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + + expected_json := "{%"start%":{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + ":00" + "%",%"timeZone%":%"" + tz + "%"}" + ",%"end%":" + - "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + - "%",%"timeZone%":%"" + tz + "%"}" + "}" + "{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + ":00" + + "%",%"timeZone%":%"" + tz + "%"}" + ",%"kind%":%"calendar#event%",%"summary%":%"test from Wunderlist replacer%"}" assert_strings_equal ("Simple test of attributes", expected_json, calendar_event_p.json_out) @@ -96,9 +97,15 @@ feature -- Test routines create calendar_date.make_with_date (cd) +-- I removed DATE as part of the json. I am not sure that it is necessary but since it is working I will stick to the new implementation +-- expected_json := "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T" + dt.formatted_out ("[0]hh:[0]mi") + +-- "%",%"timeZone%":%"" + tz + "%"}" - expected_json := "{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T" + dt.formatted_out ("[0]hh:[0]mi") + + + expected_json := "{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T" + dt.formatted_out ("[0]hh:[0]mi") + ":00" + "%",%"timeZone%":%"" + tz + "%"}" + + assert_strings_equal ("Simple test of calendar date", expected_json, calendar_date.json_out) end From 5b074a41209a07ffc9eba62f69e07b823bd51d9f Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 13 Dec 2020 21:43:12 +0100 Subject: [PATCH 10/16] Added PUT to api call and implemented update of existing calendar event. Need to implement setting of id which now is hard coded --- calendar/src/calendar_event_payload.e | 21 +++++---- calendar/src/eg_calendar_api.e | 17 +++++++ calendar/test/test_calendar_api.e | 68 +++++++++++++++++++++++++-- gsuite_base/eg_common_api.e | 9 ++++ 4 files changed, 102 insertions(+), 13 deletions(-) diff --git a/calendar/src/calendar_event_payload.e b/calendar/src/calendar_event_payload.e index a5b0075..aa6512a 100644 --- a/calendar/src/calendar_event_payload.e +++ b/calendar/src/calendar_event_payload.e @@ -28,20 +28,23 @@ do summary := "test from Wunderlist replacer" create start.make_with_date (ce.sd) create ending.make_with_date (ce.ed) + id := "testid" end default_create do - kind:= "" - summary:="" - create start - create ending + id := "" + kind:= "" + summary:="" + create start + create ending end - kind: STRING - summary: STRING - start: CALENDAR_DATE_PAYLOAD - ending: CALENDAR_DATE_PAYLOAD + id : STRING + kind: STRING + summary: STRING + start: CALENDAR_DATE_PAYLOAD + ending: CALENDAR_DATE_PAYLOAD @@ -83,7 +86,7 @@ feature -- Implementation convertible_features (a_object: ANY): ARRAY [STRING] -- once - Result := <<"summary","kind","start", "ending">> + Result := <<"summary","kind","start", "ending","id">> end end diff --git a/calendar/src/eg_calendar_api.e b/calendar/src/eg_calendar_api.e index a297e8a..61e4147 100644 --- a/calendar/src/eg_calendar_api.e +++ b/calendar/src/eg_calendar_api.e @@ -99,6 +99,23 @@ feature -- Access end + update_calendar_event (name_of_calendar: STRING; event_id: STRING; payload: CALENDAR_EVENT_PAYLOAD): detachable STRING + require + start_date_exists: attached payload.start + ending_date_exists: attached payload.ending + + do + api_put_call (calendar_url("calendars/" + name_of_calendar + "/events/" + event_id, Void), Void, payload.json_out, Void) + if + attached last_response as l_response and then + attached l_response.body as l_body + then + Result := l_body + end + end + + + feature -- Calenader URL calendar_url (a_query: STRING; a_params: detachable STRING): STRING diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index f8a89fe..60b6bf4 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -29,7 +29,8 @@ feature -- {NONE} retrieve_access_token -- test_list_calendars - test_create_calendar_event +-- test_create_calendar_event + test_update_calendar_event -- test_list_primary_calendar -- test_list_primary_calendar_events -- test_list_calendars @@ -179,7 +180,7 @@ feature -- Tests print ("%N") -- end check - cannot_create_the_spreedsheet: False + cannot_create_calwnsar: False end else check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end @@ -204,13 +205,13 @@ feature -- Tests require token_is_valid local - payload: CALENDAR_EVENT_PAYLOAD + payload: CALENDAR_EVENT_PAYLOAD l_esapi: EG_CALENDAR_API ce: CALENDAR_EVENT start_date, end_date: CALENDAR_DATE d: DATE dt: DATE_TIME -de: DATE + de: DATE dte: DATE_TIME do @@ -257,6 +258,65 @@ de: DATE end end + test_update_calendar_event + require + token_is_valid + local + payload: CALENDAR_EVENT_PAYLOAD + l_esapi: EG_CALENDAR_API + ce: CALENDAR_EVENT + start_date, end_date: CALENDAR_DATE + d: DATE + dt: DATE_TIME + de: DATE + dte: DATE_TIME + + do + create d.make_now + create dt.make_now + create start_date.make (d, dt, "Europe/Zurich") + + create de.make_now + create dte.make_now + dte.minute_add (60) + + create end_date.make (de, dte, "Europe/Zurich") + create ce.make (start_date, end_date) + create payload.make (ce) + + create l_esapi.make (last_token.token) + if attached l_esapi.update_calendar_event ("primary","testid", payload) as l_calendar_event then + if l_esapi.has_error then + -- debug ("test_create_sheet") + logger.write_error ("test_create_calendar event-> Error") + print ("test_create_sheet-> Error: msg:" + l_esapi.error_message + "%N") + print ("test_create_sheet-> See codes here: https://developers.google.com/maps-booking/reference/rest-api-v3/status_codes") + print ("%N") + -- end + check + cannot_update_the_calednar_event: False + end + else +-- check Json_Field_spreadsheetId: l_calendars.has_substring ("calendar") end + -- check Json_Field_spreadsheetId: l_spreedsheet.has_substring ("spreadsheetId calendarListEntry") end + -- check Json_Field_properties: l_spreedsheet.has_substring ("properties") end + -- check Json_Field_sheets: l_spreedsheet.has_substring ("sheets") end + -- check Json_Field_spreadsheetUrl: l_spreedsheet.has_substring ("spreadsheetUrl") end + -- developerMetadata and namedRanges are optional. + -- debug ("test_create_sheet") + print ("Created Calednar Event%N") + print (l_calendar_event) + print ("%N") + -- end + end + else + -- Bad scope. no connection, etc + check Unexptected_Behavior: False end + end + end + + + feature {NONE} -- Implementations diff --git a/gsuite_base/eg_common_api.e b/gsuite_base/eg_common_api.e index 1440af1..a686302 100644 --- a/gsuite_base/eg_common_api.e +++ b/gsuite_base/eg_common_api.e @@ -156,6 +156,15 @@ feature {NONE} -- Implementation internal_api_call (a_api_url, "POST", a_query_params, a_payload, a_upload_data) end + api_put_call (a_api_url: STRING; a_query_params: detachable STRING_TABLE [STRING]; a_payload: detachable STRING; a_upload_data: detachable TUPLE[data:PATH; content_type: STRING]) + note + eis: "name=payload_body", "src=https://tools.ietf.org/html/draft-ietf-httpbis-p3-payload-14#section-3.2", "protocol=https://tools.ietf.org/html/draft-ietf-httpbis-p3-payload-14#section-3.2" + -- POST REST API call for `a_api_url' + do + internal_api_call (a_api_url, "PUT", a_query_params, a_payload, a_upload_data) + end + + api_delete_call (a_api_url: STRING; a_query_params: detachable STRING_TABLE [STRING]) -- DELETE REST API call for `a_api_url' do From ab4b3a96e8c5e5fffd20b2f7dc7ec92619119fdd Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 27 Dec 2020 18:20:02 +0100 Subject: [PATCH 11/16] Updated with Calednar id to be able to update an id. --- calendar/src/calendar_event.e | 17 +++++++++-- calendar/src/calendar_event_payload.e | 2 +- calendar/src/eg_calendar_api.e | 42 +++++++++------------------ calendar/test/calendar_test_set.e | 2 +- calendar/test/test_calendar_api.e | 4 +-- 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/calendar/src/calendar_event.e b/calendar/src/calendar_event.e index 2c45679..db9f727 100644 --- a/calendar/src/calendar_event.e +++ b/calendar/src/calendar_event.e @@ -8,21 +8,32 @@ class CALENDAR_EVENT create + make_generate_id, make feature - make(start_date, end_date : CALENDAR_DATE) -local - tools :DATE_TIME_TOOLS + + make(start_date, end_date : CALENDAR_DATE; event_id : STRING) do sd := start_date ed := end_date + id := event_id + end + + make_generate_id(start_date, end_date : CALENDAR_DATE) + do + sd := start_date + ed := end_date + id := "create unique id" end sd:CALENDAR_DATE ed:CALENDAR_DATE + id : STRING + + end diff --git a/calendar/src/calendar_event_payload.e b/calendar/src/calendar_event_payload.e index aa6512a..52c93c2 100644 --- a/calendar/src/calendar_event_payload.e +++ b/calendar/src/calendar_event_payload.e @@ -28,7 +28,7 @@ do summary := "test from Wunderlist replacer" create start.make_with_date (ce.sd) create ending.make_with_date (ce.ed) - id := "testid" + id := ce.id end default_create diff --git a/calendar/src/eg_calendar_api.e b/calendar/src/eg_calendar_api.e index 61e4147..45ecd36 100644 --- a/calendar/src/eg_calendar_api.e +++ b/calendar/src/eg_calendar_api.e @@ -98,11 +98,24 @@ feature -- Access end end + check_event_id (id: STRING) : BOOLEAN +-- TODO Create a CALENDAR_EVENT_ID to handle the rules. + +-- Google doc: Provided IDs must follow these rules: +-- - characters allowed in the ID are those used in base32hex encoding, i.e. lowercase letters a-v and digits 0-9, see section 3.1.2 in RFC2938 +-- - the length of the ID must be between 5 and 1024 characters +-- - the ID must be unique per calendar + + do + Result := true + end + update_calendar_event (name_of_calendar: STRING; event_id: STRING; payload: CALENDAR_EVENT_PAYLOAD): detachable STRING require start_date_exists: attached payload.start ending_date_exists: attached payload.ending + event_id_follow_google_rules : check_event_id(event_id) do api_put_call (calendar_url("calendars/" + name_of_calendar + "/events/" + event_id, Void), Void, payload.json_out, Void) @@ -157,33 +170,4 @@ feature -- Access Result := l_res.representation end - payload_create_calendar_event: STRING - note - EIS: "name=calendar event", "src=https://developers.google.com/calendar/v3/reference/events#resource" - local - l_res: JSON_OBJECT - l_jsa_start: JSON_STRING - l_jsa_end: JSON_ARRAY - do - - create l_res.make_with_capacity (5) - -- Add the required parameters in the paylod: "start" and "end" - --https://developers.google.com/calendar/v3/reference/events/insert - - -- "start": { - -- "date": date, - -- "dateTime": datetime, - -- "timeZone": string - -- }, - -- "end": { - -- "date": date, - -- "dateTime": datetime, - -- "timeZone": string - -- } - - --????????????? - - Result := l_res.representation - end - end diff --git a/calendar/test/calendar_test_set.e b/calendar/test/calendar_test_set.e index a443a30..e7b2819 100644 --- a/calendar/test/calendar_test_set.e +++ b/calendar/test/calendar_test_set.e @@ -64,7 +64,7 @@ feature -- Test routines create end_date.make (d, dt, tz) - create calendar_event.make (start_date, end_date) + create calendar_event.make (start_date, end_date, "testcalendareventpaload123") create calendar_event_p.make (calendar_event) -- Removed date might be temporary expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index 60b6bf4..49a4381 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -224,7 +224,7 @@ feature -- Tests dte.minute_add (20) create end_date.make (de, dte, "Europe/Zurich") - create ce.make (start_date, end_date) + create ce.make (start_date, end_date, "createtesteventid123") create payload.make (ce) create l_esapi.make (last_token.token) @@ -281,7 +281,7 @@ feature -- Tests dte.minute_add (60) create end_date.make (de, dte, "Europe/Zurich") - create ce.make (start_date, end_date) + create ce.make (start_date, end_date, "eventidupdatetest123") create payload.make (ce) create l_esapi.make (last_token.token) From 6cf6d0bd5013fc001156aeeb9a7595a30b2b2195 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sun, 27 Dec 2020 19:49:34 +0100 Subject: [PATCH 12/16] Implemented checks of calendar id but not all. Corrected test case --- calendar/src/eg_calendar_api.e | 6 ++++++ calendar/test/calendar_test_set.e | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/calendar/src/eg_calendar_api.e b/calendar/src/eg_calendar_api.e index 45ecd36..75ffc3f 100644 --- a/calendar/src/eg_calendar_api.e +++ b/calendar/src/eg_calendar_api.e @@ -108,6 +108,12 @@ feature -- Access do Result := true + if id.count <= 5 or id.count >= 1024 then + Result := false + elseif not id.as_lower.is_equal (id) then + Result := false + end + end diff --git a/calendar/test/calendar_test_set.e b/calendar/test/calendar_test_set.e index e7b2819..bc12151 100644 --- a/calendar/test/calendar_test_set.e +++ b/calendar/test/calendar_test_set.e @@ -71,7 +71,7 @@ feature -- Test routines expected_json := "{%"start%":{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + ":00" + "%",%"timeZone%":%"" + tz + "%"}" + ",%"end%":" + "{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + ":00" + - "%",%"timeZone%":%"" + tz + "%"}" + ",%"kind%":%"calendar#event%",%"summary%":%"test from Wunderlist replacer%"}" + "%",%"timeZone%":%"" + tz + "%"}" + ",%"kind%":%"calendar#event%",%"summary%":%"test from Wunderlist replacer%",%"id%":%"testcalendareventpaload123%"}" assert_strings_equal ("Simple test of attributes", expected_json, calendar_event_p.json_out) @@ -110,6 +110,22 @@ feature -- Test routines end + test_calendar_event_id + local + calednar_api : EG_CALENDAR_API + do + create calednar_api.make ("DUMMAYSTRING") + + assert_booleans_equal ("Should be a correct id", true, calednar_api.check_event_id ("aaaaaaaaaa")) + assert_booleans_equal ("Too few characters", false, calednar_api.check_event_id ("aaaa5")) + assert_booleans_equal ("Minimum nmber of characters", true, calednar_api.check_event_id ("aaaaa6")) + assert_booleans_equal ("Too many characters", false, calednar_api.check_event_id ( create {STRING}.make_filled ('a', 1024))) + assert_booleans_equal ("Maximum number if characters", true, calednar_api.check_event_id ( create {STRING}.make_filled ('a', 1023))) + + assert_booleans_equal ("Uppercase not allowed", false, calednar_api.check_event_id ("aaaaAaaaaa")) + + end + feature {NONE} From 2eb2c9c7ff90cfeada937e01586114156a5f998d Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Fri, 12 Mar 2021 09:07:59 +0100 Subject: [PATCH 13/16] Refactoring to be able to add GUI support for applicaiton flow --- calendar/src/calendar_event.e | 5 +- calendar/src/calendar_event_payload.e | 10 +-- calendar/test/calendar_test_set.e | 4 +- calendar/test/test_calendar_api.e | 4 +- gsuite_base/application_flow.e | 109 ++++++++++++++++++++++++++ 5 files changed, 122 insertions(+), 10 deletions(-) diff --git a/calendar/src/calendar_event.e b/calendar/src/calendar_event.e index db9f727..f990d32 100644 --- a/calendar/src/calendar_event.e +++ b/calendar/src/calendar_event.e @@ -14,11 +14,12 @@ class feature - make(start_date, end_date : CALENDAR_DATE; event_id : STRING) + make(start_date, end_date : CALENDAR_DATE; sum, event_id : STRING) do sd := start_date ed := end_date id := event_id + summary := sum end @@ -27,11 +28,13 @@ class sd := start_date ed := end_date id := "create unique id" + summary := "summary" end sd:CALENDAR_DATE ed:CALENDAR_DATE id : STRING + summary : STRING diff --git a/calendar/src/calendar_event_payload.e b/calendar/src/calendar_event_payload.e index 52c93c2..59c734f 100644 --- a/calendar/src/calendar_event_payload.e +++ b/calendar/src/calendar_event_payload.e @@ -25,11 +25,11 @@ feature make (ce: CALENDAR_EVENT ) do kind:= "calendar#event" - summary := "test from Wunderlist replacer" - create start.make_with_date (ce.sd) - create ending.make_with_date (ce.ed) - id := ce.id - end + summary := ce.summary + create start.make_with_date (ce.sd) + create ending.make_with_date (ce.ed) + id := ce.id +end default_create do diff --git a/calendar/test/calendar_test_set.e b/calendar/test/calendar_test_set.e index bc12151..1ae679b 100644 --- a/calendar/test/calendar_test_set.e +++ b/calendar/test/calendar_test_set.e @@ -64,14 +64,14 @@ feature -- Test routines create end_date.make (d, dt, tz) - create calendar_event.make (start_date, end_date, "testcalendareventpaload123") + create calendar_event.make (start_date, end_date, "test summary", "testcalendareventpaload123") create calendar_event_p.make (calendar_event) -- Removed date might be temporary expected_json := "{%"start%":{%"date%":%"" + d.formatted_out ("YYYY-[0]MM-[0]DD") + "%",%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + expected_json := "{%"start%":{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + ":00" + "%",%"timeZone%":%"" + tz + "%"}" + ",%"end%":" + "{%"dateTime%":%"" + dt.formatted_out ("YYYY-[0]MM-[0]DD") + "T"+ dt.formatted_out ("[0]hh:[0]mi") + ":00" + - "%",%"timeZone%":%"" + tz + "%"}" + ",%"kind%":%"calendar#event%",%"summary%":%"test from Wunderlist replacer%",%"id%":%"testcalendareventpaload123%"}" + "%",%"timeZone%":%"" + tz + "%"}" + ",%"kind%":%"calendar#event%",%"summary%":%"test summary%",%"id%":%"testcalendareventpaload123%"}" assert_strings_equal ("Simple test of attributes", expected_json, calendar_event_p.json_out) diff --git a/calendar/test/test_calendar_api.e b/calendar/test/test_calendar_api.e index 49a4381..5c85cb9 100644 --- a/calendar/test/test_calendar_api.e +++ b/calendar/test/test_calendar_api.e @@ -224,7 +224,7 @@ feature -- Tests dte.minute_add (20) create end_date.make (de, dte, "Europe/Zurich") - create ce.make (start_date, end_date, "createtesteventid123") + create ce.make (start_date, end_date, "test summary", "createtesteventid123") create payload.make (ce) create l_esapi.make (last_token.token) @@ -281,7 +281,7 @@ feature -- Tests dte.minute_add (60) create end_date.make (de, dte, "Europe/Zurich") - create ce.make (start_date, end_date, "eventidupdatetest123") + create ce.make (start_date, end_date, "test summary", "eventidupdatetest123") create payload.make (ce) create l_esapi.make (last_token.token) diff --git a/gsuite_base/application_flow.e b/gsuite_base/application_flow.e index 4dcecd9..28065fb 100644 --- a/gsuite_base/application_flow.e +++ b/gsuite_base/application_flow.e @@ -11,6 +11,7 @@ inherit LOGGABLE + feature {NONE} -- Initialization retrieve_access_token @@ -30,6 +31,22 @@ feature {NONE} -- Initialization end end + read_token_from_file + local + file: FILE + token: OAUTH_TOKEN + do + create {PLAIN_TEXT_FILE} file.make_with_name (Token_file_path_s) + if file.exists then + file.open_read + file.read_stream (file.count) + if attached {OAUTH_TOKEN} deserialize (file.last_string) as l_token then + last_token := l_token + end + end + end + + get_token local file: FILE @@ -66,6 +83,78 @@ feature {NONE} -- Initialization last_token := token end + get_authorization_url: STRING + require + attached api_key + attached api_secret + local + google: OAUTH_20_GOOGLE_API + config: OAUTH_CONFIG + file: FILE + do + check + attached api_key as l_api_key + attached api_secret as l_api_secret + then + logger.write_debug ("get_token_from_url-> api_key:'" + l_api_key + "' secret:'" + l_api_secret + "'") + create Result.make_empty + create config.make_default (l_api_key, l_api_secret) + config.set_callback ("urn:ietf:wg:oauth:2.0:oob") + config.set_scope (google_auth_path_path_s) + create google + my_api_service := google.create_service (config) + logger.write_debug ("%N===Google OAuth Workflow ===%N") + + -- Obtain the Authorization URL + logger.write_debug ("%NFetching the Authorization URL..."); + + if attached my_api_service as api_service then + if attached api_service.authorization_url (empty_token) as lauthorization_url then + logger.write_debug ("%NGot the Authorization URL!%N"); + logger.write_debug ("%NNow go and authorize here:%N"); + Result := lauthorization_url + end + end + end + end + + my_api_service: detachable OAUTH_SERVICE_I + + + set_token( autorization_code : STRING) + require + attached api_key + attached api_secret + attached my_api_service + local + google: OAUTH_20_GOOGLE_API + config: OAUTH_CONFIG +-- api_service: OAUTH_SERVICE_I + file: FILE + do + check + attached api_key as l_api_key + attached api_secret as l_api_secret + then +-- logger.write_debug ("get_token_from_url-> api_key:'" + l_api_key + "' secret:'" + l_api_secret + "'") + +-- create config.make_default (l_api_key, l_api_secret) +-- config.set_callback ("urn:ietf:wg:oauth:2.0:oob") +-- config.set_scope (google_auth_path_path_s) +-- create google +-- api_service := google.create_service (config) +-- logger.write_debug ("%N===Google OAuth Workflow ===%N") + if attached my_api_service as api_service then + if attached api_service.access_token_post (empty_token, create {OAUTH_VERIFIER}.make (autorization_code)) as access_token then + create {PLAIN_TEXT_FILE} file.make_create_read_write (Token_file_path_s) + file.put_string (serialize (access_token)) + file.flush + file.close + end + end + end + end + get_token_from_url: OAUTH_TOKEN require attached api_key @@ -212,6 +301,26 @@ feature -- Status report Result := not last_token.token.is_empty end + has_expired: BOOLEAN + require + valid_token: token_is_valid + local + file: FILE + l_date_file: DATE_TIME + l_date_now: DATE_TIME + l_diff: INTEGER_64 + do + read_token_from_file + create {PLAIN_TEXT_FILE} file.make_with_name (Token_file_path_s) + create l_date_file.make_from_epoch (file.date) + create l_date_now.make_now_utc + l_diff := l_date_now.definite_duration (l_date_file).seconds_count + if l_diff > last_token.expires_in-300 then + Result := True + end + end + + feature -- Serialize Access Token serialize (a_object: ANY): STRING From 3180823ec2783d7702a15cf8090f8d2ed4d6a357 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Tue, 16 Mar 2021 17:35:08 +0100 Subject: [PATCH 14/16] Refresh token was not saved when refresing the token --- gsuite_base/application_flow.e | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gsuite_base/application_flow.e b/gsuite_base/application_flow.e index 28065fb..5735393 100644 --- a/gsuite_base/application_flow.e +++ b/gsuite_base/application_flow.e @@ -225,10 +225,19 @@ feature {NONE} -- Initialization request.add_body_parameter ("client_id", l_api_key) request.add_body_parameter ("client_secret", l_api_secret) request.add_body_parameter ("refresh_token", if attached a_token.refresh_token as l_token then l_token else "" end) + if attached a_token.refresh_token as l_token then + logger.write_debug ("refresh_access_token-> refresh_token: " + l_token) + end request.add_body_parameter ("grant_type", "refresh_token") if attached request.execute as l_response then + logger.write_debug ("refresh_access_token-> Got Response") if attached l_response.body as l_body then + logger.write_debug ("refresh_access_token-> Response included body" + l_body) if attached {OAUTH_TOKEN} google.access_token_extractor.extract (l_body) as l_access_token then + logger.write_debug ("refresh_access_token-> Updating token") + if attached a_token.refresh_token as l_token then + l_access_token.set_refresh_token (l_token) + end create {PLAIN_TEXT_FILE} file.make_create_read_write (Token_file_path_s) file.put_string (serialize (l_access_token)) Result := l_access_token From 4bacb24120fe564ac73e10aae2cc4fad4b6fad7d Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Sat, 20 Mar 2021 20:25:24 +0100 Subject: [PATCH 15/16] Adding a reminder --- gsuite_base/application_flow.e | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsuite_base/application_flow.e b/gsuite_base/application_flow.e index 5735393..9788be2 100644 --- a/gsuite_base/application_flow.e +++ b/gsuite_base/application_flow.e @@ -263,7 +263,7 @@ feature -- Access feature -- Status Setting - set_from_json_credentials_file_path (an_fp: PATH) + set_from_json_credentials_file_path (an_fp: PATH) --TODO if file does not exists it shuold not fail. It should try to create a file with correct information. -- sets api_key and api_secret from given api credentials file path normally provided by google -> https://console.developers.google.com -- create a Create OAuth client ID -> desktop app -> and export it to a json file with download link local From b43bd1a5ae9d1a3a574d5c91d42f1a0a7ed99735 Mon Sep 17 00:00:00 2001 From: Anders Persson Date: Fri, 24 Sep 2021 12:52:40 +0200 Subject: [PATCH 16/16] Added status of if it was possible to retrieve a token --- gsuite_base/application_flow.e | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gsuite_base/application_flow.e b/gsuite_base/application_flow.e index 9788be2..c5dfc2b 100644 --- a/gsuite_base/application_flow.e +++ b/gsuite_base/application_flow.e @@ -19,10 +19,12 @@ feature {NONE} -- Initialization local l_secs: INTEGER do + retrieve_access_token_error_has_occured := false create last_token.make_empty get_token if last_token.token.is_empty then logger.write_warning ("retrieve_access_token-> There is something wrong token is empty from file_path: " + Token_file_path_s) + retrieve_access_token_error_has_occured := true check not_happening: False end @@ -329,6 +331,8 @@ feature -- Status report end end + retrieve_access_token_error_has_occured : BOOLEAN + feature -- Serialize Access Token