Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement groups #51

Merged
merged 11 commits into from
Dec 16, 2019
28 changes: 21 additions & 7 deletions src/BotTerminator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public async Task StartAsync()
return;
}
UserLookup = new WikiBotDatabase(await RedditInstance.GetSubredditAsync(SubredditName, false));
await UserLookup.CheckUserAsync(CacheFreshenerUserName);
await UserLookup.CheckUserAsync(CacheFreshenerUserName, String.Empty);
await UpdateSubredditCacheAsync();

this.Modules = new List<BotModule>()
Expand All @@ -92,7 +92,14 @@ public async Task StartAsync()

public async Task CacheSubredditAsync(String subredditName)
{
SubredditLookup[subredditName] = new CachedSubreddit(await RedditInstance.GetSubredditAsync(subredditName, false), configurationLoader);
Subreddit subreddit = null;
// we have to do it this way, otherwise ModPermissions won't be set
await RedditInstance.User.GetModeratorSubreddits(-1).ForEachAsync(moderatedSubreddit =>
{
if (moderatedSubreddit.DisplayName == SubredditName) subreddit = moderatedSubreddit;
});
SubredditLookup[subredditName] = new CachedSubreddit(subreddit, configurationLoader);
await SubredditLookup[subredditName].ReloadOptionsAsync(this);
}

public async Task UpdateSubredditCacheAsync()
Expand All @@ -119,11 +126,11 @@ await RedditInstance.User.GetModeratorSubreddits(-1).ForEachAsync(subreddit =>
}
}

}
}/*
else
{
SubredditLookup[subreddit.DisplayName] = new CachedSubreddit(subreddit, configurationLoader);
}
await SubredditLookup[subreddit.DisplayName].ReloadOptionsAsync(this);
}*/
}
await Task.WhenAll(moderatedSubreddits.Select(subreddit => SubredditLookup[subreddit.DisplayName].ReloadOptionsAsync(this)));
}
Expand All @@ -146,7 +153,7 @@ public bool IsConfigurable(Subreddit subreddit)
/// <returns>A value determining whether the user is not bannable on Reddit.</returns>
public static Boolean IsUnbannable(ModeratableThing thing) => String.IsNullOrWhiteSpace(thing?.AuthorName) || thing?.AuthorName == DeletedUserName;

internal async Task<Boolean> CheckShouldBanAsync(ModeratableThing thing)
internal async Task<Boolean> CheckShouldBanAsync(ModeratableThing thing, IEnumerable<String> bannedGroups)
{
if (IsUnbannable(thing)) return false;

Expand All @@ -159,7 +166,14 @@ internal async Task<Boolean> CheckShouldBanAsync(ModeratableThing thing)
return false;
}
}
return await UserLookup.CheckUserAsync(thing.AuthorName);
IEnumerable<String> groupNames = (await UserLookup.GetGroupsForUserAsync(thing.AuthorName)).Select(group => group.Name);
return groupNames.Any(groupName => bannedGroups.Contains(groupName));
}

internal async Task<IReadOnlyCollection<Models.Group>> GetBannedGroupsAsync(AbstractSubredditOptionSet options)
{
IReadOnlyCollection<String> actioned = options.ActionedUserTypes.ToHashSet();
return actioned.Count == 0 ? await UserLookup.GetDefaultBannedGroupsAsync() : (await UserLookup.GetAllGroupsAsync()).Values.Where(group => actioned.Contains(group.Name)).ToArray();
}

internal async Task QuarantineOptInAsync(String subredditName)
Expand Down
3 changes: 3 additions & 0 deletions src/Configuration/AbstractSubredditOptionSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public abstract class AbstractSubredditOptionSet
[JsonProperty("banDuration", Required = Required.DisallowNull)]
public abstract Int32 BanDuration { get; set; }

[JsonProperty("actionedUserTypes")]
public abstract IEnumerable<String> ActionedUserTypes { get; set; }

[JsonProperty("ignoredUsers")]
public abstract IEnumerable<String> IgnoredUsers { get; set; }

Expand Down
53 changes: 50 additions & 3 deletions src/Configuration/BanListConfig.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,60 @@
using Newtonsoft.Json;
using BotTerminator.Models;
using Newtonsoft.Json;
using RedditSharp.Things;
using System;
using System.Collections.Generic;
using System.Linq;

namespace BotTerminator.Configuration
{
[JsonObject]
public class BanListConfig : BotConfig
{
[JsonProperty("bannedUsers")]
public ISet<String> Items { get; set; } = new HashSet<String>();
private const Int32 CurrentConfigVersion = 2;

public BanListConfig(int version = CurrentConfigVersion)
{
this.Version = version;
}

[JsonProperty("nonGroupFlairCssClasses", DefaultValueHandling = DefaultValueHandling.Populate)]
public IReadOnlyCollection<String> NonGroupFlairCssClasses { get; set; } = Array.Empty<String>();

[JsonProperty("groups")]
public Dictionary<String, Group> GroupLookup { get; set; } = new Dictionary<string, Group>();

[JsonIgnore]
public Int32 Count => GroupLookup.Values.Sum(group => group.Members.Count);

public IEnumerable<String> GetAllNames()
{
return NonGroupFlairCssClasses.Concat(GroupLookup.Keys);
}

public IReadOnlyCollection<Group> GetDefaultActionedOnGroups()
{
return GroupLookup.Values.Where(group => group.ActionByDefault).ToArray();
}

public IReadOnlyCollection<Group> GetGroupsByUser(String username)
{
return GroupLookup.Values.Where(group => group.Members.Contains(username)).ToArray();
}

public bool IsInGroup(String groupCssClass, String username)
{
return GroupLookup.ContainsKey(groupCssClass) && GroupLookup[groupCssClass].Members.Contains(username);
}

public bool IsInAnyGroup(String username)
{
return GroupLookup.Values.Any(group => group.Members.Contains(username));
}

public bool ShouldHide(Post post)
{
String cssClass = post.LinkFlairCssClass;
return IsInAnyGroup(cssClass) || NonGroupFlairCssClasses.Contains(cssClass);
}
}
}
10 changes: 10 additions & 0 deletions src/Configuration/ShadedOptionSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,15 @@ public override RemovalType RemovalType
}
set => throw new NotSupportedException(operationNotSupportedMessage);
}

public override IEnumerable<String> ActionedUserTypes
{
get
{
return optionSets.First(optionSet => optionSet.ActionedUserTypes != null).ActionedUserTypes;
// TODO: somehow respect enumerablesAdditive
}
set => throw new NotSupportedException(operationNotSupportedMessage);
}
}
}
4 changes: 4 additions & 0 deletions src/Configuration/SubredditOptionSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ public SubredditOptionSet(AbstractSubredditOptionSet toCopyFrom)

public override Int32 BanDuration { get; set; } = 0;

// TODO: can we use a set here?

public override IEnumerable<String> IgnoredUsers { get; set; } = new List<String>(0);

public override IEnumerable<String> ActionedUserTypes { get; set; }

public override RemovalType RemovalType { get; set; } = RemovalType.Spam;
}
}
16 changes: 13 additions & 3 deletions src/Data/IBotDatabase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using BotTerminator.Configuration;
using BotTerminator.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
Expand All @@ -8,8 +10,16 @@ namespace BotTerminator.Data
{
public interface IBotDatabase
{
Task<bool> CheckUserAsync(String name);
Task<BanListConfig> GetConfigAsync();

Task UpdateUserAsync(String name, Boolean value, Boolean force = false);
Task<IReadOnlyDictionary<String, Group>> GetAllGroupsAsync();

Task<IReadOnlyCollection<Group>> GetGroupsForUserAsync(String name);

Task<IReadOnlyCollection<Group>> GetDefaultBannedGroupsAsync();

Task<bool> CheckUserAsync(String username, String groupName);

Task UpdateUserAsync(String username, String groupName, Boolean value, Boolean force = false);
}
}
20 changes: 15 additions & 5 deletions src/Data/MemoryBotDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,34 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BotTerminator.Configuration;
using BotTerminator.Models;

namespace BotTerminator.Data
{
public class MemoryBotDatabase : IBotDatabase
{
private HashSet<String> Users { get; set; } = new HashSet<string>();
private BanListConfig Users { get; set; } = new BanListConfig();

public Task<Boolean> CheckUserAsync(String name) => Task.FromResult(Users.Contains(name));
public Task<BanListConfig> GetConfigAsync() => Task.FromResult(Users);

public Task UpdateUserAsync(String name, Boolean value, Boolean force)
public Task<IReadOnlyDictionary<String, Group>> GetAllGroupsAsync() => Task.FromResult<IReadOnlyDictionary<String, Group>>(Users.GroupLookup);

public Task<Boolean> CheckUserAsync(String username, String groupName) => Task.FromResult(Users.IsInGroup(groupName, username));

public Task<IReadOnlyCollection<Group>> GetDefaultBannedGroupsAsync() => Task.FromResult(Users.GroupLookup.Where(group => group.Value.ActionByDefault).ToList() as IReadOnlyCollection<Group>);

public Task<IReadOnlyCollection<Group>> GetGroupsForUserAsync(String username) => Task.FromResult(Users.GetGroupsByUser(username));

public Task UpdateUserAsync(String name, String groupName, Boolean value, Boolean force = false)
{
if (value)
{
Users.Add(name);
Users.GroupLookup[groupName].Members.Add(name);
}
else
{
Users.Remove(name);
Users.GroupLookup[groupName].Members.Remove(name);
}
return Task.CompletedTask;
}
Expand Down
14 changes: 12 additions & 2 deletions src/Data/NullBotDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BotTerminator.Configuration;
using BotTerminator.Models;

namespace BotTerminator.Data
{
public class NullBotDatabase : IBotDatabase
{
public Task<Boolean> CheckUserAsync(String name) => Task.FromResult(false);
public Task<Boolean> CheckUserAsync(String username, String groupName) => Task.FromResult(false);

public Task UpdateUserAsync(String name, Boolean value, Boolean force) => Task.CompletedTask;
public Task<BanListConfig> GetConfigAsync() => Task.FromResult(new BanListConfig());

public Task<IReadOnlyDictionary<String, Group>> GetAllGroupsAsync() => Task.FromResult<IReadOnlyDictionary<String, Group>>(new Dictionary<String, Group>());

public Task<IReadOnlyCollection<Group>> GetDefaultBannedGroupsAsync() => Task.FromResult(Array.Empty<Group>() as IReadOnlyCollection<Group>);

public Task<IReadOnlyCollection<Group>> GetGroupsForUserAsync(String name) => Task.FromResult(Array.Empty<Group>() as IReadOnlyCollection<Group>);

public Task UpdateUserAsync(String username, String groupName, Boolean value, Boolean force = false) => Task.CompletedTask;
}
}
32 changes: 32 additions & 0 deletions src/Data/SQLiteBotDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BotTerminator.Configuration;
using BotTerminator.Models;

namespace BotTerminator.Data
{
Expand All @@ -13,9 +15,39 @@ public Task<Boolean> CheckUserAsync(String name)
throw new NotImplementedException();
}

public Task<Boolean> CheckUserAsync(String username, String groupName)
{
throw new NotImplementedException();
}

public Task<IReadOnlyDictionary<String, Group>> GetAllGroupsAsync()
{
throw new NotImplementedException();
}

public Task<BanListConfig> GetConfigAsync()
{
throw new NotImplementedException();
}

public Task<IReadOnlyCollection<Group>> GetDefaultBannedGroupsAsync()
{
throw new NotImplementedException();
}

public Task<IReadOnlyCollection<Group>> GetGroupsForUserAsync(String name)
{
throw new NotImplementedException();
}

public Task UpdateUserAsync(String name, Boolean value, Boolean force = false)
{
throw new NotImplementedException();
}

public Task UpdateUserAsync(String username, String groupName, Boolean value, Boolean force = false)
{
throw new NotImplementedException();
}
}
}
Loading