diff --git a/Newsbot.Cli.sln b/Newsbot.Cli.sln new file mode 100644 index 0000000..f3d9890 --- /dev/null +++ b/Newsbot.Cli.sln @@ -0,0 +1,35 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newsbot.Cli", "Newsbot.Cli\Newsbot.Cli.csproj", "{1566F59D-6BFA-4F98-B4B0-F2A5D92B182B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newsbot.Domain", "Newsbot.Domain\Newsbot.Domain.csproj", "{71C391A5-9A94-449C-896E-8D6AB79CE44B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newsbot.Services", "Newsbot.Services\Newsbot.Services.csproj", "{B82F77EA-64FF-40AD-BD8B-6EAFAB2062BA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Newsbot.Tests", "Newsbot.Tests\Newsbot.Tests.csproj", "{04B65EE4-E65C-4AA6-A27C-9400BE74FC31}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1566F59D-6BFA-4F98-B4B0-F2A5D92B182B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1566F59D-6BFA-4F98-B4B0-F2A5D92B182B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1566F59D-6BFA-4F98-B4B0-F2A5D92B182B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1566F59D-6BFA-4F98-B4B0-F2A5D92B182B}.Release|Any CPU.Build.0 = Release|Any CPU + {71C391A5-9A94-449C-896E-8D6AB79CE44B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71C391A5-9A94-449C-896E-8D6AB79CE44B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71C391A5-9A94-449C-896E-8D6AB79CE44B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71C391A5-9A94-449C-896E-8D6AB79CE44B}.Release|Any CPU.Build.0 = Release|Any CPU + {B82F77EA-64FF-40AD-BD8B-6EAFAB2062BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B82F77EA-64FF-40AD-BD8B-6EAFAB2062BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B82F77EA-64FF-40AD-BD8B-6EAFAB2062BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B82F77EA-64FF-40AD-BD8B-6EAFAB2062BA}.Release|Any CPU.Build.0 = Release|Any CPU + {04B65EE4-E65C-4AA6-A27C-9400BE74FC31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04B65EE4-E65C-4AA6-A27C-9400BE74FC31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04B65EE4-E65C-4AA6-A27C-9400BE74FC31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04B65EE4-E65C-4AA6-A27C-9400BE74FC31}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Newsbot.Cli/Commands/ArticlesListCommand.cs b/Newsbot.Cli/Commands/ArticlesListCommand.cs new file mode 100644 index 0000000..ef5f040 --- /dev/null +++ b/Newsbot.Cli/Commands/ArticlesListCommand.cs @@ -0,0 +1,35 @@ +using System.Runtime.CompilerServices; +using CliFx; +using CliFx.Attributes; +using CliFx.Infrastructure; +using jtom38.Newsbot.Services; +using jtom38.Newsbot.Services.Terminal; +using Newsbot.Services.Collector; + +namespace jtom38.Newsbot.Cli.Commands; + +[Command("articles list", Description = "List the newest articles")] +public class ArticlesListCommand : ICommand +{ + public async ValueTask ExecuteAsync(IConsole console) + { + var cfg = ConfigClient.LoadAsync(); + var client = new ArticlesClient(cfg.Result.Uri); + var r = await client.ListArticles(); + + var count = 0; + foreach (var item in r) + { + var title = item.Title ?? ""; + title = title.ReplaceLineEndings(""); + + var msg = $"[{count}] = {title}"; + await console.Output.WriteLineAsync(msg); + count++; + } + + + //var resp = UserInputService.WaitForInput("Enter the number to read the article"); + + } +} \ No newline at end of file diff --git a/Newsbot.Cli/Commands/Config/SetAuthKey.cs b/Newsbot.Cli/Commands/Config/SetAuthKey.cs new file mode 100644 index 0000000..a7f5bcb --- /dev/null +++ b/Newsbot.Cli/Commands/Config/SetAuthKey.cs @@ -0,0 +1,15 @@ +using CliFx; +using CliFx.Attributes; +using CliFx.Infrastructure; + +namespace jtom38.Newsbot.Cli.Commands.Config; + +[Command("config set token")] +public class SetAuthKey : ICommand +{ + public ValueTask ExecuteAsync(IConsole console) + { + //await SetInstanceService.Save(Uri); + return default; + } +} \ No newline at end of file diff --git a/Newsbot.Cli/Commands/Config/SetInstance.cs b/Newsbot.Cli/Commands/Config/SetInstance.cs new file mode 100644 index 0000000..76aa6d1 --- /dev/null +++ b/Newsbot.Cli/Commands/Config/SetInstance.cs @@ -0,0 +1,18 @@ +using CliFx; +using CliFx.Attributes; +using CliFx.Infrastructure; +using jtom38.Newsbot.Services.Config; + +namespace jtom38.Newsbot.Cli.Commands.Config; + +[Command("config set instance")] +public class SetInstance: ICommand +{ + [CommandParameter(0, Description = "URI of the instance", Name = "uri")] + public required string Uri { get; set; } + + public async ValueTask ExecuteAsync(IConsole console) + { + await SetInstanceService.Save(Uri); + } +} \ No newline at end of file diff --git a/Newsbot.Cli/Commands/Config/ShowInstance.cs b/Newsbot.Cli/Commands/Config/ShowInstance.cs new file mode 100644 index 0000000..5692807 --- /dev/null +++ b/Newsbot.Cli/Commands/Config/ShowInstance.cs @@ -0,0 +1,16 @@ +using CliFx; +using CliFx.Attributes; +using CliFx.Infrastructure; +using jtom38.Newsbot.Services; + +namespace jtom38.Newsbot.Cli.Commands.Config; + +[Command("config show instance")] +public class ShowInstance : ICommand +{ + public async ValueTask ExecuteAsync(IConsole console) + { + var res = await ConfigClient.LoadAsync(); + await console.Output.WriteLineAsync(res.Uri); + } +} \ No newline at end of file diff --git a/Newsbot.Cli/Commands/SourcesList.cs b/Newsbot.Cli/Commands/SourcesList.cs new file mode 100644 index 0000000..7e0c53c --- /dev/null +++ b/Newsbot.Cli/Commands/SourcesList.cs @@ -0,0 +1,14 @@ +using CliFx; +using CliFx.Attributes; +using CliFx.Infrastructure; + +namespace jtom38.Newsbot.Cli.Commands; + +[Command("sources list", Description = "Lists the known sources")] +public class SourcesList : ICommand +{ + public async ValueTask ExecuteAsync(IConsole console) + { + + } +} \ No newline at end of file diff --git a/Newsbot.Cli/Newsbot.Cli b/Newsbot.Cli/Newsbot.Cli new file mode 100755 index 0000000..4a2ee73 Binary files /dev/null and b/Newsbot.Cli/Newsbot.Cli differ diff --git a/Newsbot.Cli/Newsbot.Cli.csproj b/Newsbot.Cli/Newsbot.Cli.csproj new file mode 100644 index 0000000..027b9d1 --- /dev/null +++ b/Newsbot.Cli/Newsbot.Cli.csproj @@ -0,0 +1,22 @@ + + + + Exe + net7.0 + enable + enable + + true + true + jtom38.Newsbot.Cli + + + + + + + + + + + diff --git a/Newsbot.Cli/Program.cs b/Newsbot.Cli/Program.cs new file mode 100644 index 0000000..f2b3e2e --- /dev/null +++ b/Newsbot.Cli/Program.cs @@ -0,0 +1,7 @@ +using CliFx; + +await new CliApplicationBuilder() + .AddCommandsFromThisAssembly() + .SetExecutableName("Newsbot.Cli") + .Build() + .RunAsync(); \ No newline at end of file diff --git a/Newsbot.Domain/Models/Collector/ArticleDetailsDto.cs b/Newsbot.Domain/Models/Collector/ArticleDetailsDto.cs new file mode 100644 index 0000000..870ae86 --- /dev/null +++ b/Newsbot.Domain/Models/Collector/ArticleDetailsDto.cs @@ -0,0 +1,20 @@ +namespace jtom38.Newsbot.Domain.Models.Collector; + +public class ArticleDetailsDto +{ + public Guid ID { get; set; } + public string[]? Tags { get; set; } + public string? Title { get; set; } + public string? Url { get; set; } + public DateTime PubDate { get; set; } + public string? Video { get; set; } + public int VideoHeight { get; set; } + public int VideoWidth { get; set; } + public string? Thumbnail { get; set; } + public string? Description { get; set; } + public string? AuthorName { get; set; } + public string? AuthorImage { get; set; } + + public SourceDto? Source { get; set; } + +} \ No newline at end of file diff --git a/Newsbot.Domain/Models/Collector/ArticlesDto.cs b/Newsbot.Domain/Models/Collector/ArticlesDto.cs new file mode 100644 index 0000000..d9273e4 --- /dev/null +++ b/Newsbot.Domain/Models/Collector/ArticlesDto.cs @@ -0,0 +1,45 @@ +using Newtonsoft.Json; + +namespace jtom38.Newsbot.Domain.Models.Collector; + +public class ArticlesDto +{ + [JsonProperty("id")] + public Guid Id { get; set; } + + [JsonProperty("sourceId")] + public Guid SourceId { get; set; } + + [JsonProperty("tags")] + public List? Tags { get; set; } + + [JsonProperty("title")] + public string? Title { get; set; } + + [JsonProperty("url")] + public string? Url { get; set; } + + [JsonProperty("pubDate")] + public DateTime PubDate { get; set; } + + [JsonProperty("video")] + public string? Video { get; set; } + + [JsonProperty("videoHeight")] + public int VideoHeight { get; set; } + + [JsonProperty("videoWidth")] + public int VideoWidth { get; set; } + + [JsonProperty("thumbnail")] + public string? Thumbnail { get; set; } + + [JsonProperty("description")] + public string? Description { get; set; } + + [JsonProperty("authorName")] + public string? AuthorName { get; set; } + + [JsonProperty("authorImage")] + public string? AuthorImage { get; set; } +} \ No newline at end of file diff --git a/Newsbot.Domain/Models/Collector/DiscordWebHookDto.cs b/Newsbot.Domain/Models/Collector/DiscordWebHookDto.cs new file mode 100644 index 0000000..e038877 --- /dev/null +++ b/Newsbot.Domain/Models/Collector/DiscordWebHookDto.cs @@ -0,0 +1,10 @@ +namespace jtom38.Newsbot.Domain.Models.Collector; + +public class DiscordWebHookDto +{ + public Guid ID { get; set; } + public string? Url { get; set; } + public string? Server { get; set; } + public string? Channel { get; set; } + public bool Enabled { get; set; } +} \ No newline at end of file diff --git a/Newsbot.Domain/Models/Collector/SourceDto.cs b/Newsbot.Domain/Models/Collector/SourceDto.cs new file mode 100644 index 0000000..c153aa9 --- /dev/null +++ b/Newsbot.Domain/Models/Collector/SourceDto.cs @@ -0,0 +1,15 @@ +namespace jtom38.Newsbot.Domain.Models.Collector; + +public class SourceDto +{ + public Guid ID { get; set; } + public string? Site { get; set; } + public string? Name { get; set; } + public string? Source { get; set; } + public string? Type { get; set; } + public string? Value { get; set; } + public bool Enabled { get; set; } + public string? Url { get; set; } + public string[]? Tags { get; set; } + public bool Deleted { get; set; } +} \ No newline at end of file diff --git a/Newsbot.Domain/Models/Collector/SubscriptionDetailsDto.cs b/Newsbot.Domain/Models/Collector/SubscriptionDetailsDto.cs new file mode 100644 index 0000000..ada7dec --- /dev/null +++ b/Newsbot.Domain/Models/Collector/SubscriptionDetailsDto.cs @@ -0,0 +1,11 @@ +namespace jtom38.Newsbot.Domain.Models.Collector; + +public class SubscriptionDetailsDto +{ + public Guid Id { get; set; } + public bool CodeAllowReleases { get; set; } + public bool CodeAllowCommits { get; set; } + public SourceDto? Source { get; set; } + public DiscordWebHookDto? DiscordWebHook { get; set; } + +} \ No newline at end of file diff --git a/Newsbot.Domain/Models/Collector/SubscriptionDto.cs b/Newsbot.Domain/Models/Collector/SubscriptionDto.cs new file mode 100644 index 0000000..cefd2be --- /dev/null +++ b/Newsbot.Domain/Models/Collector/SubscriptionDto.cs @@ -0,0 +1,10 @@ +namespace jtom38.Newsbot.Domain.Models.Collector; + +public class SubscriptionDto +{ + public Guid Id { get; set; } + public Guid SourceId { get; set; } + public Guid DiscordWebHookId { get; set; } + public bool CodeAllowReleases { get; set; } + public bool CodeAllowCommits { get; set; } +} \ No newline at end of file diff --git a/Newsbot.Domain/Models/Config.cs b/Newsbot.Domain/Models/Config.cs new file mode 100644 index 0000000..15de88f --- /dev/null +++ b/Newsbot.Domain/Models/Config.cs @@ -0,0 +1,7 @@ +namespace jtom38.Newsbot.Domain.Models; + +public class ConfigModel +{ + public string? Uri { get; set; } + public string? ApiToken { get; set; } +} \ No newline at end of file diff --git a/Newsbot.Domain/Newsbot.Domain.csproj b/Newsbot.Domain/Newsbot.Domain.csproj new file mode 100644 index 0000000..0964c6e --- /dev/null +++ b/Newsbot.Domain/Newsbot.Domain.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + jtom38.Newsbot.Domain + + + + + + + diff --git a/Newsbot.Services/Collector/ArticlesClient.cs b/Newsbot.Services/Collector/ArticlesClient.cs new file mode 100644 index 0000000..51c29f1 --- /dev/null +++ b/Newsbot.Services/Collector/ArticlesClient.cs @@ -0,0 +1,27 @@ +using Newtonsoft.Json; +using jtom38.Newsbot.Domain.Models.Collector; + +namespace Newsbot.Services.Collector; + +public class ArticlesClient +{ + private readonly HttpClient _client; + private string? InstanceUri { get; set; } + + public ArticlesClient(string? instanceUri) + { + _client = new HttpClient(); + InstanceUri = instanceUri; + } + + public async Task> ListArticles() + { + var resp = await _client.GetAsync($"{InstanceUri}/api/articles"); + var content = await resp.Content.ReadAsStringAsync(); + var res = JsonConvert.DeserializeObject>(content); + + res ??= new List(); + + return res; + } +} \ No newline at end of file diff --git a/Newsbot.Services/Config/SetInstanceService.cs b/Newsbot.Services/Config/SetInstanceService.cs new file mode 100644 index 0000000..21fe492 --- /dev/null +++ b/Newsbot.Services/Config/SetInstanceService.cs @@ -0,0 +1,25 @@ +using jtom38.Newsbot.Domain.Models; + +namespace jtom38.Newsbot.Services.Config; + +public class SetInstanceService +{ + public static async Task Save(string uri) + { + var containsHttp = uri.Contains("http://"); + var containsHttps = uri.Contains("https://"); + if (!containsHttp && !containsHttps) + { + throw new Exception("Uri does not define http or https."); + } + + Console.WriteLine($"Instance Set to '{uri}'"); + + var cfg = await ConfigClient.LoadAsync(); + + cfg ??= new ConfigModel(); + cfg.Uri = uri ?? ""; + + await ConfigClient.SaveAsync(cfg); + } +} \ No newline at end of file diff --git a/Newsbot.Services/ConfigClient.cs b/Newsbot.Services/ConfigClient.cs new file mode 100644 index 0000000..c466ebb --- /dev/null +++ b/Newsbot.Services/ConfigClient.cs @@ -0,0 +1,55 @@ +using System.Text.Json; +using jtom38.Newsbot.Domain.Models; + +namespace jtom38.Newsbot.Services; + +public static class ConfigClient +{ + public static async Task LoadAsync() + { + var blank = new ConfigModel(); + try + { + var cfg = await LoadFileAsync(); + return cfg; + } + catch (DirectoryNotFoundException) + { + Directory.CreateDirectory(GetConfigPath()); + await SaveAsync(blank); + return blank; + } + catch (FileNotFoundException) + { + await SaveAsync(blank); + return blank; + } + } + + public static async Task SaveAsync(ConfigModel config) + { + var jsonString = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true}); + await File.WriteAllTextAsync(GetConfigPath(), jsonString); + } + + private static string GetConfigDirectory() + { + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + var path = Path.Join(appDataPath, "newsbot-cli"); + + return path; + } + + private static string GetConfigPath() + { + var path = Path.Join(GetConfigDirectory(), "config.json"); + return path; + } + + private static async Task LoadFileAsync() + { + var content = await File.ReadAllTextAsync(GetConfigPath()); + var res = JsonSerializer.Deserialize(content); + return res ?? new ConfigModel(); + } +} \ No newline at end of file diff --git a/Newsbot.Services/Newsbot.Services.csproj b/Newsbot.Services/Newsbot.Services.csproj new file mode 100644 index 0000000..e0cc086 --- /dev/null +++ b/Newsbot.Services/Newsbot.Services.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + jtom38.Newsbot.Services + + + + + + + + + + + diff --git a/Newsbot.Services/Terminal/UserInputService.cs b/Newsbot.Services/Terminal/UserInputService.cs new file mode 100644 index 0000000..1e7d597 --- /dev/null +++ b/Newsbot.Services/Terminal/UserInputService.cs @@ -0,0 +1,18 @@ +namespace jtom38.Newsbot.Services.Terminal; + +public class UserInputService +{ + public UserInputService() + { + + } + + public static async Task WaitForInput(string message) + { + await Task.Delay(1); + Console.WriteLine(message); + Console.WriteLine("Enter your selection or press 'q' to exit"); + var input = Console.ReadLine(); + return input ?? ""; + } +} \ No newline at end of file diff --git a/Newsbot.Tests/Clients/ArticlesClientTests.cs b/Newsbot.Tests/Clients/ArticlesClientTests.cs new file mode 100644 index 0000000..8cf7d74 --- /dev/null +++ b/Newsbot.Tests/Clients/ArticlesClientTests.cs @@ -0,0 +1,20 @@ +using jtom38.Newsbot.Domain.Models.Collector; +using Newsbot.Services.Collector; + +namespace Newsbot.Tests.Clients; + +public class ArticlesClientTests +{ + [Fact] + public async Task ArticlesAreReturned() + { + var c = new ArticlesClient("http://192.168.1.225:5001"); + var res = await c.ListArticles(); + res ??= new List(); + + if (res.Count == 0) + { + Assert.Fail("No results came back"); + } + } +} \ No newline at end of file diff --git a/Newsbot.Tests/Commands/SetAuthKeyTest.cs b/Newsbot.Tests/Commands/SetAuthKeyTest.cs new file mode 100644 index 0000000..3051e7d --- /dev/null +++ b/Newsbot.Tests/Commands/SetAuthKeyTest.cs @@ -0,0 +1,6 @@ +namespace Newsbot.Services.Config; + +public class SetAuthKeyTest +{ + +} \ No newline at end of file diff --git a/Newsbot.Tests/Commands/SetInstanceTest.cs b/Newsbot.Tests/Commands/SetInstanceTest.cs new file mode 100644 index 0000000..6860a28 --- /dev/null +++ b/Newsbot.Tests/Commands/SetInstanceTest.cs @@ -0,0 +1,30 @@ +using jtom38.Newsbot.Domain.Models; +using jtom38.Newsbot.Services; +using jtom38.Newsbot.Services.Config; +using Xunit.Abstractions; + +namespace Newsbot.Tests.Commands; + +public class SetInstanceTest +{ + private readonly ITestOutputHelper _testOutputHelper; + + public SetInstanceTest(ITestOutputHelper testOutputHelper) + { + _testOutputHelper = testOutputHelper; + } + + [Fact] + public async Task SetInstanceSavesTheUri() + { + var uri = "http://localhost:5001"; + try + { + await SetInstanceService.Save(uri); + } + catch(Exception ex) + { + Assert.Fail(ex.Message); + } + } +} \ No newline at end of file diff --git a/Newsbot.Tests/Newsbot.Tests.csproj b/Newsbot.Tests/Newsbot.Tests.csproj new file mode 100644 index 0000000..30afcc3 --- /dev/null +++ b/Newsbot.Tests/Newsbot.Tests.csproj @@ -0,0 +1,22 @@ + + + + net7.0 + enable + enable + + false + + + + + + + + + + + + + + diff --git a/Newsbot.Tests/Services/ConfigClientTests.cs b/Newsbot.Tests/Services/ConfigClientTests.cs new file mode 100644 index 0000000..0f3d532 --- /dev/null +++ b/Newsbot.Tests/Services/ConfigClientTests.cs @@ -0,0 +1,18 @@ +using jtom38.Newsbot.Domain.Models; +using jtom38.Newsbot.Services; + +namespace Newsbot.Tests.Services; + +public class ConfigClientTests +{ + [Fact] + public async Task CanLoadConfig() + { + var cfg = await ConfigClient.LoadAsync(); + cfg = cfg ??= new ConfigModel(); + if (cfg.Uri == "") + { + Assert.Fail("Uri was missing"); + } + } +} \ No newline at end of file diff --git a/Newsbot.Tests/Usings.cs b/Newsbot.Tests/Usings.cs new file mode 100644 index 0000000..8c927eb --- /dev/null +++ b/Newsbot.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 53882a8..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Newsbot.Cli - diff --git a/makefile b/makefile new file mode 100644 index 0000000..140322d --- /dev/null +++ b/makefile @@ -0,0 +1,12 @@ +.PHONY: help +help: ## Shows this help command + @egrep -h '\s##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +build: ## builds the application with the current go runtime + dotnet restore + dotnet build + +pub: ## Generate artifacts + dotnet restore + dotnet publish + cp ./Newsbot.Cli/bin/Debug/net7.0/osx-arm64/publish/Newsbot.Cli ./newsbot \ No newline at end of file