From bcf207acb5381605efc81fcba31763e8f7930bf0 Mon Sep 17 00:00:00 2001 From: Nicolas Constant Date: Wed, 3 Feb 2021 23:54:02 -0500 Subject: [PATCH] added moderation repository and parsers --- .../Repository/ModerationRepository.cs | 143 ++++++++++++++++++ .../Tools/ModerationParser.cs | 20 +++ .../Tools/ModerationRegexParser.cs | 28 ++++ .../Tools/ModerationRegexParserTests.cs | 10 ++ 4 files changed, 201 insertions(+) create mode 100644 src/BirdsiteLive.Domain/Repository/ModerationRepository.cs create mode 100644 src/BirdsiteLive.Domain/Tools/ModerationParser.cs create mode 100644 src/BirdsiteLive.Domain/Tools/ModerationRegexParser.cs create mode 100644 src/Tests/BirdsiteLive.Domain.Tests/Tools/ModerationRegexParserTests.cs diff --git a/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs b/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs new file mode 100644 index 0000000..90c93ca --- /dev/null +++ b/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using BirdsiteLive.Common.Settings; +using BirdsiteLive.Domain.Tools; +using Newtonsoft.Json.Converters; + +namespace BirdsiteLive.Domain.Repository +{ + public class ModerationRepository + { + private readonly Regex[] _followersWhiteListing; + private readonly Regex[] _followersBlackListing; + private readonly Regex[] _twitterAccountsWhiteListing; + private readonly Regex[] _twitterAccountsBlackListing; + + private readonly Dictionary _modMode = + new Dictionary(); + + #region Ctor + public ModerationRepository(ModerationSettings settings) + { + var parsedFollowersWhiteListing = ModerationParser.Parse(settings.FollowersWhiteListing); + var parsedFollowersBlackListing = ModerationParser.Parse(settings.FollowersBlackListing); + var parsedTwitterAccountsWhiteListing = ModerationParser.Parse(settings.TwitterAccountsWhiteListing); + var parsedTwitterAccountsBlackListing = ModerationParser.Parse(settings.TwitterAccountsBlackListing); + + _followersWhiteListing = parsedFollowersWhiteListing + .Select(x => ModerationRegexParser.Parse(ModerationEntityTypeEnum.Follower, x)) + .ToArray(); + _followersBlackListing = parsedFollowersBlackListing + .Select(x => ModerationRegexParser.Parse(ModerationEntityTypeEnum.Follower, x)) + .ToArray(); + _twitterAccountsWhiteListing = parsedTwitterAccountsWhiteListing + .Select(x => ModerationRegexParser.Parse(ModerationEntityTypeEnum.TwitterAccount, x)) + .ToArray(); + _twitterAccountsBlackListing = parsedTwitterAccountsBlackListing + .Select(x => ModerationRegexParser.Parse(ModerationEntityTypeEnum.TwitterAccount, x)) + .ToArray(); + + // Set Follower moderation politic + if (_followersWhiteListing.Any()) + _modMode.Add(ModerationEntityTypeEnum.Follower, ModerationTypeEnum.WhiteListing); + else if (_followersBlackListing.Any()) + _modMode.Add(ModerationEntityTypeEnum.Follower, ModerationTypeEnum.BlackListing); + else + _modMode.Add(ModerationEntityTypeEnum.Follower, ModerationTypeEnum.None); + + // Set Twitter account moderation politic + if (_twitterAccountsWhiteListing.Any()) + _modMode.Add(ModerationEntityTypeEnum.TwitterAccount, ModerationTypeEnum.WhiteListing); + else if (_twitterAccountsBlackListing.Any()) + _modMode.Add(ModerationEntityTypeEnum.TwitterAccount, ModerationTypeEnum.BlackListing); + else + _modMode.Add(ModerationEntityTypeEnum.TwitterAccount, ModerationTypeEnum.None); + } + #endregion + + public ModerationTypeEnum GetModerationType(ModerationEntityTypeEnum type) + { + return _modMode[type]; + } + + public ModeratedTypeEnum CheckStatus(ModerationEntityTypeEnum type, string entity) + { + if (_modMode[type] == ModerationTypeEnum.None) return ModeratedTypeEnum.None; + + switch (type) + { + case ModerationEntityTypeEnum.Follower: + return ProcessFollower(entity); + case ModerationEntityTypeEnum.TwitterAccount: + return ProcessTwitterAccount(entity); + } + + throw new NotImplementedException($"Type {type} is not supported"); + } + + private ModeratedTypeEnum ProcessFollower(string entity) + { + var politic = _modMode[ModerationEntityTypeEnum.Follower]; + + switch (politic) + { + case ModerationTypeEnum.None: + return ModeratedTypeEnum.None; + case ModerationTypeEnum.BlackListing: + if (_followersBlackListing.Any(x => x.IsMatch(entity))) + return ModeratedTypeEnum.BlackListed; + return ModeratedTypeEnum.None; + case ModerationTypeEnum.WhiteListing: + if (_followersWhiteListing.Any(x => x.IsMatch(entity))) + return ModeratedTypeEnum.WhiteListed; + return ModeratedTypeEnum.None; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private ModeratedTypeEnum ProcessTwitterAccount(string entity) + { + var politic = _modMode[ModerationEntityTypeEnum.TwitterAccount]; + + switch (politic) + { + case ModerationTypeEnum.None: + return ModeratedTypeEnum.None; + case ModerationTypeEnum.BlackListing: + if (_twitterAccountsBlackListing.Any(x => x.IsMatch(entity))) + return ModeratedTypeEnum.BlackListed; + return ModeratedTypeEnum.None; + case ModerationTypeEnum.WhiteListing: + if (_twitterAccountsWhiteListing.Any(x => x.IsMatch(entity))) + return ModeratedTypeEnum.WhiteListed; + return ModeratedTypeEnum.None; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + public enum ModerationEntityTypeEnum + { + Unknown = 0, + Follower = 1, + TwitterAccount = 2 + } + + public enum ModerationTypeEnum + { + None = 0, + BlackListing = 1, + WhiteListing = 2 + } + + public enum ModeratedTypeEnum + { + None = 0, + BlackListed = 1, + WhiteListed = 2 + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/Tools/ModerationParser.cs b/src/BirdsiteLive.Domain/Tools/ModerationParser.cs new file mode 100644 index 0000000..51dd979 --- /dev/null +++ b/src/BirdsiteLive.Domain/Tools/ModerationParser.cs @@ -0,0 +1,20 @@ +using System; +using System.Linq; + +namespace BirdsiteLive.Domain.Tools +{ + public class ModerationParser + { + public static string[] Parse(string entry) + { + var separationChar = '|'; + if (entry.Contains(";")) separationChar = ';'; + else if (entry.Contains(",")) separationChar = ','; + + var splitEntries = entry + .Split(new[] {separationChar}, StringSplitOptions.RemoveEmptyEntries) + .Select(x => x.ToLowerInvariant()); + return splitEntries.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/Tools/ModerationRegexParser.cs b/src/BirdsiteLive.Domain/Tools/ModerationRegexParser.cs new file mode 100644 index 0000000..6f4df11 --- /dev/null +++ b/src/BirdsiteLive.Domain/Tools/ModerationRegexParser.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.RegularExpressions; +using BirdsiteLive.Domain.Repository; +using Org.BouncyCastle.Pkcs; + +namespace BirdsiteLive.Domain.Tools +{ + public class ModerationRegexParser + { + public static Regex Parse(ModerationEntityTypeEnum type, string data) + { + data = data.ToLowerInvariant().Trim(); + + if (type == ModerationEntityTypeEnum.Follower) + { + if (data.StartsWith("@")) + return new Regex($@"^{data}$"); + + if (data.StartsWith("*")) + data = data.Replace("*", "(.+)"); + + return new Regex($@"^@(.+)@{data}$"); + } + + return new Regex($@"^{data}$"); + } + } +} \ No newline at end of file diff --git a/src/Tests/BirdsiteLive.Domain.Tests/Tools/ModerationRegexParserTests.cs b/src/Tests/BirdsiteLive.Domain.Tests/Tools/ModerationRegexParserTests.cs new file mode 100644 index 0000000..fce5d71 --- /dev/null +++ b/src/Tests/BirdsiteLive.Domain.Tests/Tools/ModerationRegexParserTests.cs @@ -0,0 +1,10 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace BirdsiteLive.Domain.Tests.Tools +{ + [TestClass] + public class ModerationRegexParserTests + { + + } +} \ No newline at end of file