Skip to content

Commit

Permalink
Merge pull request #25 from Regenhardt/master
Browse files Browse the repository at this point in the history
Get all tasks including further pages, and optionally remove all found tasks
  • Loading branch information
mehmetseckin authored Jul 24, 2024
2 parents 4be003b + cd9876f commit 09f9e76
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 36 deletions.
8 changes: 5 additions & 3 deletions src/Todo.CLI/Commands/RemoveCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ namespace Todo.CLI.Commands;
public class RemoveCommand : Command
{
private static readonly Option<string> ListOpt = new(["--list", "-l"], "The name of the list to remove the item from.");
private static readonly Option<DateTime?> OlderThanOpt = new(new[] { "--older-than" }, "Only items completed before this date.");
public RemoveCommand(IServiceProvider serviceProvider) : base("remove", "Deletes a to do item.")
private static readonly Option<DateTime?> OlderThanOpt = new(["--older-than"], "Only items completed before this date.");
private static readonly Option<bool> AllOpt = new(new[] { "--all", "-a" }, "Remove all items fitting the filter. You will be prompted before removal.");
public RemoveCommand(IServiceProvider serviceProvider) : base("remove", "Deletes to do items.")
{
Add(ListOpt);
Add(OlderThanOpt);
this.SetHandler(RemoveCommandHandler.Create(serviceProvider), ListOpt, OlderThanOpt);
Add(AllOpt);
this.SetHandler(RemoveCommandHandler.Create(serviceProvider), ListOpt, OlderThanOpt, AllOpt);
}
}
1 change: 1 addition & 0 deletions src/Todo.CLI/Handlers/CompleteCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static Func<string, string, Task<int>> Create(IServiceProvider servicePro

var selectedItems = Question
.Checkbox(message, items)
.Page(50)
.Prompt();

CompleteItems(todoItemRepository, selectedItems);
Expand Down
121 changes: 89 additions & 32 deletions src/Todo.CLI/Handlers/RemoveCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public class RemoveCommandHandler
private const string PromptMessage = "Which item(s) would you like to delete?";
private const string UIHelpMessage = "Use arrow keys to navigate between options. [SPACEBAR] to mark the options, and [ENTER] to confirm your input.";

public static Func<string, DateTime?, Task<int>> Create(IServiceProvider serviceProvider)
public static Func<string, DateTime?, bool, Task<int>> Create(IServiceProvider serviceProvider)
{
return async (listName, olderThan) =>
return async (listName, olderThan, removeAll) =>
{
var todoItemRepository = serviceProvider.GetRequiredService<ITodoItemRepository>();

Expand All @@ -35,44 +35,101 @@ public class RemoveCommandHandler
.ToList();
}

// Ask user which item to delete
var message = PromptMessage
+ Environment.NewLine
+ Environment.NewLine
+ UIHelpMessage;

try
if (items.Count == 0)
{
var selectedItems = Question
.Checkbox(message, items)
.Prompt();

DeleteItems(todoItemRepository, selectedItems);
Console.WriteLine("No items found.");
return 0;
}
catch (ArgumentOutOfRangeException exc)
{
if (exc.ParamName == "top" &&
exc.Message.Contains(
"The value must be greater than or equal to zero and less than the console's buffer size in that dimension.",
StringComparison.Ordinal))
{
Console.Clear();
Console.ForegroundColor = ConsoleColor.Red;
await Console.Error.WriteLineAsync(
$"Too many tasks ({items.Count}) to display on the current console. Filter tasks by passing a specific list using the --list parameter, or increase buffer size of the console.");
Console.ResetColor();
return 1;
}

throw;
}
return !removeAll
?await RemoveSpecificItems(items, todoItemRepository)
: await RemoveAllItems(items, todoItemRepository);
};
}

private static void DeleteItems(ITodoItemRepository todoItemRepository, IEnumerable<TodoItem> selectedItems)
private static async Task<int> RemoveSpecificItems(List<TodoItem> items, ITodoItemRepository todoItemRepository)
{
// Ask user which item to delete
var message = PromptMessage
+ Environment.NewLine
+ Environment.NewLine
+ UIHelpMessage;

try
{
var selectedItems = Question
.Checkbox(message, items)
.Page(50)
.Prompt();

await DeleteItems(todoItemRepository, selectedItems);
return 0;
}
catch (ArgumentOutOfRangeException exc)
{
if (exc.ParamName == "top" &&
exc.Message.Contains(
"The value must be greater than or equal to zero and less than the console's buffer size in that dimension.",
StringComparison.Ordinal))
{
Console.Clear();
Console.ForegroundColor = ConsoleColor.Red;
await Console.Error.WriteLineAsync(
$"Too many tasks ({items.Count}) to display on the current console. Filter tasks by passing a specific list using the --list parameter, or increase buffer size of the console.");
Console.ResetColor();
return 1;
}

throw;
}
}

private static async Task<int> RemoveAllItems(List<TodoItem> items, ITodoItemRepository todoItemRepository)
{
Task.WaitAll(selectedItems.Select(todoItemRepository.DeleteAsync).ToArray());
var message = items.Count < 50
? "Are you sure you want to delete all items?" + Environment.NewLine +
string.Join(Environment.NewLine, items)
: $"Are you sure you want to delete all {items.Count} items?";

if (Question.Confirm(message).Prompt())
{
await DeleteItems(todoItemRepository, items);
return 0;
}

Console.Clear();
return 0;
}

private static async Task DeleteItems(ITodoItemRepository todoItemRepository, IEnumerable<TodoItem> selectedItems)
{
var items = selectedItems.ToList();
var done = false;
do
{
try
{
await Task.WhenAll(items.Select(async item =>
{
await todoItemRepository.DeleteAsync(item);
items.Remove(item);
}).ToArray());
done = true;
}
catch (AggregateException agg)
{
var exc = agg.InnerExceptions.First();
if(exc.Message.Contains("Too many retries performed"))
{
await Console.Out.WriteLineAsync($"Too many requests, rate limit hit, {items.Count} left, waiting a second and trying again...");
await Task.Delay(1000);
}
else
{
throw;
}
}
} while (!done);
Console.Clear();
}
}
10 changes: 9 additions & 1 deletion src/Todo.Core/Repository/TodoItemRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,18 @@ public async Task<IEnumerable<TodoItem>> ListByListIdAsync(string listId, bool i
ArgumentException.ThrowIfNullOrEmpty(listId);

var graphServiceClient = new GraphServiceClient(AuthenticationProvider);
IEnumerable<TodoTask>? tasks = (await graphServiceClient.Me.Todo.Lists[listId].Tasks.GetAsync())?.Value;
var todoTaskCollectionResponse = (await graphServiceClient.Me.Todo.Lists[listId].Tasks.GetAsync());
IEnumerable<TodoTask>? tasks = todoTaskCollectionResponse?.Value;
if (tasks is null)
return new List<TodoItem>(0);

// if there are more pages, get them
while (todoTaskCollectionResponse?.OdataNextLink != null)
{
todoTaskCollectionResponse = await graphServiceClient.Me.Todo.Lists[listId].Tasks.WithUrl(todoTaskCollectionResponse.OdataNextLink).GetAsync();
tasks = tasks.Concat(todoTaskCollectionResponse?.Value!);
}

if (!includeCompleted)
{
tasks = tasks.Where(t => t.Status is not TaskStatus.Completed);
Expand Down

0 comments on commit 09f9e76

Please sign in to comment.