Skip to content

Commit

Permalink
Upgrade to Microsoft To Do and .NET 8
Browse files Browse the repository at this point in the history
  • Loading branch information
Regenhardt committed Feb 20, 2024
1 parent b7817ff commit fc04fb0
Show file tree
Hide file tree
Showing 24 changed files with 681 additions and 429 deletions.
39 changes: 21 additions & 18 deletions src/Todo.CLI/Auth/TodoCliAuthenticationProviderFactory.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Graph;
using Microsoft.Graph.Auth;

namespace Todo.CLI.Auth;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Client;
using Microsoft.Kiota.Abstractions.Authentication;

namespace Todo.CLI.Auth
static class TodoCliAuthenticationProviderFactory
{
static class TodoCliAuthenticationProviderFactory
public static IAuthenticationProvider GetAuthenticationProvider(IServiceProvider factory)
{
public static IAuthenticationProvider GetAuthenticationProvider(IServiceProvider factory)
{
var config = (TodoCliConfiguration)factory.GetService(typeof(TodoCliConfiguration));
var config = factory.GetRequiredService<TodoCliConfiguration>();

IPublicClientApplication app = PublicClientApplicationBuilder
.Create(config.ClientId)
.WithRedirectUri("http://localhost") // Only loopback redirect uri is supported, see https://aka.ms/msal-net-os-browser for details
.Build();

TokenCacheHelper.EnableSerialization(app.UserTokenCache);

IPublicClientApplication app = PublicClientApplicationBuilder
.Create(config.ClientId)
.WithRedirectUri("http://localhost") // Only loopback redirect uri is supported, see https://aka.ms/msal-net-os-browser for details
.Build();

TokenCacheHelper.EnableSerialization(app.UserTokenCache);
var login = app.AcquireTokenInteractive(config.Scopes).WithPrompt(Prompt.NoPrompt).ExecuteAsync()
.GetAwaiter().GetResult();
var token = login.AccessToken;

return new InteractiveAuthenticationProvider(app, config.Scopes);
}
return new ApiKeyAuthenticationProvider("Bearer " + token, "Authorization",
ApiKeyAuthenticationProvider.KeyLocation.Header);
}
}
}
70 changes: 33 additions & 37 deletions src/Todo.CLI/Auth/TokenCacheHelper.cs
Original file line number Diff line number Diff line change
@@ -1,55 +1,51 @@
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace Todo.CLI.Auth
namespace Todo.CLI.Auth;

static class TokenCacheHelper
{
static class TokenCacheHelper
public static void EnableSerialization(ITokenCache tokenCache)
{
public static void EnableSerialization(ITokenCache tokenCache)
{
tokenCache.SetBeforeAccess(BeforeAccessNotification);
tokenCache.SetAfterAccess(AfterAccessNotification);
}
tokenCache.SetBeforeAccess(BeforeAccessNotification);
tokenCache.SetAfterAccess(AfterAccessNotification);
}

/// <summary>
/// Path to the token cache
/// </summary>
public static readonly string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + ".msalcache.bin3";
/// <summary>
/// Path to the token cache
/// </summary>
public static readonly string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + ".msalcache.bin";

private static readonly object FileLock = new object();
private static readonly object FileLock = new object();


private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
private static void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (FileLock)
{
lock (FileLock)
{
args.TokenCache.DeserializeMsalV3(File.Exists(CacheFilePath)
? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath),
null,
DataProtectionScope.CurrentUser)
: null);
}
args.TokenCache.DeserializeMsalV3(File.Exists(CacheFilePath)
? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath),
null,
DataProtectionScope.CurrentUser)
: null);
}
}

private static void AfterAccessNotification(TokenCacheNotificationArgs args)
private static void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (args.HasStateChanged)
{
// if the access operation resulted in a cache update
if (args.HasStateChanged)
lock (FileLock)
{
lock (FileLock)
{
// reflect changesgs in the persistent store
File.WriteAllBytes(CacheFilePath,
ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
null,
DataProtectionScope.CurrentUser)
);
}
// reflect changesgs in the persistent store
File.WriteAllBytes(CacheFilePath,
ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
null,
DataProtectionScope.CurrentUser)
);
}
}
}
}
}
43 changes: 27 additions & 16 deletions src/Todo.CLI/Commands/AddCommand.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
using System;
using System.Collections.Generic;
using System.CommandLine;
using System.Text;
using Todo.CLI.Handlers;

namespace Todo.CLI.Commands
namespace Todo.CLI.Commands;

public class AddCommand : Command
{
public class AddCommand : Command
public AddCommand(IServiceProvider serviceProvider) : base("add", "Adds a to do item or list.")
{
public AddCommand(IServiceProvider serviceProvider) : base("add")
{
Description = "Adds a to do item.";
Add(new AddListCommand(serviceProvider));
Add(new AddItemCommand(serviceProvider));
}

internal class AddListCommand : Command
{
private static readonly Argument<string> NameArgument = new("name", "The name of the new to do list.");

AddArgument(GetSubjectArgument());
public AddListCommand(IServiceProvider serviceProvider) : base("list", "Adds a new to do list.")
{
AddArgument(NameArgument);

Handler = AddCommandHandler.Create(serviceProvider);
this.SetHandler(AddCommandHandler.List.Create(serviceProvider), NameArgument);
}
}

private Argument GetSubjectArgument()
internal class AddItemCommand : Command
{
private static readonly Argument<string> ListArgument = new("list", "The list to add the to do item to.");
private static readonly Argument<string> SubjectArgument = new("subject", "The subject of the new to do item.");

public AddItemCommand(IServiceProvider serviceProvider) : base("item", "Adds a new to do item to the given list.")
{
return new Argument("subject")
{
Description = "The subject of the new to do item.",
ArgumentType = typeof(string)
};
AddArgument(ListArgument);
AddArgument(SubjectArgument);

this.SetHandler(AddCommandHandler.Item.Create(serviceProvider), ListArgument, SubjectArgument);
}
}
}
}
30 changes: 15 additions & 15 deletions src/Todo.CLI/Commands/CompleteCommand.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
using System;
using System.CommandLine;
using Todo.CLI.Handlers;
using Todo.Core;
using Todo.Core.Model;

namespace Todo.CLI.Commands
namespace Todo.CLI.Commands;

public class CompleteCommand : Command
{
public class CompleteCommand : Command
{
public CompleteCommand(IServiceProvider serviceProvider) : base("complete")
{
Description = "Completes a to do item.";
private static readonly Argument<string> ItemArg =
new("name",
"The name of the todo item to complete. If multiple lists have this item, the first one will be completed.")
{ Arity = ArgumentArity.ZeroOrOne };
private static readonly Option<string> ListOpt = new(["--list", "-l"], "The name of the list to complete the item in.")
{ Arity = ArgumentArity.ZeroOrOne };

AddOption(GetItemOption());
public CompleteCommand(IServiceProvider serviceProvider) : base("complete")
{
Description = "Completes a to do item.";

Handler = CompleteCommandHandler.Create(serviceProvider);
}
Add(ItemArg);
Add(ListOpt);

private Option GetItemOption()
{
return new Option(new string[] { "id", "item-id" }, "The unique identifier of the todo item to complete.");
}
this.SetHandler(CompleteCommandHandler.Create(serviceProvider), ItemArg, ListOpt);
}
}
37 changes: 16 additions & 21 deletions src/Todo.CLI/Commands/ListCommand.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
using System;
using System.CommandLine;
using Todo.CLI.Handlers;
using Todo.Core;

namespace Todo.CLI.Commands
namespace Todo.CLI.Commands;

public class ListCommand : Command
{
public class ListCommand : Command
private static readonly Option<bool> GetAllOption = new(["-a", "--all"], "Lists all to do items including the completed ones.");
private static readonly Option<bool> NoStatusOption = new(["--no-status"], "Suppresses the bullet indicating whether the item is completed or not.");
private static readonly Argument<string> ListNameArgument = new("list-name", "Only list tasks of this To-Do list.")
{
public ListCommand(IServiceProvider serviceProvider) : base("list")
{
Description = "Retrieves a list of the to do items.";

AddOption(GetAllOption());
AddOption(GetNoStatusOption());
Arity = ArgumentArity.ZeroOrOne
};

Handler = ListCommandHandler.Create(serviceProvider);
}

private Option GetAllOption()
{
return new Option(new string[] { "-a", "--all" }, "Lists all to do items including the completed ones.");
}
public ListCommand(IServiceProvider serviceProvider) : base("list")
{
Description = "Retrieves a list of the to do items across all To-Do lists.";

private Option GetNoStatusOption()
{
return new Option(new string[] { "--no-status" }, "Suppresses the bullet indicating whether the item is completed or not.");
}
Add(GetAllOption);
Add(NoStatusOption);
Add(ListNameArgument);

this.SetHandler(ListCommandHandler.Create(serviceProvider), GetAllOption, NoStatusOption, ListNameArgument);
}
}
}
16 changes: 7 additions & 9 deletions src/Todo.CLI/Commands/RemoveCommand.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
using System;
using System.CommandLine;
using Todo.CLI.Handlers;
using Todo.Core;
using Todo.Core.Model;

namespace Todo.CLI.Commands
namespace Todo.CLI.Commands;

public class RemoveCommand : Command
{
public class RemoveCommand : Command
private static readonly Option<string> ListOpt = new(["--list", "-l"], "The name of the list to remove the item from.");
public RemoveCommand(IServiceProvider serviceProvider) : base("remove", "Deletes a to do item.")
{
public RemoveCommand(IServiceProvider serviceProvider) : base("remove")
{
Description = "Deletes a to do item.";
Handler = RemoveCommandHandler.Create(serviceProvider);
}
Add(ListOpt);
this.SetHandler(RemoveCommandHandler.Create(serviceProvider), ListOpt);
}
}
51 changes: 20 additions & 31 deletions src/Todo.CLI/Commands/TodoCommand.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,27 @@
using Todo.CLI.Handlers;
using System;
using System;
using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
using System.Reflection;

namespace Todo.CLI.Commands
namespace Todo.CLI.Commands;

public class TodoCommand : RootCommand
{
public class TodoCommand : RootCommand
private static readonly Option<bool> Version = new(["-v", "--version"], "Prints out the todo CLI version.");
public TodoCommand(IServiceProvider serviceProvider)
{
public TodoCommand(IServiceProvider serviceProvider)
{
// Add static parameters
Description = "A CLI to manage Microsoft to do items.";

// Add options
AddOption(GetVersionOption());

// Add handlers
Handler = TodoCommandHandler.Create();
// Add static parameters
Description = "A CLI to manage Microsoft to do items.";

// Add back when https://github.com/dotnet/command-line-api/issues/1691 is resolved.
//// Add options
//Add(Version);

// Add subcommands
AddCommand(new AddCommand(serviceProvider));
AddCommand(new ListCommand(serviceProvider));
AddCommand(new CompleteCommand(serviceProvider));
AddCommand(new RemoveCommand(serviceProvider));
}
//// Add handlers
//this.SetHandler(TodoCommandHandler.Create(), Version);

private Option GetVersionOption()
{
return new Option(new string[] { "-v", "--version" }, "Prints out the todo CLI version.")
{
Argument = new Argument<bool>()
};
}
// Add subcommands
Add(new AddCommand(serviceProvider));
Add(new ListCommand(serviceProvider));
Add(new CompleteCommand(serviceProvider));
Add(new RemoveCommand(serviceProvider));
}
}
}
Loading

0 comments on commit fc04fb0

Please sign in to comment.