Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion WindowsAppCommunity.Sdk
Submodule WindowsAppCommunity.Sdk updated 83 files
+14 −2 src/IModifiableImagesCollection.cs
+1 −1 src/IModifiableProject.cs
+1 −1 src/IModifiablePublisher.cs
+3 −1 src/IReadOnlyAccentColor.cs
+2 −2 src/IReadOnlyConnection.cs
+8 −5 src/IReadOnlyConnectionsCollection.cs
+4 −2 src/IReadOnlyEntity.cs
+9 −2 src/IReadOnlyFeaturesCollection.cs
+2 −1 src/IReadOnlyImagesCollection.cs
+10 −3 src/IReadOnlyLinksCollection.cs
+7 −5 src/IReadOnlyProject.cs
+2 −1 src/IReadOnlyProjectCollection.cs
+8 −6 src/IReadOnlyPublisher.cs
+2 −1 src/IReadOnlyPublisherCollection.cs
+4 −2 src/IReadOnlyUser.cs
+2 −1 src/IReadOnlyUserCollection.cs
+29 −0 src/InMemoryConnection.cs
+10 −3 src/Link.cs
+18 −3 src/Models/IConnections.cs
+0 −2 src/Models/IImages.cs
+14 −0 src/Models/IProjectCollection.cs
+2 −3 src/Models/IProjectRoleCollection.cs
+14 −0 src/Models/IPublisherCollection.cs
+2 −3 src/Models/IPublisherRoleCollection.cs
+18 −0 src/Models/IPublisherRoleGraphCollection.cs
+2 −3 src/Models/IUserRoleCollection.cs
+15 −9 src/Models/Project.cs
+14 −0 src/Models/ProjectCollection.cs
+19 −0 src/Models/ProjectRole.cs
+15 −11 src/Models/Publisher.cs
+19 −0 src/Models/PublisherRole.cs
+8 −0 src/Models/PublisherRoleCollection.cs
+0 −1 src/Models/Role.cs
+13 −7 src/Models/User.cs
+19 −0 src/Models/UserRole.cs
+0 −24 src/Nomad/IdOverriddenIpfsFile.cs
+27 −27 src/Nomad/ModifiableAccentColor.cs
+85 −0 src/Nomad/ModifiableConnection.cs
+147 −0 src/Nomad/ModifiableConnectionCollection.cs
+371 −0 src/Nomad/ModifiableEntity.cs
+40 −35 src/Nomad/ModifiableImagesCollection.cs
+138 −0 src/Nomad/ModifiableLinksCollection.cs
+523 −0 src/Nomad/ModifiableProject.cs
+112 −0 src/Nomad/ModifiableProjectCollection.cs
+173 −0 src/Nomad/ModifiableProjectRole.cs
+129 −0 src/Nomad/ModifiableProjectRoleCollection.cs
+453 −0 src/Nomad/ModifiablePublisher.cs
+120 −0 src/Nomad/ModifiablePublisherCollection.cs
+161 −0 src/Nomad/ModifiablePublisherRole.cs
+172 −0 src/Nomad/ModifiablePublisherRoleCollection.cs
+366 −0 src/Nomad/ModifiableUser.cs
+142 −0 src/Nomad/ModifiableUserRole.cs
+168 −0 src/Nomad/ModifiableUserRoleCollection.cs
+36 −0 src/Nomad/NameIdOverriddenGetCidFile.cs
+74 −0 src/Nomad/ProjectRepository.cs
+72 −0 src/Nomad/PublisherRepository.cs
+6 −3 src/Nomad/ReadOnlyAccentColor.cs
+33 −0 src/Nomad/ReadOnlyConnection.cs
+79 −0 src/Nomad/ReadOnlyConnectionCollection.cs
+94 −0 src/Nomad/ReadOnlyEntity.cs
+28 −9 src/Nomad/ReadOnlyImagesCollection.cs
+86 −0 src/Nomad/ReadOnlyLinksCollection.cs
+231 −0 src/Nomad/ReadOnlyProject.cs
+49 −0 src/Nomad/ReadOnlyProjectCollection.cs
+115 −0 src/Nomad/ReadOnlyProjectRole.cs
+52 −0 src/Nomad/ReadOnlyProjectRoleCollection.cs
+220 −0 src/Nomad/ReadOnlyPublisher.cs
+46 −0 src/Nomad/ReadOnlyPublisherCollection.cs
+104 −0 src/Nomad/ReadOnlyPublisherRole.cs
+52 −0 src/Nomad/ReadOnlyPublisherRoleCollection.cs
+183 −0 src/Nomad/ReadOnlyUser.cs
+98 −0 src/Nomad/ReadOnlyUserRole.cs
+52 −0 src/Nomad/ReadOnlyUserRoleCollection.cs
+86 −0 src/Nomad/RepositoryContainer.cs
+72 −0 src/Nomad/UserRepository.cs
+5 −0 src/Role.cs
+1 −2 src/WindowsAppCommunity.Sdk.csproj
+36 −8 tests/BasicTests.cs
+385 −0 tests/ProjectTests.cs
+635 −0 tests/PublisherTests.cs
+21 −0 tests/TestSetup.cs
+98 −0 tests/TestSetupHelpers.cs
+362 −0 tests/UserTests.cs
177 changes: 177 additions & 0 deletions src/Commands/Project/ProjectCommandGroup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ipfs.CoreApi;
using OwlCore.Kubo;
using OwlCore.Nomad.Kubo;
using OwlCore.Nomad.Kubo.Events;
using OwlCore.Storage;
using Remora.Commands.Attributes;
using Remora.Discord.API.Abstractions.Rest;
using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Extensions;
using Remora.Discord.Commands.Feedback.Services;
using Remora.Results;
using WindowsAppCommunity.Discord.ServerCompanion.Services;
using WindowsAppCommunity.Sdk.Nomad;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace WindowsAppCommunity.Discord.ServerCompanion.Commands.Project
{

public class ProjectCommandGroup(INomadRepoService nomadRepoService, IInteractionContext interactionContext, IFeedbackService feedbackService, IDiscordRestInteractionAPI interactionAPI, IDiscordRestChannelAPI channelApi, IDiscordRestGuildAPI guildApi, ICommandContext context) : Remora.Commands.Groups.CommandGroup
{
[Command("createProject")]
public async Task<IResult> CreateProjectAsync(string name, string description)
{
if (!context.TryGetUserID(out var userId))
return await feedbackService.SendContextualErrorAsync("Could not determine the user ID.");

if (!context.TryGetChannelID(out var channelId))
return await feedbackService.SendContextualErrorAsync("Could not determine the channel ID.");

var knownId = userId.Value.ToString();
var repoId = knownId;
var (repositoryContainer, Config, repoSettings) = await nomadRepoService.GetNomadRepoAsync(repoId, knownId, CancellationToken.None);


var initialMessage = await channelApi.CreateMessageAsync(channelId, "Starting project creation process...");

if (!initialMessage.IsSuccess)
return initialMessage;

var createdProject = await repositoryContainer.ProjectRepository.CreateAsync(new(KnownId: knownId), Config.CancellationToken);
await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, $"Created project with ID {createdProject.Id} via known ID {knownId}");

await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Setting name and description...");
await createdProject.UpdateNameAsync(name, Config.CancellationToken);
await createdProject.UpdateDescriptionAsync(description, Config.CancellationToken);

// await initialMessage.EditMessageAsync(initialMessage.Entity.ID, "Publishing local event stream to ipns...");
await createdProject.FlushAsync(Config.CancellationToken);

await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Saving repository keys...");
await repoSettings.SaveAsync(Config.CancellationToken);

await channelApi.DeleteMessageAsync(channelId, initialMessage.Entity.ID);
return await feedbackService.SendContextualSuccessAsync($"Project created successfully with id '{createdProject.Id}' name '{name}' and description '{description}'");
}

[Command("getProject")]
public async Task<IResult> GetProjectAsync(string projectId)
{
if (!context.TryGetUserID(out var userId))
return await feedbackService.SendContextualErrorAsync("Could not determine the user ID.");

if (!context.TryGetChannelID(out var channelId))
return await feedbackService.SendContextualErrorAsync("Could not determine the channel ID.");
var repoId = string.Empty;
var knownId = repoId = userId.Value.ToString();
var (repositoryContainer, Config, repoSettings) = await nomadRepoService.GetNomadRepoAsync(repoId, knownId, CancellationToken.None);

var initialMessage = await channelApi.CreateMessageAsync(channelId, $"Getting project {projectId}");

var project = await repositoryContainer.ProjectRepository.GetAsync(projectId, Config.CancellationToken);
var responseBuilder = new StringBuilder();

responseBuilder.AppendLine($"Project ID: {project.Id}");
responseBuilder.AppendLine($"Name: {project.Name}");
responseBuilder.AppendLine($"Description: {project.Description}");
responseBuilder.AppendLine($"Extended Description: {project.ExtendedDescription}");
responseBuilder.AppendLine($"Accent Color: {project.AccentColor}");
responseBuilder.AppendLine($"Category: {project.Category}");

responseBuilder.AppendLine("Features:");
foreach (var feature in project.Features)
{
responseBuilder.AppendLine($" - {feature}");
}

responseBuilder.AppendLine("Links:");
foreach (var link in project.Links)
{
responseBuilder.AppendLine($" - ID: {link.Id}");
responseBuilder.AppendLine($" Name: {link.Name}");
responseBuilder.AppendLine($" Description: {link.Description}");
responseBuilder.AppendLine($" URL: {link.Url}");
}

responseBuilder.AppendLine("Images:");
await foreach (var image in project.GetImageFilesAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {image.Id}");
responseBuilder.AppendLine($" Name: {image.Name}");

var cid = await image.GetCidAsync(Config.Client, new AddFileOptions { Pin = Config.KuboOptions.ShouldPin }, Config.CancellationToken);
responseBuilder.AppendLine($" CID: {cid}");
responseBuilder.AppendLine($" Type: {image.GetType()}");
}

responseBuilder.AppendLine("Connections:");
await foreach (var connection in project.GetConnectionsAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {connection.Id}");
responseBuilder.AppendLine($" Value: {await connection.GetValueAsync(Config.CancellationToken)}");
}

responseBuilder.AppendLine("Users:");
await foreach (var user in project.GetUsersAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {user.Id}");
responseBuilder.AppendLine($" Name: {user.Name}");
responseBuilder.AppendLine($" Role:");
responseBuilder.AppendLine($" ID: {user.Role.Id}");
responseBuilder.AppendLine($" Name: {user.Role.Name}");
responseBuilder.AppendLine($" Description: {user.Role.Description}");
}

responseBuilder.AppendLine("Publisher:");
var publisher = await project.GetPublisherAsync(Config.CancellationToken);
if (publisher is not null)
{
responseBuilder.AppendLine($" - ID: {publisher.Id}");
responseBuilder.AppendLine($" Name: {publisher.Name}");
}

responseBuilder.AppendLine("Dependencies:");
await foreach (var dependency in project.Dependencies.GetProjectsAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {dependency.Id}");
responseBuilder.AppendLine($" Name: {dependency.Name}");
}

await channelApi.DeleteMessageAsync(channelId, initialMessage.Entity.ID);

return await feedbackService.SendContextualSuccessAsync(responseBuilder.ToString());
}

[Command("listProject")]
public async Task<IResult> ListProjectAsync()
{
if (!context.TryGetUserID(out var userId))
return await feedbackService.SendContextualErrorAsync("Could not determine the user ID.");

if (!context.TryGetChannelID(out var channelId))
return await feedbackService.SendContextualErrorAsync("Could not determine the channel ID.");
var repoId = string.Empty;
var knownId = repoId = userId.Value.ToString();
var (repositoryContainer, Config, repoSettings) = await nomadRepoService.GetNomadRepoAsync(repoId, knownId, CancellationToken.None);

var initialMessage = await channelApi.CreateMessageAsync(channelId, $"Listing projects...");

var responseBuilder = new StringBuilder();
await foreach (var project in repositoryContainer.ProjectRepository.GetAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($"{nameof(project.Id)}: {project.Id}");
responseBuilder.AppendLine($"{nameof(project.Name)}: {project.Name}");
}
responseBuilder.AppendLine($"Finished listing projects for repository {repoId}");

await channelApi.DeleteMessageAsync(channelId, initialMessage.Entity.ID);
return await feedbackService.SendContextualSuccessAsync(responseBuilder.ToString());
}
}
}
183 changes: 183 additions & 0 deletions src/Commands/Publisher/PublisherCommandGroup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ipfs.CoreApi;
using OwlCore.Kubo;
using OwlCore.Nomad.Kubo;
using OwlCore.Nomad.Kubo.Events;
using OwlCore.Storage;
using Remora.Commands.Attributes;
using Remora.Discord.API.Abstractions.Rest;
using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Extensions;
using Remora.Discord.Commands.Feedback.Services;
using Remora.Results;
using WindowsAppCommunity.Discord.ServerCompanion.Services;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace WindowsAppCommunity.Discord.ServerCompanion.Commands.Publisher
{
public class PublisherCommandGroup(INomadRepoService nomadRepoService, IInteractionContext interactionContext, IFeedbackService feedbackService, IDiscordRestInteractionAPI interactionAPI, IDiscordRestChannelAPI channelApi, IDiscordRestGuildAPI guildApi, ICommandContext context) : Remora.Commands.Groups.CommandGroup
{
[Command("createPublisher")]
public async Task<IResult> CreatePublisherAsync(string repoId, string name, string description)
{
if (!context.TryGetUserID(out var userId))
return await feedbackService.SendContextualErrorAsync("Could not determine the user ID.");

if (!context.TryGetChannelID(out var channelId))
return await feedbackService.SendContextualErrorAsync("Could not determine the channel ID.");

var knownId = userId.Value.ToString();

var initialMessage = await channelApi.CreateMessageAsync(channelId, $"Starting publisher creation for repository {repoId}...");
if (!initialMessage.IsSuccess)
return initialMessage;

var (repositoryContainer, Config, repoSettings) = await nomadRepoService.GetNomadRepoAsync(repoId, knownId, CancellationToken.None);


await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Creating publisher...");
var createdPublisher = await repositoryContainer.PublisherRepository.CreateAsync(new(KnownId: knownId), Config.CancellationToken);
await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, $"Created publisher with ID {createdPublisher.Id}");

await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Setting name and description...");
await createdPublisher.UpdateNameAsync(name, Config.CancellationToken);
await createdPublisher.UpdateDescriptionAsync(description, Config.CancellationToken);

await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Publishing local event stream...");
await createdPublisher.PublishLocalAsync<ModifiablePublisher, ValueUpdateEvent>(Config.CancellationToken);

await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Publishing roaming value...");
await createdPublisher.PublishRoamingAsync<ModifiablePublisher, ValueUpdateEvent, WindowsAppCommunity.Sdk.Models.Publisher>(Config.CancellationToken);

await channelApi.EditMessageAsync(channelId, initialMessage.Entity.ID, "Saving repository keys...");
await repoSettings.SaveAsync(Config.CancellationToken);

await channelApi.DeleteMessageAsync(channelId, initialMessage.Entity.ID);
return await feedbackService.SendContextualSuccessAsync(
$"Publisher created successfully with ID '{createdPublisher.Id}', name '{name}', and description '{description}'.");
}


[Command("getPublisher")]
public async Task<IResult> GetPublisherAsync(string publisherId)
{
if (!context.TryGetUserID(out var userId))
return await feedbackService.SendContextualErrorAsync("Could not determine the user ID.");

if (!context.TryGetChannelID(out var channelId))
return await feedbackService.SendContextualErrorAsync("Could not determine the channel ID.");

var repoId = userId.Value.ToString();
var knownId = repoId;
var (repositoryContainer, Config, repoSettings) = await nomadRepoService.GetNomadRepoAsync(repoId, knownId, CancellationToken.None);

var initialMessage = await channelApi.CreateMessageAsync(channelId, $"Getting publisher {publisherId}");

var publisher = await repositoryContainer.PublisherRepository.GetAsync(publisherId, Config.CancellationToken);
var responseBuilder = new StringBuilder();

responseBuilder.AppendLine($"Publisher ID: {publisher.Id}");
responseBuilder.AppendLine($"Name: {publisher.Name}");
responseBuilder.AppendLine($"Description: {publisher.Description}");
responseBuilder.AppendLine($"Extended Description: {publisher.ExtendedDescription}");
responseBuilder.AppendLine($"Accent Color: {publisher.AccentColor}");

responseBuilder.AppendLine("Links:");
foreach (var link in publisher.Links)
{
responseBuilder.AppendLine($" - ID: {link.Id}");
responseBuilder.AppendLine($" Name: {link.Name}");
responseBuilder.AppendLine($" Description: {link.Description}");
responseBuilder.AppendLine($" URL: {link.Url}");
}

responseBuilder.AppendLine("Images:");
await foreach (var image in publisher.GetImageFilesAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {image.Id}");
responseBuilder.AppendLine($" Name: {image.Name}");

var cid = await image.GetCidAsync(Config.Client, new AddFileOptions { Pin = Config.KuboOptions.ShouldPin }, Config.CancellationToken);
responseBuilder.AppendLine($" CID: {cid}");
responseBuilder.AppendLine($" Type: {image.GetType()}");
}

responseBuilder.AppendLine("Connections:");
await foreach (var connection in publisher.GetConnectionsAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {connection.Id}");
responseBuilder.AppendLine($" Value: {await connection.GetValueAsync(Config.CancellationToken)}");
}

responseBuilder.AppendLine("Projects:");
await foreach (var project in publisher.GetProjectsAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {project.Id}");
responseBuilder.AppendLine($" Name: {project.Name}");
}

responseBuilder.AppendLine("Users:");
await foreach (var user in publisher.GetUsersAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {user.Id}");
responseBuilder.AppendLine($" Name: {user.Name}");
responseBuilder.AppendLine($" Role:");
responseBuilder.AppendLine($" ID: {user.Role.Id}");
responseBuilder.AppendLine($" Name: {user.Role.Name}");
responseBuilder.AppendLine($" Description: {user.Role.Description}");
}

responseBuilder.AppendLine("Parent Publishers:");
await foreach (var parentPublisher in publisher.ParentPublishers.GetPublishersAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {parentPublisher.Id}");
responseBuilder.AppendLine($" Name: {parentPublisher.Name}");
}

responseBuilder.AppendLine("Child Publishers:");
await foreach (var childPublisher in publisher.ChildPublishers.GetPublishersAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($" - ID: {childPublisher.Id}");
responseBuilder.AppendLine($" Name: {childPublisher.Name}");
}

await channelApi.DeleteMessageAsync(channelId, initialMessage.Entity.ID);

return await feedbackService.SendContextualSuccessAsync(responseBuilder.ToString());
}


[Command("listPublisher")]
public async Task<IResult> ListPublisherAsync()
{
if (!context.TryGetUserID(out var userId))
return await feedbackService.SendContextualErrorAsync("Could not determine the user ID.");

if (!context.TryGetChannelID(out var channelId))
return await feedbackService.SendContextualErrorAsync("Could not determine the channel ID.");

var repoId = userId.Value.ToString();
var knownId = repoId;
var (repositoryContainer, Config, repoSettings) = await nomadRepoService.GetNomadRepoAsync(repoId, knownId, CancellationToken.None);

var initialMessage = await channelApi.CreateMessageAsync(channelId, "Listing publishers...");

var responseBuilder = new StringBuilder();
await foreach (var publisher in repositoryContainer.PublisherRepository.GetAsync(Config.CancellationToken))
{
responseBuilder.AppendLine($"{nameof(publisher.Id)}: {publisher.Id}");
responseBuilder.AppendLine($"{nameof(publisher.Name)}: {publisher.Name}");
}
responseBuilder.AppendLine($"Finished listing publishers for repository {repoId}");

await channelApi.DeleteMessageAsync(channelId, initialMessage.Entity.ID);
return await feedbackService.SendContextualSuccessAsync(responseBuilder.ToString());
}


}
}
Loading