From 0aaf15a89dd25a31fc9c5d80887440f05557adca Mon Sep 17 00:00:00 2001 From: Giovani Date: Fri, 10 Apr 2020 23:02:02 -0400 Subject: [PATCH] finished creating second level todos in todoist as checklists in habitica --- .../HttpSyncFunction.cs | 10 +-- .../ScheduledSyncFunction.cs | 9 ++- .../Storage/HabitTodoLink.cs | 4 +- .../Storage/TodoHabitLink.cs | 8 ++- .../Todoist/Item.cs | 3 + .../Extensions.cs | 4 +- .../HabiticaIntegrationService.cs | 68 ++++++++++++++---- .../HabiticaServiceClient.cs | 71 ++++++++++++------- .../TodoistIntegrationService.cs | 7 +- 9 files changed, 125 insertions(+), 59 deletions(-) diff --git a/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs b/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs index 94a1aa8..312fe80 100644 --- a/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs +++ b/Habitica.Todoist.Integration.Function.Sync/HttpSyncFunction.cs @@ -27,8 +27,8 @@ namespace Habitica.Todoist.Integration.Function.Sync public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log) { // initialize integration services - var todoistService = new TodoistIntegrationService(HttpConfiguration.TodoistApiKey, - HttpConfiguration.TableStorageConnectionString, + var todoistService = new TodoistIntegrationService(HttpConfiguration.TodoistApiKey, + HttpConfiguration.TableStorageConnectionString, HttpConfiguration.GiosUserId); var habiticaService = new HabiticaIntegrationService(HttpConfiguration.HabiticaUserId, HttpConfiguration.HabiticaApiKey, @@ -40,9 +40,9 @@ namespace Habitica.Todoist.Integration.Function.Sync // perform actions await habiticaService.Add(items.WhereAdded()); - await habiticaService.UpdateTasks(items.WhereUpdated()); - await habiticaService.CompleteTasks(items.WhereCompleted()); - await habiticaService.DeleteTasks(items.WhereDeleted()); + await habiticaService.Update(items.WhereUpdated()); + await habiticaService.Complete(items.WhereCompleted()); + await habiticaService.Delete(items.WhereDeleted()); // commit read changes await todoistService.CommitRead(); diff --git a/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs b/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs index bf5d0bd..210a354 100644 --- a/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs +++ b/Habitica.Todoist.Integration.Function.Sync/ScheduledSyncFunction.cs @@ -21,7 +21,7 @@ namespace Habitica.Todoist.Integration.Function.Sync [Singleton("SyncLock", SingletonScope.Host)] [FunctionName("ScheduledSyncFunction")] - public static async Task Run([TimerTrigger("* * * * * *")]TimerInfo myTimer, ILogger log) + public static async Task Run([TimerTrigger("0 */30 * * * *")]TimerInfo myTimer, ILogger log) { // initialize integration services var todoistService = new TodoistIntegrationService(ScheduledConfiguration.TodoistApiKey, @@ -33,14 +33,13 @@ namespace Habitica.Todoist.Integration.Function.Sync ScheduledConfiguration.GiosUserId); // get all changed items from todoist - var items = await todoistService.ReadItemChanges(); // perform actions await habiticaService.Add(items.WhereAdded()); - await habiticaService.UpdateTasks(items.WhereUpdated()); - await habiticaService.CompleteTasks(items.WhereCompleted()); - await habiticaService.DeleteTasks(items.WhereDeleted()); + await habiticaService.Update(items.WhereUpdated()); + await habiticaService.Complete(items.WhereCompleted()); + await habiticaService.Delete(items.WhereDeleted()); // commit read changes await todoistService.CommitRead(); diff --git a/Habitica.Todoist.Integration.Model/Storage/HabitTodoLink.cs b/Habitica.Todoist.Integration.Model/Storage/HabitTodoLink.cs index 8ed54d2..4d75665 100644 --- a/Habitica.Todoist.Integration.Model/Storage/HabitTodoLink.cs +++ b/Habitica.Todoist.Integration.Model/Storage/HabitTodoLink.cs @@ -9,13 +9,15 @@ namespace Habitica.Todoist.Integration.Model.Storage { public HabitTodoLink() { } - public HabitTodoLink(string userId, string habiticaId, string todoistId) + public HabitTodoLink(string userId, string habiticaId, string todoistId, string habiticaParentId = null) { PartitionKey = userId; RowKey = habiticaId; + HabiticaParentId = habiticaParentId; TodoistId = todoistId; } + public string HabiticaParentId { get; set; } public string TodoistId { get; set; } public TodoHabitLink Reverse() diff --git a/Habitica.Todoist.Integration.Model/Storage/TodoHabitLink.cs b/Habitica.Todoist.Integration.Model/Storage/TodoHabitLink.cs index 3ac8ddb..d01ebe6 100644 --- a/Habitica.Todoist.Integration.Model/Storage/TodoHabitLink.cs +++ b/Habitica.Todoist.Integration.Model/Storage/TodoHabitLink.cs @@ -9,18 +9,20 @@ namespace Habitica.Todoist.Integration.Model.Storage { public TodoHabitLink() { } - public TodoHabitLink(string userId, string todoistId, string habiticaId) + public TodoHabitLink(string userId, string todoistId, string habiticaId, string todoistParentId = null) { PartitionKey = userId; RowKey = todoistId; + TodoistParentId = todoistParentId; HabiticaId = habiticaId; } + public string TodoistParentId { get; set; } public string HabiticaId { get; set; } - public HabitTodoLink Reverse() + public HabitTodoLink Reverse(string habiticaParentId = null) { - return new HabitTodoLink(PartitionKey, HabiticaId, RowKey); + return new HabitTodoLink(PartitionKey, HabiticaId, RowKey, habiticaParentId); } } } diff --git a/Habitica.Todoist.Integration.Model/Todoist/Item.cs b/Habitica.Todoist.Integration.Model/Todoist/Item.cs index 3b5f1e1..c4da509 100644 --- a/Habitica.Todoist.Integration.Model/Todoist/Item.cs +++ b/Habitica.Todoist.Integration.Model/Todoist/Item.cs @@ -24,6 +24,9 @@ namespace Habitica.Todoist.Integration.Model.Todoist [JsonProperty("date_completed")] public string Date_completed { get; set; } + /// + /// This field will always be false when an item is marked as deleted + /// [JsonIgnore] public bool IsChild => !string.IsNullOrEmpty(Parent_Id); } diff --git a/Habitica.Todoist.Integration.Services/Extensions.cs b/Habitica.Todoist.Integration.Services/Extensions.cs index 2fae40a..192aac3 100644 --- a/Habitica.Todoist.Integration.Services/Extensions.cs +++ b/Habitica.Todoist.Integration.Services/Extensions.cs @@ -11,7 +11,7 @@ namespace Habitica.Todoist.Integration.Services.Extensions { public static ChecklistItem ToHabiticaChecklistItem(this Item item, string habiticaId = null) { - if (string.IsNullOrEmpty(item.Parent_Id)) + if (!item.IsChild) return null; var checklistItem = new ChecklistItem @@ -25,7 +25,7 @@ namespace Habitica.Todoist.Integration.Services.Extensions public static Task ToHabiticaTask(this Item item, string habiticaId = null) { - if (!string.IsNullOrEmpty(item.Parent_Id)) + if (item.IsChild) return null; var taskTypeStr = Enum.GetName(typeof(TaskType), TaskType.Todo).ToLower(); diff --git a/Habitica.Todoist.Integration.Services/HabiticaIntegrationService.cs b/Habitica.Todoist.Integration.Services/HabiticaIntegrationService.cs index 73659d6..22d283b 100644 --- a/Habitica.Todoist.Integration.Services/HabiticaIntegrationService.cs +++ b/Habitica.Todoist.Integration.Services/HabiticaIntegrationService.cs @@ -61,32 +61,50 @@ namespace Habitica.Todoist.Integration.Services var checklistItem = (await habiticaClient.CreateChecklistItem(item.ToHabiticaChecklistItem(), habiticaTaskId)).Data.Checklist .First(x => x.Text == item.Content); - var link = new TodoHabitLink(userId, item.Id, checklistItem.Id); + var link = new TodoHabitLink(userId, item.Id, checklistItem.Id, item.Parent_Id); await storageClient.InsertOrUpdate(link); - await storageClient.InsertOrUpdate(link.Reverse()); + await storageClient.InsertOrUpdate(link.Reverse(habiticaTaskId)); } - public async Task UpdateTasks(IEnumerable items) + public async Task Update(IEnumerable items) { - foreach (var item in items) - await UpdateTask(item); + foreach (var item in items.OrderBy(x => x.Parent_Id)) + { + if (!item.IsChild) + await UpdateTask(item); + else + await UpdateChecklistItem(item); + } } public async Task UpdateTask(Item item) { + if (item.IsChild) + throw new ArgumentException("Item passed as arguement has a valid Parent_Id"); + var habiticaId = (await storageClient.RetrieveRecord(userId, item.Id)).HabiticaId; await habiticaClient.UpdateTask(item.ToHabiticaTask(habiticaId)); } - public async Task CompleteTasks(IEnumerable items) + public async Task UpdateChecklistItem(Item item) { - foreach (var item in items) - await CompleteTask(item); + if (!item.IsChild) + throw new ArgumentException("Item passed as arguement does not have a valid Parent_Id"); + + var habiticaTaskId = (await storageClient.RetrieveRecord(userId, item.Parent_Id)).HabiticaId; + var habiticaChecklistId = (await storageClient.RetrieveRecord(userId, item.Id)).HabiticaId; + await habiticaClient.UpdateChecklistItem(item.ToHabiticaChecklistItem(habiticaChecklistId), habiticaTaskId); } - public async Task CompleteTask(Item item) + public async Task Complete(IEnumerable items) { - await CompleteTask(item.Id); + foreach (var item in items.OrderByDescending(x => x.Parent_Id)) + { + if (!item.IsChild) + await CompleteTask(item.Id); + else + await CompleteChecklistItem(item.Id, item.Parent_Id); + } } public async Task CompleteTask(string todoistId) @@ -95,15 +113,28 @@ namespace Habitica.Todoist.Integration.Services await habiticaClient.ScoreTask(habiticaId, ScoreAction.Up); } - public async Task DeleteTasks(IEnumerable items) + public async Task CompleteChecklistItem(string todoistId, string todoistParentId) { - foreach (var item in items) - await DeleteTask(item); + var habiticaTaskId = (await storageClient.RetrieveRecord(userId, todoistParentId)).HabiticaId; + var habiticaChecklistId = (await storageClient.RetrieveRecord(userId, todoistId)).HabiticaId; + await habiticaClient.ScoreChecklistItem(habiticaTaskId, habiticaChecklistId); } - public async Task DeleteTask(Item item) + public async Task Delete(IEnumerable items) { - await DeleteTask(item.Id); + List<(Item Item, TodoHabitLink Link)> itemsAndLinks = new List<(Item, TodoHabitLink)>(); + foreach (var item in items) + itemsAndLinks.Add((item, await storageClient.RetrieveRecord(userId, item.Id))); + + foreach (var itemAndLink in itemsAndLinks.OrderByDescending(x => x.Link.TodoistParentId)) + { + var item = itemAndLink.Item; + var link = itemAndLink.Link; + if (string.IsNullOrEmpty(link.TodoistParentId)) + await DeleteTask(item.Id); + else + await DeleteChecklistItem(item.Id, link.TodoistParentId); + } } public async Task DeleteTask(string todoistId) @@ -111,5 +142,12 @@ namespace Habitica.Todoist.Integration.Services var habiticaId = (await storageClient.RetrieveRecord(userId, todoistId)).HabiticaId; await habiticaClient.DeleteTask(habiticaId); } + + public async Task DeleteChecklistItem(string todoistId, string todoistParentId) + { + var habiticaTaskId = (await storageClient.RetrieveRecord(userId, todoistParentId)).HabiticaId; + var habiticaChecklistId = (await storageClient.RetrieveRecord(userId, todoistId)).HabiticaId; + await habiticaClient.DeleteChecklistItem(habiticaTaskId, habiticaChecklistId); + } } } diff --git a/Habitica.Todoist.Integration.Services/HabiticaServiceClient.cs b/Habitica.Todoist.Integration.Services/HabiticaServiceClient.cs index 59eee18..219043c 100644 --- a/Habitica.Todoist.Integration.Services/HabiticaServiceClient.cs +++ b/Habitica.Todoist.Integration.Services/HabiticaServiceClient.cs @@ -23,17 +23,6 @@ namespace Habitica.Todoist.Integration.Services this.apiKey = apiKey; } - public async Task> CreateChecklistItem(ChecklistItem checklistItem, string taskId) - { - using (var client = CreateWebClient()) - { - var request = JsonConvert.SerializeObject(checklistItem); - var json = await client.UploadStringTaskAsync($"{baseUrl}/tasks/{taskId}/checklist", "POST", request); - - return JsonConvert.DeserializeObject>(json); - } - } - public async Task> CreateTask(HabiticaTask task) { using (var client = CreateWebClient()) @@ -45,19 +34,6 @@ namespace Habitica.Todoist.Integration.Services } } - public async Task>> ReadTasks(TaskType taskType = TaskType.Todo) - { - var taskTypeStr = Enum.GetName(taskType.GetType(), taskType).ToLower(); - using (var client = CreateWebClient()) - { - var json = await client.DownloadStringTaskAsync($"{baseUrl}/tasks/user"); - var response = JsonConvert.DeserializeObject>>(json); - response.Data.RemoveAll(x => x.Type != taskTypeStr); - - return response; - } - } - public async Task UpdateTask(HabiticaTask task) { using (var client = CreateWebClient()) @@ -82,6 +58,53 @@ namespace Habitica.Todoist.Integration.Services await client.UploadStringTaskAsync($"{baseUrl}/tasks/{taskId}/score/{actionStr}", "POST", ""); } + //public async Task>> ReadTasks(TaskType taskType = TaskType.Todo) + //{ + // var taskTypeStr = Enum.GetName(taskType.GetType(), taskType).ToLower(); + // using (var client = CreateWebClient()) + // { + // var json = await client.DownloadStringTaskAsync($"{baseUrl}/tasks/user"); + // var response = JsonConvert.DeserializeObject>>(json); + // response.Data.RemoveAll(x => x.Type != taskTypeStr); + + // return response; + // } + //} //public async Task>> ReadTasks(TaskType taskType = TaskType.Todo) + + public async Task> CreateChecklistItem(ChecklistItem checklistItem, string taskId) + { + using (var client = CreateWebClient()) + { + var request = JsonConvert.SerializeObject(checklistItem); + var json = await client.UploadStringTaskAsync($"{baseUrl}/tasks/{taskId}/checklist", "POST", request); + + return JsonConvert.DeserializeObject>(json); + } + } + + public async Task> UpdateChecklistItem(ChecklistItem checklistItem, string taskId) + { + using (var client = CreateWebClient()) + { + var request = JsonConvert.SerializeObject(checklistItem); + var json = await client.UploadStringTaskAsync($"{baseUrl}/tasks/{taskId}/checklist/{checklistItem.Id}", "PUT", request); + + return JsonConvert.DeserializeObject>(json); + } + } + + public async Task DeleteChecklistItem(string taskId, string checklistItemId) + { + using (var client = CreateWebClient()) + await client.UploadStringTaskAsync($"{baseUrl}/tasks/{taskId}/checklist/{checklistItemId}", "DELETE", ""); + } + + public async Task ScoreChecklistItem(string taskId, string checklistItemId) + { + using (var client = CreateWebClient()) + await client.UploadStringTaskAsync($"{baseUrl}/tasks/{taskId}/checklist/{checklistItemId}/score", "POST", ""); + } + private WebClient CreateWebClient() { var client = new WebClient(); diff --git a/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs b/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs index 0ab9e3e..2f0b5d3 100644 --- a/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs +++ b/Habitica.Todoist.Integration.Services/TodoistIntegrationService.cs @@ -89,20 +89,19 @@ namespace Habitica.Todoist.Integration.Services return changedItems .Where(x => storageClient .Exists(userId, x.Id) && x.Is_deleted == 0 && x.Date_completed != null) - .OrderBy(x => x.Parent_Id); + .OrderByDescending(x => x.Parent_Id); } public IEnumerable WhereDeleted() { return changedItems .Where(x => storageClient - .Exists(userId, x.Id) && x.Is_deleted == 1) - .OrderBy(x => x.Parent_Id); + .Exists(userId, x.Id) && x.Is_deleted == 1); } public IEnumerator GetEnumerator() { - return changedItems.OrderBy(x => x.Parent_Id).GetEnumerator(); + return changedItems.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator()