From 332d671023d8f97aa7a0c3804567982d4dc47916 Mon Sep 17 00:00:00 2001 From: Giovani Date: Tue, 24 Mar 2020 14:58:15 -0400 Subject: [PATCH] refactored business logic and added http sync function --- .../Configuration.cs | 29 ++++++ .../HttpSyncFunction.cs | 58 ++++++++++++ .../ScheduledSyncFunction.cs | 94 +++++-------------- .../TodoistExtensions.cs | 41 -------- .../TodoistIntegrationService.cs | 63 ++++++++++++- Habitica.Todoist.Integration.sln | 2 +- 6 files changed, 172 insertions(+), 115 deletions(-) create mode 100644 Habitica.Todoist.Integration.Function.Sync/Configuration.cs create mode 100644 Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs delete mode 100644 Habitica.Todoist.Integration.Services/TodoistExtensions.cs diff --git a/Habitica.Todoist.Integration.Function.Sync/Configuration.cs b/Habitica.Todoist.Integration.Function.Sync/Configuration.cs new file mode 100644 index 0000000..bdff26d --- /dev/null +++ b/Habitica.Todoist.Integration.Function.Sync/Configuration.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Habitica.Todoist.Integration.Function.Sync +{ + public class Configuration + { + private IConfiguration configuration { get; set; } + public string HabiticaUserId => configuration["habiticaUserId"]; + public string HabiticaApiKey => configuration["habiticaApiKey"]; + public string TodoistApiKey => configuration["todoistApiKey"]; + public string TableStorageConnectionString => configuration["tableStorageConnectionString"]; + public string GiosUserId => "0b6ec4eb-8878-4b9e-8585-7673764a6541"; + + public Configuration() + { + BuildConfig(); + } + + private void BuildConfig() + { + configuration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .Build(); + } + } +} diff --git a/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs b/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs new file mode 100644 index 0000000..a9af22e --- /dev/null +++ b/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using Microsoft.Extensions.Configuration; +using Habitica.Todoist.Integration.Model.Todoist; +using HabiticaTask = Habitica.Todoist.Integration.Model.Habitica.Task; +using Habitica.Todoist.Integration.Model.Habitica.Enums; + +namespace Habitica.Todoist.Integration.Function.Sync +{ + public static class HttpSyncFunction + { + public static Configuration HttpConfiguration { get; set; } = new Configuration(); + + [FunctionName("HttpSyncFunction")] + public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) + { + return new OkObjectResult("TEST"); + } + + private static string GetHabiticaDifficulty(int todoistDifficulty) + { + switch (todoistDifficulty) + { + case 1: + return "0.1"; + case 2: + return "1"; + case 3: + return "1.5"; + case 4: + return "2"; + } + return null; + } + + private static HabiticaTask TaskFromTodoistItem(Item item, string id = null) + { + var taskTypeStr = Enum.GetName(typeof(TaskType), TaskType.Todo).ToLower(); + var task = new HabiticaTask + { + Id = id, + Text = item.Content, + Type = taskTypeStr, + Date = item.Due?.ToJavaScriptDateStr(), + Priority = GetHabiticaDifficulty(item.Priority) + }; + + return task; + } + } +} diff --git a/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs b/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs index f2fe240..2041757 100644 --- a/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs +++ b/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs @@ -17,97 +17,60 @@ namespace Habitica.Todoist.Integration.Function.Sync { public static class ScheduledSyncFunction { - private static IConfiguration configuration { get; set; } - private static string habiticaUserId => configuration["habiticaUserId"]; - private static string habiticaApiKey => configuration["habiticaApiKey"]; - private static string todoistApiKey => configuration["todoistApiKey"]; - private static string tableStorageConnectionString => configuration["tableStorageConnectionString"]; - private static string giosUserId => "0b6ec4eb-8878-4b9e-8585-7673764a6541"; + public static Configuration ScheduledConfiguration { get; set; } = new Configuration(); [Singleton] [FunctionName("ScheduledSyncFunction")] - public static async Task Run([TimerTrigger("0 */30 * * * *")]TimerInfo myTimer, ILogger log) + public static async Task Run([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer, ILogger log) { - BuildConfig(); - // initialize all the clients - var habiticaClient = new HabiticaServiceClient(habiticaUserId, habiticaApiKey); - var todoistClient = new TodoistServiceClient(todoistApiKey); - var tableStorageClient = new TableStorageClient(tableStorageConnectionString); + var habiticaClient = new HabiticaServiceClient(ScheduledConfiguration.HabiticaUserId, ScheduledConfiguration.HabiticaApiKey); + var todoistClient = new TodoistServiceClient(ScheduledConfiguration.TodoistApiKey); + var storageClient = new TableStorageClient(ScheduledConfiguration.TableStorageConnectionString); - // get todoist sync token if available - var syncToken = ""; - try - { - syncToken = tableStorageClient.Query() - .Where(x => x.PartitionKey == giosUserId) - .ToList() - .OrderByDescending(x => x.Timestamp) - .First().RowKey; - } - catch { } + // initialize integration services + var todoistIntegration = new TodoistIntegrationService(todoistClient, storageClient, ScheduledConfiguration.GiosUserId); + var giosUserId = ScheduledConfiguration.GiosUserId; // get all changed items from todoist - var response = await todoistClient.GetItemChanges(syncToken); - var changedItems = response.Items; - - // filter out items by actions - var addItems = changedItems - .Where(x => !tableStorageClient - .Exists(giosUserId, x.Id) && x.Is_deleted == 0) - .ToList(); - - var updateItems = changedItems - .Where(x => tableStorageClient - .Exists(giosUserId, x.Id) && x.Is_deleted == 0 && x.Date_completed == null) - .ToList(); - - var completeItems = changedItems - .Where(x => x.Is_deleted == 0 && x.Date_completed != null) - .ToList(); - - var deleteItems = changedItems - .Where(x => tableStorageClient - .Exists(giosUserId, x.Id) && x.Is_deleted == 1) - .ToList(); + var items = await todoistIntegration.ReadItemChanges(); // perform actions - foreach (var addItem in addItems) + foreach (var addedItem in items.WhereAdded()) { - var task = (await habiticaClient.CreateTask(TaskFromTodoistItem(addItem))).Data; - var link = new TodoHabitLink(giosUserId, addItem.Id, task.Id); + var task = (await habiticaClient.CreateTask(TaskFromTodoistItem(addedItem))).Data; + var link = new TodoHabitLink(giosUserId, addedItem.Id, task.Id); - await tableStorageClient.InsertOrUpdate(link); - await tableStorageClient.InsertOrUpdate(link.Reverse()); + await storageClient.InsertOrUpdate(link); + await storageClient.InsertOrUpdate(link.Reverse()); } - foreach (var updateItem in updateItems) + foreach (var updatedItem in items.WhereUpdated()) { - var habiticaId = tableStorageClient.Query() - .Where(x => x.PartitionKey == giosUserId && x.RowKey == updateItem.Id) + var habiticaId = storageClient.Query() + .Where(x => x.PartitionKey == giosUserId && x.RowKey == updatedItem.Id) .ToList().First().HabiticaId; - await habiticaClient.UpdateTask(TaskFromTodoistItem(updateItem, habiticaId)); + await habiticaClient.UpdateTask(TaskFromTodoistItem(updatedItem, habiticaId)); } - foreach (var completeItem in completeItems) + foreach (var completedItem in items.WhereCompleted()) { - var habiticaId = tableStorageClient.Query() - .Where(x => x.PartitionKey == giosUserId && x.RowKey == completeItem.Id) + var habiticaId = storageClient.Query() + .Where(x => x.PartitionKey == giosUserId && x.RowKey == completedItem.Id) .ToList().First().HabiticaId; await habiticaClient.ScoreTask(habiticaId, ScoreAction.Up); } - foreach (var deleteItem in deleteItems) + foreach (var deleteItem in items.WhereDeleted()) { - var habiticaId = tableStorageClient.Query() + var habiticaId = storageClient.Query() .Where(x => x.PartitionKey == giosUserId && x.RowKey == deleteItem.Id) .ToList().First().HabiticaId; await habiticaClient.DeleteTask(habiticaId); } - // store new todoist sync token - var todoistSync = new TodoistSync(giosUserId, response.Sync_token); - await tableStorageClient.InsertOrUpdate(todoistSync); + // commit read changes + await todoistIntegration.CommitRead(); } private static string GetHabiticaDifficulty(int todoistDifficulty) @@ -140,12 +103,5 @@ namespace Habitica.Todoist.Integration.Function.Sync return task; } - - private static void BuildConfig() - { - configuration = new ConfigurationBuilder() - .AddEnvironmentVariables() - .Build(); - } } } diff --git a/Habitica.Todoist.Integration.Services/TodoistExtensions.cs b/Habitica.Todoist.Integration.Services/TodoistExtensions.cs deleted file mode 100644 index 526fdcd..0000000 --- a/Habitica.Todoist.Integration.Services/TodoistExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Habitica.Todoist.Integration.Data; -using Habitica.Todoist.Integration.Model.Storage; -using Habitica.Todoist.Integration.Model.Todoist; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Habitica.Todoist.Integration.Services -{ - public static class TodoistExtensions - { - public static IEnumerable WhereAdded(this List items, TableStorageClient storageClient, string userId) - { - return items - .Where(x => !storageClient - .Exists(userId, x.Id) && x.Is_deleted == 0); - } - - public static IEnumerable WhereUpdated(this List items, TableStorageClient storageClient, string userId) - { - return items - .Where(x => storageClient - .Exists(userId, x.Id) && x.Is_deleted == 0 && x.Date_completed == null); - } - - public static IEnumerable WhereCompleted(this List items, TableStorageClient storageClient, string userId) - { - return items - .Where(x => storageClient - .Exists(userId, x.Id) && x.Is_deleted == 0 && x.Date_completed != null); - } - - public static IEnumerable WhereDeleted(this List items, TableStorageClient storageClient, string userId) - { - return items - .Where(x => storageClient - .Exists(userId, x.Id) && x.Is_deleted == 1); - } - } -} diff --git a/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs b/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs index 7db444a..a3c14f6 100644 --- a/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs +++ b/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs @@ -6,6 +6,7 @@ using System.Text; using System.Linq; using Habitica.Todoist.Integration.Model.Todoist; using System.Threading.Tasks; +using System.Collections; namespace Habitica.Todoist.Integration.Services { @@ -26,10 +27,12 @@ namespace Habitica.Todoist.Integration.Services this.userId = userId; } - public async Task> ReadItemChanges() + public async Task ReadItemChanges() { var response = await todoistClient.GetItemChanges(ReadLatestSyncToken()); - return response.Items; + latestSyncToken = response.Sync_token; + + return new Items(response.Items, storageClient, userId); } public async Task CommitRead() @@ -41,7 +44,7 @@ namespace Habitica.Todoist.Integration.Services { try { - latestSyncToken = storageClient.Query() + return storageClient.Query() .Where(x => x.PartitionKey == userId) .ToList() .OrderByDescending(x => x.Timestamp) @@ -49,7 +52,59 @@ namespace Habitica.Todoist.Integration.Services } catch { } - return latestSyncToken; + return string.Empty; + } + + public class Items : IEnumerable + { + private List items { get; set; } + private readonly TableStorageClient storageClient; + private readonly string userId; + + internal Items(List items, TableStorageClient storageClient, string userId) + { + this.items = items; + this.storageClient = storageClient; + this.userId = userId; + } + + public IEnumerable WhereAdded() + { + return items + .Where(x => !storageClient + .Exists(userId, x.Id) && x.Is_deleted == 0); + } + + public IEnumerable WhereUpdated() + { + return items + .Where(x => storageClient + .Exists(userId, x.Id) && x.Is_deleted == 0); + } + + public IEnumerable WhereCompleted() + { + return items + .Where(x => storageClient + .Exists(userId, x.Id) && x.Is_deleted == 0 && x.Date_completed != null); + } + + public IEnumerable WhereDeleted() + { + return items + .Where(x => storageClient + .Exists(userId, x.Id) && x.Is_deleted == 1); + } + + public IEnumerator GetEnumerator() + { + return items.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } } } } diff --git a/Habitica.Todoist.Integration.sln b/Habitica.Todoist.Integration.sln index 04f2851..1742247 100644 --- a/Habitica.Todoist.Integration.sln +++ b/Habitica.Todoist.Integration.sln @@ -20,7 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Functions", "Functions", "{ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Habitica.Todoist.Integration.Function.Sync", "Habitica.Todoist.Integration.Function.Sync\Habitica.Todoist.Integration.Function.Sync.csproj", "{9C825688-20BC-4580-8126-1E7320A8CC4D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Habitica.Todoist.Integration.Data", "Habitica.Todoist.Integration.Data\Habitica.Todoist.Integration.Data.csproj", "{08055C1C-7581-4E74-97BB-C5D56E0CA3D8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Habitica.Todoist.Integration.Data", "Habitica.Todoist.Integration.Data\Habitica.Todoist.Integration.Data.csproj", "{08055C1C-7581-4E74-97BB-C5D56E0CA3D8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution