From 8d0a612238ec3be2fc56d28a18512da1bc189ec8 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 02:15:13 -0400 Subject: [PATCH 1/9] added boostrapper --- .gitignore | 1 + src/BSLManager/BSLManager.csproj | 9 +++++ src/BSLManager/Bootstrapper.cs | 62 ++++++++++++++++++++++++++++++++ src/BSLManager/Program.cs | 54 +++++++++++++++++++++++----- 4 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 src/BSLManager/Bootstrapper.cs diff --git a/.gitignore b/.gitignore index 086c047..a6584fc 100644 --- a/.gitignore +++ b/.gitignore @@ -351,3 +351,4 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ +/src/BSLManager/Properties/launchSettings.json diff --git a/src/BSLManager/BSLManager.csproj b/src/BSLManager/BSLManager.csproj index fafc29d..28c8e18 100644 --- a/src/BSLManager/BSLManager.csproj +++ b/src/BSLManager/BSLManager.csproj @@ -6,7 +6,16 @@ + + + + + + + + + diff --git a/src/BSLManager/Bootstrapper.cs b/src/BSLManager/Bootstrapper.cs new file mode 100644 index 0000000..f450665 --- /dev/null +++ b/src/BSLManager/Bootstrapper.cs @@ -0,0 +1,62 @@ +using System; +using BirdsiteLive.Common.Settings; +using BirdsiteLive.Common.Structs; +using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.DAL.Postgres.DataAccessLayers; +using BirdsiteLive.DAL.Postgres.Settings; +using Lamar; + +namespace BSLManager +{ + public class Bootstrapper + { + private readonly DbSettings _settings; + + #region Ctor + public Bootstrapper(DbSettings settings) + { + _settings = settings; + } + #endregion + + public Container Init() + { + var container = new Container(x => + { + if (string.Equals(_settings.Type, DbTypes.Postgres, StringComparison.OrdinalIgnoreCase)) + { + var connString = $"Host={_settings.Host};Username={_settings.User};Password={_settings.Password};Database={_settings.Name}"; + var postgresSettings = new PostgresSettings + { + ConnString = connString + }; + x.For().Use(x => postgresSettings); + + x.For().Use().Singleton(); + x.For().Use().Singleton(); + x.For().Use().Singleton(); + } + else + { + throw new NotImplementedException($"{_settings.Type} is not supported"); + } + + x.Scan(_ => + { + //_.Assembly("BirdsiteLive.Twitter"); + //_.Assembly("BirdsiteLive.Domain"); + _.Assembly("BirdsiteLive.DAL"); + _.Assembly("BirdsiteLive.DAL.Postgres"); + //_.Assembly("BirdsiteLive.Moderation"); + //_.Assembly("BirdsiteLive.Pipeline"); + _.TheCallingAssembly(); + + _.WithDefaultConventions(); + + _.LookForRegistries(); + }); + }); + return container; + } + } +} \ No newline at end of file diff --git a/src/BSLManager/Program.cs b/src/BSLManager/Program.cs index ff1a8bd..2f90e8d 100644 --- a/src/BSLManager/Program.cs +++ b/src/BSLManager/Program.cs @@ -1,7 +1,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Text; +using System.Threading.Tasks; +using BirdsiteLive.Common.Settings; +using BirdsiteLive.DAL.Contracts; +using Microsoft.Extensions.Configuration; using NStack; using Terminal.Gui; @@ -9,10 +14,35 @@ namespace BSLManager { class Program { - static void Main(string[] args) + static async Task Main(string[] args) { Console.OutputEncoding = Encoding.Default; + var settings = GetSettings(); + + var bootstrapper = new Bootstrapper(settings); + var container = bootstrapper.Init(); + + var followersDal = container.GetInstance(); + + await LaunchAppAsync(followersDal); + } + + private static DbSettings GetSettings() + { + var builder = new ConfigurationBuilder() + .AddEnvironmentVariables(); + var configuration = builder.Build(); + + var dbSettings = configuration.GetSection("Db").Get(); + return dbSettings; + } + + private static async Task LaunchAppAsync(IFollowersDal followersDal) + { + var followers = await followersDal.GetAllFollowersAsync(); + var orderedFollowers = followers.OrderByDescending(x => x.Followings.Count).ToList(); + Application.Init(); var top = Application.Top; @@ -30,9 +60,14 @@ namespace BSLManager top.Add(win); // Creates a menubar, the item "New" has a help menu. - var menu = new MenuBar(new MenuBarItem[] { - new MenuBarItem ("_File", new MenuItem [] { - new MenuItem ("_Quit", "", () => { if (Quit ()) top.Running = false; }) + var menu = new MenuBar(new MenuBarItem[] + { + new MenuBarItem("_File", new MenuItem[] + { + new MenuItem("_Quit", "", () => + { + if (Quit()) top.Running = false; + }) }), //new MenuBarItem ("_Edit", new MenuItem [] { // new MenuItem ("_Copy", "", null), @@ -47,11 +82,11 @@ namespace BSLManager var n = MessageBox.Query(50, 7, "Quit BSL Manager", "Are you sure you want to quit?", "Yes", "No"); return n == 0; } - + var listData = new List(); - for (var i = 0; i < 100; i++) + foreach (var follower in orderedFollowers) { - listData.Add($"@User{i}@Instance.tld {i*3}"); + listData.Add($"@{follower.Acct}@{follower.Host} {follower.Followings.Count}"); } var list = new ListView(listData) @@ -102,7 +137,8 @@ namespace BSLManager if (okpressed) { listData.RemoveAt(el); - typeof(Application).GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null); + typeof(Application).GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic) + .Invoke(null, null); } } }; @@ -114,6 +150,6 @@ namespace BSLManager ); Application.Run(); - } + } } } From f1a7146c67e3fbacd7e434aa5af324b1e708fd42 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 17:14:57 -0400 Subject: [PATCH 2/9] refactorization + fix boostrapper --- src/BSLManager/App.cs | 148 +++++++++++++++++++++++++++++++ src/BSLManager/BSLManager.csproj | 3 +- src/BSLManager/Bootstrapper.cs | 34 ++++++- src/BSLManager/Program.cs | 119 +------------------------ 4 files changed, 182 insertions(+), 122 deletions(-) create mode 100644 src/BSLManager/App.cs diff --git a/src/BSLManager/App.cs b/src/BSLManager/App.cs new file mode 100644 index 0000000..3979ab6 --- /dev/null +++ b/src/BSLManager/App.cs @@ -0,0 +1,148 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.Moderation.Actions; +using Terminal.Gui; + +namespace BSLManager +{ + public class App + { + private readonly IFollowersDal _followersDal; + private readonly IRemoveFollowerAction _removeFollowerAction; + + #region Ctor + public App(IFollowersDal followersDal, IRemoveFollowerAction removeFollowerAction) + { + _followersDal = followersDal; + _removeFollowerAction = removeFollowerAction; + } + #endregion + + public void Run() + { + Application.Init(); + var top = Application.Top; + + // Creates the top-level window to show + var win = new Window("BSL Manager") + { + X = 0, + Y = 1, // Leave one row for the toplevel menu + + // By using Dim.Fill(), it will automatically resize without manual intervention + Width = Dim.Fill(), + Height = Dim.Fill() + }; + + top.Add(win); + + // Creates a menubar, the item "New" has a help menu. + var menu = new MenuBar(new MenuBarItem[] + { + new MenuBarItem("_File", new MenuItem[] + { + new MenuItem("_Quit", "", () => + { + if (Quit()) top.Running = false; + }) + }), + //new MenuBarItem ("_Edit", new MenuItem [] { + // new MenuItem ("_Copy", "", null), + // new MenuItem ("C_ut", "", null), + // new MenuItem ("_Paste", "", null) + //}) + }); + top.Add(menu); + + static bool Quit() + { + var n = MessageBox.Query(50, 7, "Quit BSL Manager", "Are you sure you want to quit?", "Yes", "No"); + return n == 0; + } + + var listData = new List(); + + Application.MainLoop.Invoke(async () => { + var followers = await _followersDal.GetAllFollowersAsync(); + var orderedFollowers = followers.OrderByDescending(x => x.Followings.Count).ToList(); + + foreach (var follower in orderedFollowers) + { + listData.Add($"@{follower.Acct}@{follower.Host} {follower.Followings.Count}"); + } + + RefreshUI(); + }); + + var list = new ListView(listData) + { + X = 1, + Y = 2, + Width = Dim.Fill(), + Height = Dim.Fill() + }; + + list.KeyDown += _ => + { + if (_.KeyEvent.Key == Key.Enter) + { + var el = list.SelectedItem; + + bool okpressed = false; + var ok = new Button(10, 14, "Yes"); + ok.Clicked += () => + { + Application.RequestStop(); + okpressed = true; + }; + + var cancel = new Button(3, 14, "No"); + cancel.Clicked += () => Application.RequestStop(); + + var dialog = new Dialog("Delete", 60, 18, cancel, ok); + + var name = new Label($"User: {listData[el]}") + { + X = 1, + Y = 1, + Width = Dim.Fill(), + Height = 1 + }; + var entry = new Label("Delete user and remove all their followings?") + { + X = 1, + Y = 3, + Width = Dim.Fill(), + Height = 1 + }; + dialog.Add(name); + dialog.Add(entry); + Application.Run(dialog); + + if (okpressed) + { + listData.RemoveAt(el); + RefreshUI(); + } + } + }; + + // Add some controls, + win.Add( + new Label(1, 0, "Listing followers"), + list + ); + + Application.Run(); + } + + private void RefreshUI() + { + typeof(Application).GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic) + .Invoke(null, null); + } + } +} \ No newline at end of file diff --git a/src/BSLManager/BSLManager.csproj b/src/BSLManager/BSLManager.csproj index 28c8e18..8a3ef97 100644 --- a/src/BSLManager/BSLManager.csproj +++ b/src/BSLManager/BSLManager.csproj @@ -1,4 +1,4 @@ - + Exe @@ -15,6 +15,7 @@ + diff --git a/src/BSLManager/Bootstrapper.cs b/src/BSLManager/Bootstrapper.cs index f450665..1698d9a 100644 --- a/src/BSLManager/Bootstrapper.cs +++ b/src/BSLManager/Bootstrapper.cs @@ -1,10 +1,14 @@ using System; +using System.Net.Http; using BirdsiteLive.Common.Settings; using BirdsiteLive.Common.Structs; using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Postgres.DataAccessLayers; using BirdsiteLive.DAL.Postgres.Settings; using Lamar; +using Lamar.Scanning.Conventions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace BSLManager { @@ -41,14 +45,19 @@ namespace BSLManager throw new NotImplementedException($"{_settings.Type} is not supported"); } + var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); + x.For().Use(_ => serviceProvider.GetService()); + + x.For(typeof(ILogger<>)).Use(typeof(DummyLogger<>)); + x.Scan(_ => { - //_.Assembly("BirdsiteLive.Twitter"); - //_.Assembly("BirdsiteLive.Domain"); + _.Assembly("BirdsiteLive.Twitter"); + _.Assembly("BirdsiteLive.Domain"); _.Assembly("BirdsiteLive.DAL"); _.Assembly("BirdsiteLive.DAL.Postgres"); - //_.Assembly("BirdsiteLive.Moderation"); - //_.Assembly("BirdsiteLive.Pipeline"); + _.Assembly("BirdsiteLive.Moderation"); + _.TheCallingAssembly(); _.WithDefaultConventions(); @@ -58,5 +67,22 @@ namespace BSLManager }); return container; } + + public class DummyLogger : ILogger + { + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + } + + public bool IsEnabled(LogLevel logLevel) + { + return false; + } + + public IDisposable BeginScope(TState state) + { + return null; + } + } } } \ No newline at end of file diff --git a/src/BSLManager/Program.cs b/src/BSLManager/Program.cs index 2f90e8d..9fc3c04 100644 --- a/src/BSLManager/Program.cs +++ b/src/BSLManager/Program.cs @@ -23,9 +23,8 @@ namespace BSLManager var bootstrapper = new Bootstrapper(settings); var container = bootstrapper.Init(); - var followersDal = container.GetInstance(); - - await LaunchAppAsync(followersDal); + var app = container.GetInstance(); + app.Run(); } private static DbSettings GetSettings() @@ -37,119 +36,5 @@ namespace BSLManager var dbSettings = configuration.GetSection("Db").Get(); return dbSettings; } - - private static async Task LaunchAppAsync(IFollowersDal followersDal) - { - var followers = await followersDal.GetAllFollowersAsync(); - var orderedFollowers = followers.OrderByDescending(x => x.Followings.Count).ToList(); - - Application.Init(); - var top = Application.Top; - - // Creates the top-level window to show - var win = new Window("BSL Manager") - { - X = 0, - Y = 1, // Leave one row for the toplevel menu - - // By using Dim.Fill(), it will automatically resize without manual intervention - Width = Dim.Fill(), - Height = Dim.Fill() - }; - - top.Add(win); - - // Creates a menubar, the item "New" has a help menu. - var menu = new MenuBar(new MenuBarItem[] - { - new MenuBarItem("_File", new MenuItem[] - { - new MenuItem("_Quit", "", () => - { - if (Quit()) top.Running = false; - }) - }), - //new MenuBarItem ("_Edit", new MenuItem [] { - // new MenuItem ("_Copy", "", null), - // new MenuItem ("C_ut", "", null), - // new MenuItem ("_Paste", "", null) - //}) - }); - top.Add(menu); - - static bool Quit() - { - var n = MessageBox.Query(50, 7, "Quit BSL Manager", "Are you sure you want to quit?", "Yes", "No"); - return n == 0; - } - - var listData = new List(); - foreach (var follower in orderedFollowers) - { - listData.Add($"@{follower.Acct}@{follower.Host} {follower.Followings.Count}"); - } - - var list = new ListView(listData) - { - X = 1, - Y = 2, - Width = Dim.Fill(), - Height = Dim.Fill() - }; - - list.KeyDown += _ => - { - if (_.KeyEvent.Key == Key.Enter) - { - var el = list.SelectedItem; - - bool okpressed = false; - var ok = new Button(10, 14, "Yes"); - ok.Clicked += () => - { - Application.RequestStop(); - okpressed = true; - }; - - var cancel = new Button(3, 14, "No"); - cancel.Clicked += () => Application.RequestStop(); - - var dialog = new Dialog("Delete", 60, 18, cancel, ok); - - var name = new Label($"User: {listData[el]}") - { - X = 1, - Y = 1, - Width = Dim.Fill(), - Height = 1 - }; - var entry = new Label("Delete user and remove all their followings?") - { - X = 1, - Y = 3, - Width = Dim.Fill(), - Height = 1 - }; - dialog.Add(name); - dialog.Add(entry); - Application.Run(dialog); - - if (okpressed) - { - listData.RemoveAt(el); - typeof(Application).GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic) - .Invoke(null, null); - } - } - }; - - // Add some controls, - win.Add( - new Label(1, 0, "Listing followers"), - list - ); - - Application.Run(); - } } } From 25221c33e0489b6a987f2d1db3ca6b88ce2ed18a Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 18:49:12 -0400 Subject: [PATCH 3/9] user removal functionnal --- src/BSLManager/App.cs | 58 ++++++++++++++++++++++---------- src/BSLManager/BSLManager.csproj | 6 ++++ src/BSLManager/Bootstrapper.cs | 18 ++++++---- src/BSLManager/Program.cs | 19 ++++------- 4 files changed, 65 insertions(+), 36 deletions(-) diff --git a/src/BSLManager/App.cs b/src/BSLManager/App.cs index 3979ab6..12b2970 100644 --- a/src/BSLManager/App.cs +++ b/src/BSLManager/App.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; using BirdsiteLive.DAL.Contracts; +using BirdsiteLive.DAL.Models; using BirdsiteLive.Moderation.Actions; using Terminal.Gui; @@ -13,6 +14,9 @@ namespace BSLManager private readonly IFollowersDal _followersDal; private readonly IRemoveFollowerAction _removeFollowerAction; + private List _displayableUserList = new List(); + private List _sourceUserList = new List(); + #region Ctor public App(IFollowersDal followersDal, IRemoveFollowerAction removeFollowerAction) { @@ -62,22 +66,10 @@ namespace BSLManager var n = MessageBox.Query(50, 7, "Quit BSL Manager", "Are you sure you want to quit?", "Yes", "No"); return n == 0; } + + RetrieveUserList(); - var listData = new List(); - - Application.MainLoop.Invoke(async () => { - var followers = await _followersDal.GetAllFollowersAsync(); - var orderedFollowers = followers.OrderByDescending(x => x.Followings.Count).ToList(); - - foreach (var follower in orderedFollowers) - { - listData.Add($"@{follower.Acct}@{follower.Host} {follower.Followings.Count}"); - } - - RefreshUI(); - }); - - var list = new ListView(listData) + var list = new ListView(_displayableUserList) { X = 1, Y = 2, @@ -104,7 +96,7 @@ namespace BSLManager var dialog = new Dialog("Delete", 60, 18, cancel, ok); - var name = new Label($"User: {listData[el]}") + var name = new Label($"User: {_displayableUserList[el]}") { X = 1, Y = 1, @@ -124,8 +116,7 @@ namespace BSLManager if (okpressed) { - listData.RemoveAt(el); - RefreshUI(); + DeleteAndRemoveUser(el); } } }; @@ -139,6 +130,37 @@ namespace BSLManager Application.Run(); } + private void DeleteAndRemoveUser(int el) + { + Application.MainLoop.Invoke(async () => + { + var userToDelete = _sourceUserList[el]; + + await _removeFollowerAction.ProcessAsync(userToDelete); + + _sourceUserList.RemoveAt(el); + _displayableUserList.RemoveAt(el); + RefreshUI(); + }); + } + + private void RetrieveUserList() + { + Application.MainLoop.Invoke(async () => + { + var followers = await _followersDal.GetAllFollowersAsync(); + _sourceUserList = followers.OrderByDescending(x => x.Followings.Count).ToList(); + + _displayableUserList.Clear(); + foreach (var follower in _sourceUserList) + { + _displayableUserList.Add($"@{follower.Acct}@{follower.Host} {follower.Followings.Count}"); + } + + RefreshUI(); + }); + } + private void RefreshUI() { typeof(Application).GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic) diff --git a/src/BSLManager/BSLManager.csproj b/src/BSLManager/BSLManager.csproj index 8a3ef97..52e5cde 100644 --- a/src/BSLManager/BSLManager.csproj +++ b/src/BSLManager/BSLManager.csproj @@ -19,4 +19,10 @@ + + + PreserveNewest + + + diff --git a/src/BSLManager/Bootstrapper.cs b/src/BSLManager/Bootstrapper.cs index 1698d9a..7375cd6 100644 --- a/src/BSLManager/Bootstrapper.cs +++ b/src/BSLManager/Bootstrapper.cs @@ -14,12 +14,14 @@ namespace BSLManager { public class Bootstrapper { - private readonly DbSettings _settings; + private readonly DbSettings _dbSettings; + private readonly InstanceSettings _instanceSettings; #region Ctor - public Bootstrapper(DbSettings settings) + public Bootstrapper(DbSettings dbSettings, InstanceSettings instanceSettings) { - _settings = settings; + _dbSettings = dbSettings; + _instanceSettings = instanceSettings; } #endregion @@ -27,9 +29,13 @@ namespace BSLManager { var container = new Container(x => { - if (string.Equals(_settings.Type, DbTypes.Postgres, StringComparison.OrdinalIgnoreCase)) + x.For().Use(x => _dbSettings); + + x.For().Use(x => _instanceSettings); + + if (string.Equals(_dbSettings.Type, DbTypes.Postgres, StringComparison.OrdinalIgnoreCase)) { - var connString = $"Host={_settings.Host};Username={_settings.User};Password={_settings.Password};Database={_settings.Name}"; + var connString = $"Host={_dbSettings.Host};Username={_dbSettings.User};Password={_dbSettings.Password};Database={_dbSettings.Name}"; var postgresSettings = new PostgresSettings { ConnString = connString @@ -42,7 +48,7 @@ namespace BSLManager } else { - throw new NotImplementedException($"{_settings.Type} is not supported"); + throw new NotImplementedException($"{_dbSettings.Type} is not supported"); } var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); diff --git a/src/BSLManager/Program.cs b/src/BSLManager/Program.cs index 9fc3c04..ea2569c 100644 --- a/src/BSLManager/Program.cs +++ b/src/BSLManager/Program.cs @@ -18,23 +18,18 @@ namespace BSLManager { Console.OutputEncoding = Encoding.Default; - var settings = GetSettings(); - - var bootstrapper = new Bootstrapper(settings); - var container = bootstrapper.Init(); - - var app = container.GetInstance(); - app.Run(); - } - - private static DbSettings GetSettings() - { var builder = new ConfigurationBuilder() .AddEnvironmentVariables(); var configuration = builder.Build(); var dbSettings = configuration.GetSection("Db").Get(); - return dbSettings; + var instanceSettings = configuration.GetSection("Instance").Get(); + + var bootstrapper = new Bootstrapper(dbSettings, instanceSettings); + var container = bootstrapper.Init(); + + var app = container.GetInstance(); + app.Run(); } } } From 809a6b605fe2e97c85d63afd12fe1651a35f221a Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 19:46:51 -0400 Subject: [PATCH 4/9] added user filtering --- src/BSLManager/App.cs | 61 ++++++++------- src/BSLManager/Domain/FollowersListState.cs | 82 +++++++++++++++++++++ src/BSLManager/Tools/ConsoleGui.cs | 15 ++++ 3 files changed, 131 insertions(+), 27 deletions(-) create mode 100644 src/BSLManager/Domain/FollowersListState.cs create mode 100644 src/BSLManager/Tools/ConsoleGui.cs diff --git a/src/BSLManager/App.cs b/src/BSLManager/App.cs index 12b2970..39c1f33 100644 --- a/src/BSLManager/App.cs +++ b/src/BSLManager/App.cs @@ -5,6 +5,8 @@ using System.Threading.Tasks; using BirdsiteLive.DAL.Contracts; using BirdsiteLive.DAL.Models; using BirdsiteLive.Moderation.Actions; +using BSLManager.Domain; +using BSLManager.Tools; using Terminal.Gui; namespace BSLManager @@ -14,8 +16,7 @@ namespace BSLManager private readonly IFollowersDal _followersDal; private readonly IRemoveFollowerAction _removeFollowerAction; - private List _displayableUserList = new List(); - private List _sourceUserList = new List(); + private readonly FollowersListState _state = new FollowersListState(); #region Ctor public App(IFollowersDal followersDal, IRemoveFollowerAction removeFollowerAction) @@ -69,10 +70,10 @@ namespace BSLManager RetrieveUserList(); - var list = new ListView(_displayableUserList) + var list = new ListView(_state.GetDisplayableList()) { X = 1, - Y = 2, + Y = 3, Width = Dim.Fill(), Height = Dim.Fill() }; @@ -96,7 +97,8 @@ namespace BSLManager var dialog = new Dialog("Delete", 60, 18, cancel, ok); - var name = new Label($"User: {_displayableUserList[el]}") + var follower = _state.GetElementAt(el); + var name = new Label($"User: @{follower.Acct}@{follower.Host}") { X = 1, Y = 1, @@ -121,9 +123,29 @@ namespace BSLManager } }; - // Add some controls, + var listingFollowersLabel = new Label(1, 0, "Listing followers"); + var filterLabel = new Label("Filter: ") { X = 1, Y = 1 }; + var filterText = new TextField("") + { + X = Pos.Right(filterLabel), + Y = 1, + Width = 40 + }; + + filterText.KeyDown += _ => + { + var text = filterText.Text.ToString(); + if (_.KeyEvent.Key == Key.Enter && !string.IsNullOrWhiteSpace(text)) + { + _state.FilterBy(text); + ConsoleGui.RefreshUI(); + } + }; + win.Add( - new Label(1, 0, "Listing followers"), + listingFollowersLabel, + filterLabel, + filterText, list ); @@ -134,13 +156,11 @@ namespace BSLManager { Application.MainLoop.Invoke(async () => { - var userToDelete = _sourceUserList[el]; - + var userToDelete = _state.GetElementAt(el); await _removeFollowerAction.ProcessAsync(userToDelete); + _state.RemoveAt(el); - _sourceUserList.RemoveAt(el); - _displayableUserList.RemoveAt(el); - RefreshUI(); + ConsoleGui.RefreshUI(); }); } @@ -149,22 +169,9 @@ namespace BSLManager Application.MainLoop.Invoke(async () => { var followers = await _followersDal.GetAllFollowersAsync(); - _sourceUserList = followers.OrderByDescending(x => x.Followings.Count).ToList(); - - _displayableUserList.Clear(); - foreach (var follower in _sourceUserList) - { - _displayableUserList.Add($"@{follower.Acct}@{follower.Host} {follower.Followings.Count}"); - } - - RefreshUI(); + _state.Load(followers.ToList()); + ConsoleGui.RefreshUI(); }); } - - private void RefreshUI() - { - typeof(Application).GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic) - .Invoke(null, null); - } } } \ No newline at end of file diff --git a/src/BSLManager/Domain/FollowersListState.cs b/src/BSLManager/Domain/FollowersListState.cs new file mode 100644 index 0000000..15b9b2a --- /dev/null +++ b/src/BSLManager/Domain/FollowersListState.cs @@ -0,0 +1,82 @@ +using System.Collections.Generic; +using System.Linq; +using BirdsiteLive.DAL.Models; + +namespace BSLManager.Domain +{ + public class FollowersListState + { + private List _displayableUserList = new List(); + private List _sourceUserList = new List(); + + private List _filteredDisplayableUserList = new List(); + private List _filteredSourceUserList = new List(); + + public void Load(List followers) + { + _sourceUserList = followers.OrderByDescending(x => x.Followings.Count).ToList(); + + ResetLists(); + } + + private void ResetLists() + { + _filteredSourceUserList = _sourceUserList.ToList(); + + _displayableUserList.Clear(); + _filteredDisplayableUserList.Clear(); + + foreach (var follower in _sourceUserList) + { + var displayedUser = $"{GetFullHandle(follower)} ({follower.Followings.Count})"; + _displayableUserList.Add(displayedUser); + _filteredDisplayableUserList.Add(displayedUser); + } + } + + public List GetDisplayableList() + { + return _filteredDisplayableUserList; + } + + public void FilterBy(string pattern) + { + ResetLists(); + + if (!string.IsNullOrWhiteSpace(pattern)) + { + var elToRemove = _filteredSourceUserList + .Where(x => !GetFullHandle(x).Contains(pattern)) + .Select(x => x) + .ToList(); + + foreach (var el in elToRemove) + { + _filteredSourceUserList.Remove(el); + + var dElToRemove = _filteredDisplayableUserList.First(x => x.Contains(GetFullHandle(el))); + _filteredDisplayableUserList.Remove(dElToRemove); + } + } + } + + private string GetFullHandle(Follower follower) + { + return $"@{follower.Acct}@{follower.Host}"; + } + + public void RemoveAt(int index) + { + var displayableUser = _filteredDisplayableUserList[index]; + var sourceUser = _filteredSourceUserList[index]; + + _displayableUserList.Remove(displayableUser); + _sourceUserList.Remove(sourceUser); + } + + public Follower GetElementAt(int index) + { + return _filteredSourceUserList[index]; + } + } +} \ No newline at end of file diff --git a/src/BSLManager/Tools/ConsoleGui.cs b/src/BSLManager/Tools/ConsoleGui.cs new file mode 100644 index 0000000..b6f7b6e --- /dev/null +++ b/src/BSLManager/Tools/ConsoleGui.cs @@ -0,0 +1,15 @@ +using System.Reflection; +using Terminal.Gui; + +namespace BSLManager.Tools +{ + public static class ConsoleGui + { + public static void RefreshUI() + { + typeof(Application) + .GetMethod("TerminalResized", BindingFlags.Static | BindingFlags.NonPublic) + .Invoke(null, null); + } + } +} \ No newline at end of file From 2aa7e89e1abda8c97f9a7d14adc1e3ab5c7b3cbd Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 19:58:04 -0400 Subject: [PATCH 5/9] added info box --- src/BSLManager/App.cs | 132 ++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 38 deletions(-) diff --git a/src/BSLManager/App.cs b/src/BSLManager/App.cs index 39c1f33..3f89294 100644 --- a/src/BSLManager/App.cs +++ b/src/BSLManager/App.cs @@ -82,44 +82,14 @@ namespace BSLManager { if (_.KeyEvent.Key == Key.Enter) { - var el = list.SelectedItem; - - bool okpressed = false; - var ok = new Button(10, 14, "Yes"); - ok.Clicked += () => - { - Application.RequestStop(); - okpressed = true; - }; - - var cancel = new Button(3, 14, "No"); - cancel.Clicked += () => Application.RequestStop(); - - var dialog = new Dialog("Delete", 60, 18, cancel, ok); - - var follower = _state.GetElementAt(el); - var name = new Label($"User: @{follower.Acct}@{follower.Host}") - { - X = 1, - Y = 1, - Width = Dim.Fill(), - Height = 1 - }; - var entry = new Label("Delete user and remove all their followings?") - { - X = 1, - Y = 3, - Width = Dim.Fill(), - Height = 1 - }; - dialog.Add(name); - dialog.Add(entry); - Application.Run(dialog); - - if (okpressed) - { - DeleteAndRemoveUser(el); - } + OpenFollowerDialog(list.SelectedItem); + } + else if (_.KeyEvent.Key == Key.Delete + || _.KeyEvent.Key == Key.DeleteChar + || _.KeyEvent.Key == Key.Backspace + || _.KeyEvent.Key == Key.D) + { + OpenDeleteDialog(list.SelectedItem); } }; @@ -152,6 +122,92 @@ namespace BSLManager Application.Run(); } + private void OpenFollowerDialog(int selectedIndex) + { + var close = new Button(3, 14, "Close"); + close.Clicked += () => Application.RequestStop(); + + var dialog = new Dialog("Info", 60, 18, close); + + var follower = _state.GetElementAt(selectedIndex); + + var name = new Label($"User: @{follower.Acct}@{follower.Host}") + { + X = 1, + Y = 1, + Width = Dim.Fill(), + Height = 1 + }; + var following = new Label($"Following Count: {follower.Followings.Count}") + { + X = 1, + Y = 3, + Width = Dim.Fill(), + Height = 1 + }; + var inbox = new Label($"Inbox: {follower.InboxRoute}") + { + X = 1, + Y = 4, + Width = Dim.Fill(), + Height = 1 + }; + var sharedInbox = new Label($"Shared Inbox: {follower.SharedInboxRoute}") + { + X = 1, + Y = 5, + Width = Dim.Fill(), + Height = 1 + }; + + dialog.Add(name); + dialog.Add(following); + dialog.Add(inbox); + dialog.Add(sharedInbox); + dialog.Add(close); + Application.Run(dialog); + } + + private void OpenDeleteDialog(int selectedIndex) + { + bool okpressed = false; + var ok = new Button(10, 14, "Yes"); + ok.Clicked += () => + { + Application.RequestStop(); + okpressed = true; + }; + + var cancel = new Button(3, 14, "No"); + cancel.Clicked += () => Application.RequestStop(); + + var dialog = new Dialog("Delete", 60, 18, cancel, ok); + + var follower = _state.GetElementAt(selectedIndex); + var name = new Label($"User: @{follower.Acct}@{follower.Host}") + { + X = 1, + Y = 1, + Width = Dim.Fill(), + Height = 1 + }; + var entry = new Label("Delete user and remove all their followings?") + { + X = 1, + Y = 3, + Width = Dim.Fill(), + Height = 1 + }; + dialog.Add(name); + dialog.Add(entry); + Application.Run(dialog); + + if (okpressed) + { + DeleteAndRemoveUser(selectedIndex); + } + } + private void DeleteAndRemoveUser(int el) { Application.MainLoop.Invoke(async () => From e64d584ca097ce2e680bf00d7abd3655c3cfd0f7 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 20:09:07 -0400 Subject: [PATCH 6/9] fix removal --- src/BSLManager/Domain/FollowersListState.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/BSLManager/Domain/FollowersListState.cs b/src/BSLManager/Domain/FollowersListState.cs index 15b9b2a..8cf4fd9 100644 --- a/src/BSLManager/Domain/FollowersListState.cs +++ b/src/BSLManager/Domain/FollowersListState.cs @@ -70,7 +70,10 @@ namespace BSLManager.Domain var displayableUser = _filteredDisplayableUserList[index]; var sourceUser = _filteredSourceUserList[index]; + _filteredDisplayableUserList.Remove(displayableUser); _displayableUserList.Remove(displayableUser); + + _filteredSourceUserList.Remove(sourceUser); _sourceUserList.Remove(sourceUser); } From 13026a56add7fef3439376b0385edb1ed9d2b55a Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 20:11:28 -0400 Subject: [PATCH 7/9] clean up --- src/BSLManager/Domain/FollowersListState.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/BSLManager/Domain/FollowersListState.cs b/src/BSLManager/Domain/FollowersListState.cs index 8cf4fd9..f33acb8 100644 --- a/src/BSLManager/Domain/FollowersListState.cs +++ b/src/BSLManager/Domain/FollowersListState.cs @@ -6,10 +6,9 @@ namespace BSLManager.Domain { public class FollowersListState { - private List _displayableUserList = new List(); - private List _sourceUserList = new List(); + private readonly List _filteredDisplayableUserList = new List(); - private List _filteredDisplayableUserList = new List(); + private List _sourceUserList = new List(); private List _filteredSourceUserList = new List(); public void Load(List followers) @@ -23,13 +22,11 @@ namespace BSLManager.Domain { _filteredSourceUserList = _sourceUserList.ToList(); - _displayableUserList.Clear(); _filteredDisplayableUserList.Clear(); foreach (var follower in _sourceUserList) { var displayedUser = $"{GetFullHandle(follower)} ({follower.Followings.Count})"; - _displayableUserList.Add(displayedUser); _filteredDisplayableUserList.Add(displayedUser); } } @@ -71,7 +68,6 @@ namespace BSLManager.Domain var sourceUser = _filteredSourceUserList[index]; _filteredDisplayableUserList.Remove(displayableUser); - _displayableUserList.Remove(displayableUser); _filteredSourceUserList.Remove(sourceUser); _sourceUserList.Remove(sourceUser); From 77088c78a4334d2efed1ea38d3ef6602e0c8a8fc Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Thu, 15 Apr 2021 23:22:05 -0400 Subject: [PATCH 8/9] added followersListState tests --- src/BirdsiteLive.sln | 9 +- .../BSLManager.Tests/BSLManager.Tests.csproj | 20 ++ .../Domain/FollowersListStateTests.cs | 307 ++++++++++++++++++ 3 files changed, 335 insertions(+), 1 deletion(-) create mode 100644 src/Tests/BSLManager.Tests/BSLManager.Tests.csproj create mode 100644 src/Tests/BSLManager.Tests/Domain/FollowersListStateTests.cs diff --git a/src/BirdsiteLive.sln b/src/BirdsiteLive.sln index ba118c6..4b0cfc1 100644 --- a/src/BirdsiteLive.sln +++ b/src/BirdsiteLive.sln @@ -47,7 +47,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Moderation.Tes EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BirdsiteLive.Common.Tests", "Tests\BirdsiteLive.Common.Tests\BirdsiteLive.Common.Tests.csproj", "{C69F7582-6050-44DC-BAAB-7C8F0BDA525C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSLManager", "BSLManager\BSLManager.csproj", "{4A84D351-E91B-4E58-8E20-211F0F4991D7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BSLManager", "BSLManager\BSLManager.csproj", "{4A84D351-E91B-4E58-8E20-211F0F4991D7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSLManager.Tests", "Tests\BSLManager.Tests\BSLManager.Tests.csproj", "{D4457271-620E-465A-B08E-7FC63C99A2F6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -131,6 +133,10 @@ Global {4A84D351-E91B-4E58-8E20-211F0F4991D7}.Debug|Any CPU.Build.0 = Debug|Any CPU {4A84D351-E91B-4E58-8E20-211F0F4991D7}.Release|Any CPU.ActiveCfg = Release|Any CPU {4A84D351-E91B-4E58-8E20-211F0F4991D7}.Release|Any CPU.Build.0 = Release|Any CPU + {D4457271-620E-465A-B08E-7FC63C99A2F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4457271-620E-465A-B08E-7FC63C99A2F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4457271-620E-465A-B08E-7FC63C99A2F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4457271-620E-465A-B08E-7FC63C99A2F6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -153,6 +159,7 @@ Global {4BE541AC-8A93-4FA3-98AC-956CC2D5B748} = {DA3C160C-4811-4E26-A5AD-42B81FAF2D7C} {0A311BF3-4FD9-4303-940A-A3778890561C} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94} {C69F7582-6050-44DC-BAAB-7C8F0BDA525C} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94} + {D4457271-620E-465A-B08E-7FC63C99A2F6} = {A32D3458-09D0-4E0A-BA4B-8C411B816B94} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {69E8DCAD-4C37-4010-858F-5F94E6FBABCE} diff --git a/src/Tests/BSLManager.Tests/BSLManager.Tests.csproj b/src/Tests/BSLManager.Tests/BSLManager.Tests.csproj new file mode 100644 index 0000000..033cfe1 --- /dev/null +++ b/src/Tests/BSLManager.Tests/BSLManager.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + + false + + + + + + + + + + + + + + diff --git a/src/Tests/BSLManager.Tests/Domain/FollowersListStateTests.cs b/src/Tests/BSLManager.Tests/Domain/FollowersListStateTests.cs new file mode 100644 index 0000000..a0171a4 --- /dev/null +++ b/src/Tests/BSLManager.Tests/Domain/FollowersListStateTests.cs @@ -0,0 +1,307 @@ +using System.Collections.Generic; +using System.Linq; +using BirdsiteLive.DAL.Models; +using BSLManager.Domain; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace BSLManager.Tests +{ + [TestClass] + public class FollowersListStateTests + { + [TestMethod] + public void FilterBy() + { + #region Stub + var followers = new List + { + new Follower + { + Id = 0, + Acct = "test", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 1, + Acct = "test", + Host = "host2", + Followings = new List() + }, + new Follower + { + Id = 2, + Acct = "user1", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 3, + Acct = "user2", + Host = "host1", + Followings = new List() + } + }; + #endregion + + var state = new FollowersListState(); + state.Load(followers); + + state.FilterBy("test"); + + #region Validate + Assert.AreEqual(2, state.GetDisplayableList().Count); + #endregion + } + + [TestMethod] + public void FilterBy_GetElement() + { + #region Stub + var followers = new List + { + new Follower + { + Id = 0, + Acct = "test", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 1, + Acct = "test", + Host = "host2", + Followings = new List() + }, + new Follower + { + Id = 2, + Acct = "user1", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 3, + Acct = "user2", + Host = "host1", + Followings = new List() + } + }; + #endregion + + var state = new FollowersListState(); + state.Load(followers); + + state.FilterBy("test"); + var el = state.GetElementAt(1); + + #region Validate + Assert.AreEqual(followers[1].Id, el.Id); + #endregion + } + + [TestMethod] + public void GetElement() + { + #region Stub + var followers = new List + { + new Follower + { + Id = 0, + Acct = "test", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 1, + Acct = "test", + Host = "host2", + Followings = new List() + }, + new Follower + { + Id = 2, + Acct = "user1", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 3, + Acct = "user2", + Host = "host1", + Followings = new List() + } + }; + #endregion + + var state = new FollowersListState(); + state.Load(followers); + + var el = state.GetElementAt(2); + + #region Validate + Assert.AreEqual(followers[2].Id, el.Id); + #endregion + } + + [TestMethod] + public void FilterBy_RemoveAt() + { + #region Stub + var followers = new List + { + new Follower + { + Id = 0, + Acct = "test", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 1, + Acct = "test", + Host = "host2", + Followings = new List() + }, + new Follower + { + Id = 2, + Acct = "user1", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 3, + Acct = "user2", + Host = "host1", + Followings = new List() + } + }; + #endregion + + var state = new FollowersListState(); + state.Load(followers.ToList()); + + state.FilterBy("test"); + state.RemoveAt(1); + + var list = state.GetDisplayableList(); + + #region Validate + Assert.AreEqual(1, list.Count); + Assert.IsTrue(list[0].Contains("@test@host1")); + #endregion + } + + [TestMethod] + public void RemoveAt() + { + #region Stub + var followers = new List + { + new Follower + { + Id = 0, + Acct = "test", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 1, + Acct = "test", + Host = "host2", + Followings = new List() + }, + new Follower + { + Id = 2, + Acct = "user1", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 3, + Acct = "user2", + Host = "host1", + Followings = new List() + } + }; + #endregion + + var state = new FollowersListState(); + state.Load(followers.ToList()); + + state.RemoveAt(1); + + var list = state.GetDisplayableList(); + + #region Validate + Assert.AreEqual(3, list.Count); + Assert.IsTrue(list[0].Contains("@test@host1")); + Assert.IsFalse(list[1].Contains("@test@host2")); + #endregion + } + + [TestMethod] + public void FilterBy_ResetFilter() + { + #region Stub + var followers = new List + { + new Follower + { + Id = 0, + Acct = "test", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 1, + Acct = "test", + Host = "host2", + Followings = new List() + }, + new Follower + { + Id = 2, + Acct = "user1", + Host = "host1", + Followings = new List() + }, + new Follower + { + Id = 3, + Acct = "user2", + Host = "host1", + Followings = new List() + } + }; + #endregion + + var state = new FollowersListState(); + state.Load(followers.ToList()); + + #region Validate + state.FilterBy("data"); + var list = state.GetDisplayableList(); + Assert.AreEqual(0, list.Count); + + state.FilterBy(string.Empty); + list = state.GetDisplayableList(); + Assert.AreEqual(4, list.Count); + #endregion + } + } +} From bc0e6e95d6a760fd965b427c25dac2013bdebe94 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 16 Apr 2021 00:06:36 -0400 Subject: [PATCH 9/9] simplify dockerfile --- Dockerfile | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7239ca2..ae4a0ba 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,13 +5,8 @@ WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS publish COPY ./src/ ./src/ -RUN dotnet restore "/src/BirdsiteLive/BirdsiteLive.csproj" -RUN dotnet restore "/src/BSLManager/BSLManager.csproj" -RUN dotnet build "/src/BirdsiteLive/BirdsiteLive.csproj" -c Release -o /app/build - -FROM build AS publish RUN dotnet publish "/src/BirdsiteLive/BirdsiteLive.csproj" -c Release -o /app/publish RUN dotnet publish "/src/BSLManager/BSLManager.csproj" -r linux-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeAllContentForSelfExtract=true -c Release -o /app/publish