From 8d0a612238ec3be2fc56d28a18512da1bc189ec8 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Sun, 11 Apr 2021 02:15:13 -0400 Subject: [PATCH 01/18] 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 02/18] 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 03/18] 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 04/18] 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 05/18] 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 06/18] 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 07/18] 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 ed7ac5303eefc232984cd0c5b7838841dc2ba3f5 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Thu, 15 Apr 2021 21:21:22 -0400 Subject: [PATCH 08/18] Added Trace Info --- src/BirdsiteLive/Controllers/InboxController.cs | 12 ++++++++++++ src/BirdsiteLive/Controllers/UsersController.cs | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/BirdsiteLive/Controllers/InboxController.cs b/src/BirdsiteLive/Controllers/InboxController.cs index a0d8748..db055cf 100644 --- a/src/BirdsiteLive/Controllers/InboxController.cs +++ b/src/BirdsiteLive/Controllers/InboxController.cs @@ -5,12 +5,22 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; namespace BirdsiteLive.Controllers { [ApiController] public class InboxController : ControllerBase { + private readonly ILogger _logger; + + #region Ctor + public InboxController(ILogger logger) + { + _logger = logger; + } + #endregion + [Route("/inbox")] [HttpPost] public async Task Inbox() @@ -19,6 +29,8 @@ namespace BirdsiteLive.Controllers using (var reader = new StreamReader(Request.Body)) { var body = await reader.ReadToEndAsync(); + + _logger.LogTrace("Inbox: {Body}", body); //System.IO.File.WriteAllText($@"C:\apdebug\inbox\{Guid.NewGuid()}.json", body); } diff --git a/src/BirdsiteLive/Controllers/UsersController.cs b/src/BirdsiteLive/Controllers/UsersController.cs index a06b1e9..8240d7b 100644 --- a/src/BirdsiteLive/Controllers/UsersController.cs +++ b/src/BirdsiteLive/Controllers/UsersController.cs @@ -17,6 +17,7 @@ using BirdsiteLive.Twitter; using BirdsiteLive.Twitter.Models; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using Newtonsoft.Json; @@ -29,15 +30,17 @@ namespace BirdsiteLive.Controllers private readonly IUserService _userService; private readonly IStatusService _statusService; private readonly InstanceSettings _instanceSettings; + private readonly ILogger _logger; #region Ctor - public UsersController(ITwitterUserService twitterUserService, IUserService userService, IStatusService statusService, InstanceSettings instanceSettings, ITwitterTweetsService twitterTweetService) + public UsersController(ITwitterUserService twitterUserService, IUserService userService, IStatusService statusService, InstanceSettings instanceSettings, ITwitterTweetsService twitterTweetService, ILogger logger) { _twitterUserService = twitterUserService; _userService = userService; _statusService = statusService; _instanceSettings = instanceSettings; _twitterTweetService = twitterTweetService; + _logger = logger; } #endregion @@ -57,6 +60,8 @@ namespace BirdsiteLive.Controllers [Route("/users/{id}")] public IActionResult Index(string id) { + _logger.LogTrace("User Index: {Id}", id); + id = id.Trim(new[] { ' ', '@' }).ToLowerInvariant(); // Ensure valid username @@ -131,6 +136,8 @@ namespace BirdsiteLive.Controllers using (var reader = new StreamReader(Request.Body)) { var body = await reader.ReadToEndAsync(); + + _logger.LogTrace("User Inbox: {Body}", body); //System.IO.File.WriteAllText($@"C:\apdebug\{Guid.NewGuid()}.json", body); var activity = ApDeserializer.ProcessActivity(body); From 77088c78a4334d2efed1ea38d3ef6602e0c8a8fc Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Thu, 15 Apr 2021 23:22:05 -0400 Subject: [PATCH 09/18] 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 10/18] 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 From 2b09bc37f8fdbc2dbeea1926b865aef844f2fae2 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 19:34:41 -0400 Subject: [PATCH 11/18] fix docker images --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ae4a0ba..11a4422 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base +FROM mcr.microsoft.com/dotnet/aspnet:3.1-buster-slim AS base WORKDIR /app EXPOSE 80 EXPOSE 443 -FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS publish +FROM mcr.microsoft.com/dotnet/sdk:3.1-buster AS publish COPY ./src/ ./src/ 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 From 7ed993e51ddcb32ea685ccbc873ed23a3be5b4e6 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 21:07:47 -0400 Subject: [PATCH 12/18] getting settings manually --- src/BSLManager/Program.cs | 16 ++-- src/BSLManager/Tools/SettingsManager.cs | 117 ++++++++++++++++++++++++ 2 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 src/BSLManager/Tools/SettingsManager.cs diff --git a/src/BSLManager/Program.cs b/src/BSLManager/Program.cs index ea2569c..629ff25 100644 --- a/src/BSLManager/Program.cs +++ b/src/BSLManager/Program.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using BirdsiteLive.Common.Settings; using BirdsiteLive.DAL.Contracts; +using BSLManager.Tools; using Microsoft.Extensions.Configuration; using NStack; using Terminal.Gui; @@ -18,14 +19,17 @@ namespace BSLManager { Console.OutputEncoding = Encoding.Default; - var builder = new ConfigurationBuilder() - .AddEnvironmentVariables(); - var configuration = builder.Build(); + var settingsManager = new SettingsManager(); + var settings = settingsManager.GetSettings(); - var dbSettings = configuration.GetSection("Db").Get(); - var instanceSettings = configuration.GetSection("Instance").Get(); + //var builder = new ConfigurationBuilder() + // .AddEnvironmentVariables(); + //var configuration = builder.Build(); - var bootstrapper = new Bootstrapper(dbSettings, instanceSettings); + //var dbSettings = configuration.GetSection("Db").Get(); + //var instanceSettings = configuration.GetSection("Instance").Get(); + + var bootstrapper = new Bootstrapper(settings.dbSettings, settings.instanceSettings); var container = bootstrapper.Init(); var app = container.GetInstance(); diff --git a/src/BSLManager/Tools/SettingsManager.cs b/src/BSLManager/Tools/SettingsManager.cs new file mode 100644 index 0000000..db98d71 --- /dev/null +++ b/src/BSLManager/Tools/SettingsManager.cs @@ -0,0 +1,117 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using BirdsiteLive.Common.Settings; +using Newtonsoft.Json; +using Org.BouncyCastle.Asn1.IsisMtt.X509; + +namespace BSLManager.Tools +{ + public class SettingsManager + { + private const string LocalFileName = "ManagerSettings.json"; + + public (DbSettings dbSettings, InstanceSettings instanceSettings) GetSettings() + { + var localSettingsData = GetLocalSettingsFile(); + if (localSettingsData != null) return Convert(localSettingsData); + + Console.WriteLine("We need to set up the manager"); + Console.WriteLine("Please provide the following information as provided in the docker-compose file"); + + LocalSettingsData data; + do + { + data = GetDataFromUser(); + Console.WriteLine(); + Console.WriteLine("Please check if all is ok:"); + Console.WriteLine(); + Console.WriteLine($"Db Host: {data.DbHost}"); + Console.WriteLine($"Db Name: {data.DbName}"); + Console.WriteLine($"Db User: {data.DbUser}"); + Console.WriteLine($"Db Password: {data.DbPassword}"); + Console.WriteLine($"Instance Domain: {data.InstanceDomain}"); + Console.WriteLine(); + + string resp; + do + { + Console.WriteLine("Is it valid? (yes, no)"); + resp = Console.ReadLine()?.Trim().ToLowerInvariant(); + + if (resp == "n" || resp == "no") data = null; + + } while (resp != "y" && resp != "yes" && resp != "n" && resp != "no"); + + } while (data == null); + + SaveLocalSettings(data); + return Convert(data); + } + + private LocalSettingsData GetDataFromUser() + { + var data = new LocalSettingsData(); + + Console.WriteLine("Db Host:"); + data.DbHost = Console.ReadLine(); + + Console.WriteLine("Db Name:"); + data.DbName = Console.ReadLine(); + + Console.WriteLine("Db User:"); + data.DbUser = Console.ReadLine(); + + Console.WriteLine("Db Password:"); + data.DbPassword = Console.ReadLine(); + + Console.WriteLine("Instance Domain:"); + data.InstanceDomain = Console.ReadLine(); + + return data; + } + + private (DbSettings dbSettings, InstanceSettings instanceSettings) Convert(LocalSettingsData data) + { + var dbSettings = new DbSettings + { + Type = data.DbType, + Host = data.DbHost, + Name = data.DbName, + User = data.DbUser, + Password = data.DbPassword + }; + var instancesSettings = new InstanceSettings + { + Domain = data.InstanceDomain + }; + return (dbSettings, instancesSettings); + } + + private LocalSettingsData GetLocalSettingsFile() + { + if (!File.Exists(LocalFileName)) return null; + + var jsonContent = File.ReadAllText(LocalFileName); + var content = JsonConvert.DeserializeObject(jsonContent); + return content; + } + + private void SaveLocalSettings(LocalSettingsData data) + { + var jsonContent = JsonConvert.SerializeObject(data); + File.WriteAllText(LocalFileName, jsonContent); + } + } + + internal class LocalSettingsData + { + public string DbType { get; set; } = "postgres"; + public string DbHost { get; set; } + public string DbName { get; set; } + public string DbUser { get; set; } + public string DbPassword { get; set; } + + public string InstanceDomain { get; set; } + } +} \ No newline at end of file From 0e787bbca8ef202523c5f531ae9dc56e75801325 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 21:09:09 -0400 Subject: [PATCH 13/18] better deserialization --- src/BSLManager/Tools/SettingsManager.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/BSLManager/Tools/SettingsManager.cs b/src/BSLManager/Tools/SettingsManager.cs index db98d71..5ff6314 100644 --- a/src/BSLManager/Tools/SettingsManager.cs +++ b/src/BSLManager/Tools/SettingsManager.cs @@ -90,11 +90,18 @@ namespace BSLManager.Tools private LocalSettingsData GetLocalSettingsFile() { - if (!File.Exists(LocalFileName)) return null; + try + { + if (!File.Exists(LocalFileName)) return null; - var jsonContent = File.ReadAllText(LocalFileName); - var content = JsonConvert.DeserializeObject(jsonContent); - return content; + var jsonContent = File.ReadAllText(LocalFileName); + var content = JsonConvert.DeserializeObject(jsonContent); + return content; + } + catch (Exception) + { + return null; + } } private void SaveLocalSettings(LocalSettingsData data) From 0896e8a2bf375537984d86c21fa200be7850712c Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 22:11:34 -0400 Subject: [PATCH 14/18] Create BSLManager.md --- BSLManager.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 BSLManager.md diff --git a/BSLManager.md b/BSLManager.md new file mode 100644 index 0000000..a9f8475 --- /dev/null +++ b/BSLManager.md @@ -0,0 +1,49 @@ +# BSLManager + +A CLI is provided in the Docker image so that admins can manage their instance. + +## Access to the CLI + +Since the CLI is packaged into the docker image, you'll have to open a shell from the container. To do so, list first your running containers: + +``` +docker ps +``` + +This should display you something equivalent to this: + +``` +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +3734c41af5a7 postgres:9.6 "docker-entrypoint.s…" 2 weeks ago Up 2 weeks 5432/tcp db_1 +be6870fe103e nicolasconstant/birdsitelive:latest "dotnet BirdsiteLive…" 6 weeks ago Up 2 weeks 443/tcp, 0.0.0.0:5000->80/tcp birdsitelive +``` + +Find the BSL container and keep the ID, here it's `be6870fe103e`. And you only need the three first char to identify it, so we'll be using `be6`. + +Then open a shell inside the container (change `be6` with your own id): + +``` +docker exec -it be6 /bin/bash +``` + +And you should now be inside the container, and all you have to do is calling the CLI: + +``` +./BSLManager +``` + +## Setting up the CLI + +The manager will ask you to provide information about the database and the instance. +Those must be same than the ones in the `docker-compose.yml` file. +Provide the information, review it and validate it. Then the CLI UI should shows up. + +## Using the CLI + +You can navigate between the sections with the arrows and tab keys. + +The **filter** permits to filter the list of users with a pattern. + +All users have their followings count provided next to them. +You can select any user by using the up/down arrow keys and hitting the `Enter` key, this will display more information about the user. +You can also remove a user and all their followings by hitting the `Del` key. You will be prompted by a confirmation message, and you'll be able to remove this user. From a9a59eb4336006df512654d6bb23ea98b4f619bf Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 22:12:49 -0400 Subject: [PATCH 15/18] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 241316e..da3e83b 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ You can find an official (and temporary) instance here: [beta.birdsite.live](htt I'm providing a [docker build](https://hub.docker.com/r/nicolasconstant/birdsitelive). To install it on your own server, please follow [those instructions](https://github.com/NicolasConstant/BirdsiteLive/blob/master/INSTALLATION.md). More [options](https://github.com/NicolasConstant/BirdsiteLive/blob/master/VARIABLES.md) are also available. +Also a [CLI](https://github.com/NicolasConstant/BirdsiteLive/blob/master/BSLManager.md) is available for adminitrative tasks. + ## License This project is licensed under the AGPLv3 License - see [LICENSE](https://github.com/NicolasConstant/BirdsiteLive/blob/master/LICENSE) for details. From 9686d6187d18fd48b3da44ac8cdfaa7aaeb83d35 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 23:13:22 -0400 Subject: [PATCH 16/18] added basic logging --- src/BSLManager/App.cs | 19 +++++++++++++++---- src/BSLManager/Tools/BasicLogger.cs | 13 +++++++++++++ .../Processors/FollowerModerationProcessor.cs | 6 +++++- 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 src/BSLManager/Tools/BasicLogger.cs diff --git a/src/BSLManager/App.cs b/src/BSLManager/App.cs index 3f89294..0e48262 100644 --- a/src/BSLManager/App.cs +++ b/src/BSLManager/App.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -212,9 +213,19 @@ namespace BSLManager { Application.MainLoop.Invoke(async () => { - var userToDelete = _state.GetElementAt(el); - await _removeFollowerAction.ProcessAsync(userToDelete); - _state.RemoveAt(el); + try + { + var userToDelete = _state.GetElementAt(el); + + BasicLogger.Log($"Delete {userToDelete.Acct}@{userToDelete.Host}"); + await _removeFollowerAction.ProcessAsync(userToDelete); + BasicLogger.Log($"Remove user from list"); + _state.RemoveAt(el); + } + catch (Exception e) + { + BasicLogger.Log(e.Message); + } ConsoleGui.RefreshUI(); }); diff --git a/src/BSLManager/Tools/BasicLogger.cs b/src/BSLManager/Tools/BasicLogger.cs new file mode 100644 index 0000000..dbb9265 --- /dev/null +++ b/src/BSLManager/Tools/BasicLogger.cs @@ -0,0 +1,13 @@ +using System; +using System.IO; + +namespace BSLManager.Tools +{ + public static class BasicLogger + { + public static void Log(string log) + { + File.AppendAllLines($"Log-{Guid.NewGuid()}.txt", new []{ log }); + } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Moderation/Processors/FollowerModerationProcessor.cs b/src/BirdsiteLive.Moderation/Processors/FollowerModerationProcessor.cs index 99d72f6..d697351 100644 --- a/src/BirdsiteLive.Moderation/Processors/FollowerModerationProcessor.cs +++ b/src/BirdsiteLive.Moderation/Processors/FollowerModerationProcessor.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using BirdsiteLive.DAL.Contracts; using BirdsiteLive.Domain.Repository; using BirdsiteLive.Moderation.Actions; @@ -38,7 +39,10 @@ namespace BirdsiteLive.Moderation.Processors if (type == ModerationTypeEnum.WhiteListing && status != ModeratedTypeEnum.WhiteListed || type == ModerationTypeEnum.BlackListing && status == ModeratedTypeEnum.BlackListed) + { + Console.WriteLine($"Remove {followerHandle}"); await _removeFollowerAction.ProcessAsync(follower); + } } } } From 2730c40ae809f162609094746e2f5488aac33ca6 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 23:31:02 -0400 Subject: [PATCH 17/18] Update BSLManager.md --- BSLManager.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BSLManager.md b/BSLManager.md index a9f8475..dc044b7 100644 --- a/BSLManager.md +++ b/BSLManager.md @@ -47,3 +47,5 @@ The **filter** permits to filter the list of users with a pattern. All users have their followings count provided next to them. You can select any user by using the up/down arrow keys and hitting the `Enter` key, this will display more information about the user. You can also remove a user and all their followings by hitting the `Del` key. You will be prompted by a confirmation message, and you'll be able to remove this user. + +Deleting users having a lots of followings can take some time: after the prompt has closed the process is still running and will update the list after that. Let the software do its thing and it will go through. From 50cf8d799caf5546bd96b8890994c32892540d8e Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Fri, 28 May 2021 23:31:44 -0400 Subject: [PATCH 18/18] road to 0.17.0 --- src/BirdsiteLive/BirdsiteLive.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BirdsiteLive/BirdsiteLive.csproj b/src/BirdsiteLive/BirdsiteLive.csproj index dd17829..9151ef1 100644 --- a/src/BirdsiteLive/BirdsiteLive.csproj +++ b/src/BirdsiteLive/BirdsiteLive.csproj @@ -4,7 +4,7 @@ netcoreapp3.1 d21486de-a812-47eb-a419-05682bb68856 Linux - 0.16.2 + 0.17.0