diff --git a/CentCom.API/CentCom.API.csproj b/CentCom.API/CentCom.API.csproj
index 71d0f58..10d437f 100644
--- a/CentCom.API/CentCom.API.csproj
+++ b/CentCom.API/CentCom.API.csproj
@@ -2,8 +2,8 @@
netcoreapp3.1
- 1.0.5
- 1.0.5.0
+ 1.0.6
+ 1.0.6.0
diff --git a/CentCom.Common/CentCom.Common.csproj b/CentCom.Common/CentCom.Common.csproj
index 68d7a66..f0a4370 100644
--- a/CentCom.Common/CentCom.Common.csproj
+++ b/CentCom.Common/CentCom.Common.csproj
@@ -2,7 +2,8 @@
netstandard2.0
- 1.0.5
+ 1.0.6
+ 1.0.6.0
diff --git a/CentCom.Common/Models/Ban.cs b/CentCom.Common/Models/Ban.cs
index 76a05c7..eafb582 100644
--- a/CentCom.Common/Models/Ban.cs
+++ b/CentCom.Common/Models/Ban.cs
@@ -1,16 +1,13 @@
-using System;
+using CentCom.Common.Models.Equality;
+using System;
using System.Collections.Generic;
-using System.Linq;
using System.Net;
using System.Text.Json.Serialization;
-using System.Text.RegularExpressions;
namespace CentCom.Common.Models
{
- public class Ban :IEquatable
+ public class Ban
{
- private static Regex _keyReplacePattern = new Regex(@"[^a-z0-9]");
-
public int Id { get; set; }
public int Source { get; set; }
[JsonIgnore]
@@ -28,101 +25,9 @@ public class Ban :IEquatable
public string BanID { get; set; }
public HashSet JobBans { get; set; }
- ///
- /// Determines if two bans are equal, using their values
- ///
- /// The ban to compare against
- /// If the two bans are equal by their values
- ///
- /// Note that these equals are really just used for determining if
- /// the contents of two bans are the same, at which point they're equal.
- ///
- public bool Equals(Ban other)
- {
- if (other == null) return false;
- else if (BanID != null || other.BanID != null)
- {
- return Source == other.Source
- && BanID == other.BanID;
- }
- else
- {
- return Source == other.Source
- && BannedOn == other.BannedOn
- && BanType == other.BanType
- && CKey == other.CKey
- && BannedBy == other.BannedBy
- && Reason == other.Reason
- && Expires == other.Expires
- && UnbannedBy == other.UnbannedBy
- && (IP == null || IP.Equals(other.IP))
- && CID == other.CID
- && (BanType == BanType.Server
- || (JobBans != null && other.JobBans != null && JobBans.SetEquals(other.JobBans)));
- }
- }
-
- public static bool operator ==(Ban a, Ban b)
- {
- return (a is null && b is null) || a.Equals(b);
- }
-
- public static bool operator !=(Ban a, Ban b)
- {
- return !(a == b);
- }
-
- public override bool Equals(object obj)
+ public Ban()
{
- return (obj is Ban ban) && Equals(ban);
- }
-
- public override int GetHashCode()
- {
- var hash = new HashCode();
- if (BanID != null)
- {
- hash.Add(BanID);
- hash.Add(Source);
- }
- else
- {
- hash.Add(Source);
- hash.Add(BannedOn);
- hash.Add(BanType);
- hash.Add(CKey);
- hash.Add(BannedBy);
- hash.Add(Reason);
- hash.Add(Expires);
- hash.Add(UnbannedBy);
- hash.Add(IP);
- hash.Add(CID);
- if (JobBans != null)
- {
- foreach (var job in JobBans.OrderBy(x => x.Job))
- {
- hash.Add(job.Job, StringComparer.OrdinalIgnoreCase);
- }
- }
- }
- return hash.ToHashCode();
- }
-
- public void MakeKeysCanonical()
- {
- CKey = CKey == null ? null : GetCanonicalKey(CKey);
- BannedBy = BannedBy == null ? null : GetCanonicalKey(BannedBy);
- UnbannedBy = UnbannedBy == null ? null : GetCanonicalKey(UnbannedBy);
- }
-
- public static string GetCanonicalKey(string raw)
- {
- if (raw == null)
- {
- throw new ArgumentNullException(nameof(raw));
- }
-
- return _keyReplacePattern.Replace(raw.ToLower(), "");
+ JobBans = new HashSet(JobBanEqualityComparer.Instance);
}
}
}
diff --git a/CentCom.Common/Models/Equality/BanEqualityComparer.cs b/CentCom.Common/Models/Equality/BanEqualityComparer.cs
new file mode 100644
index 0000000..349dfd2
--- /dev/null
+++ b/CentCom.Common/Models/Equality/BanEqualityComparer.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace CentCom.Common.Models.Equality
+{
+ public class BanEqualityComparer : IEqualityComparer
+ {
+ public static readonly BanEqualityComparer Instance = new BanEqualityComparer();
+
+ public bool Equals(Ban x, Ban y)
+ {
+ if (x is null || y is null) return x == y;
+ else if (x.BanID != null || y.BanID != null)
+ {
+ return x.Source == y.Source
+ && x.BanID == y.BanID;
+ }
+ else
+ {
+ return x.Source == y.Source
+ && x.BannedOn == y.BannedOn
+ && x.BanType == y.BanType
+ && x.CKey == y.CKey
+ && x.BannedBy == y.BannedBy
+ && x.Reason == y.Reason
+ && x.Expires == y.Expires
+ && x.UnbannedBy == y.UnbannedBy
+ && (x.IP == null || x.IP.Equals(y.IP))
+ && x.CID == y.CID
+ && (x.BanType == BanType.Server
+ || (x.JobBans != null && y.JobBans != null && x.JobBans.SetEquals(y.JobBans)));
+ }
+ }
+
+ public int GetHashCode(Ban obj)
+ {
+ var hash = new HashCode();
+ if (obj.BanID != null)
+ {
+ hash.Add(obj.BanID);
+ hash.Add(obj.Source);
+ }
+ else
+ {
+ hash.Add(obj.Source);
+ hash.Add(obj.BannedOn);
+ hash.Add(obj.BanType);
+ hash.Add(obj.CKey);
+ hash.Add(obj.BannedBy);
+ hash.Add(obj.Reason);
+ hash.Add(obj.Expires);
+ hash.Add(obj.UnbannedBy);
+ hash.Add(obj.IP);
+ hash.Add(obj.CID);
+ if (obj.JobBans != null)
+ {
+ foreach (var job in obj.JobBans.OrderBy(x => x.Job))
+ {
+ hash.Add(job.Job);
+ }
+ }
+ }
+ return hash.ToHashCode();
+ }
+ }
+}
diff --git a/CentCom.Common/Models/Equality/JobBanEqualityComparer.cs b/CentCom.Common/Models/Equality/JobBanEqualityComparer.cs
new file mode 100644
index 0000000..c931651
--- /dev/null
+++ b/CentCom.Common/Models/Equality/JobBanEqualityComparer.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CentCom.Common.Models.Equality
+{
+ public class JobBanEqualityComparer : IEqualityComparer
+ {
+ public static readonly JobBanEqualityComparer Instance = new JobBanEqualityComparer();
+
+ public bool Equals(JobBan x, JobBan y)
+ {
+ return (x is null || y is null) ? x == y : x.Job == y.Job;
+ }
+
+ public int GetHashCode(JobBan obj)
+ {
+ return HashCode.Combine(obj.Job);
+ }
+ }
+}
diff --git a/CentCom.Common/Models/JobBan.cs b/CentCom.Common/Models/JobBan.cs
index f74995f..0a5bc16 100644
--- a/CentCom.Common/Models/JobBan.cs
+++ b/CentCom.Common/Models/JobBan.cs
@@ -3,38 +3,11 @@
namespace CentCom.Common.Models
{
- public class JobBan : IEquatable
+ public class JobBan
{
public int BanId { get; set; }
[JsonIgnore]
public virtual Ban BanNavigation { get; set; }
public string Job { get; set; }
-
- public bool Equals(JobBan other)
- {
- return !(other is null) && Job == other.Job;
- }
-
- public static bool operator ==(JobBan a, JobBan b)
- {
- return (a is null && b is null) || a.Equals(b);
- }
-
- public static bool operator !=(JobBan a, JobBan b)
- {
- return !(a == b);
- }
-
- public override bool Equals(object obj)
- {
- return (obj is JobBan jb) && Equals(jb);
- }
-
- public override int GetHashCode()
- {
- var hash = new HashCode();
- hash.Add(Job, StringComparer.OrdinalIgnoreCase);
- return hash.ToHashCode();
- }
}
}
diff --git a/CentCom.Server/BanSources/BanParser.cs b/CentCom.Server/BanSources/BanParser.cs
index c61ef30..faf17b1 100644
--- a/CentCom.Server/BanSources/BanParser.cs
+++ b/CentCom.Server/BanSources/BanParser.cs
@@ -8,6 +8,8 @@
using System.Threading.Tasks;
using CentCom.Common.Data;
using CentCom.Server.Exceptions;
+using CentCom.Server.Extensions;
+using CentCom.Common.Models.Equality;
namespace CentCom.Server.BanSources
{
@@ -128,12 +130,13 @@ public virtual async Task ParseBans(IJobExecutionContext context)
&& b.CKey == x.CKey
&& b.BannedBy == x.BannedBy
&& (b.BanType == BanType.Server
- || (b.JobBans != null && x.JobBans != null && b.JobBans.SetEquals(x.JobBans))));
+ || b.JobBans.SetEquals(x.JobBans)));
}
// Update ban if an existing one is found
if (matchedBan != null)
{
+ // Check for a difference in date time, unbans, or reason
if (matchedBan.Reason != b.Reason || matchedBan.Expires != b.Expires || matchedBan.UnbannedBy != b.UnbannedBy)
{
matchedBan.Reason = b.Reason;
@@ -141,6 +144,14 @@ public virtual async Task ParseBans(IJobExecutionContext context)
matchedBan.UnbannedBy = b.UnbannedBy;
updated++;
}
+
+ // Check for a difference in recorded jobbans
+ if (b.BanType == BanType.Job && !b.JobBans.SetEquals(matchedBan.JobBans))
+ {
+ matchedBan.JobBans = new HashSet(JobBanEqualityComparer.Instance);
+ matchedBan.AddJobRange(b.JobBans.Select(x => x.Job));
+ updated++;
+ }
}
// Otherwise add insert a new ban
else
@@ -157,8 +168,14 @@ public virtual async Task ParseBans(IJobExecutionContext context)
// Delete any missing bans if we're doing a complete refresh
if (isCompleteRefresh)
{
- var bansHashed = new HashSet(bans);
- var missingBans = storedBans.Except(bansHashed).ToHashSet();
+ var bansHashed = new HashSet(bans, BanEqualityComparer.Instance);
+ var missingBans = storedBans.Except(bansHashed, BanEqualityComparer.Instance).ToList();
+
+ if (bansHashed.Count == 0 && missingBans.Count > 1)
+ {
+ throw new Exception("Failed to find any bans for source, aborting removal phase of ban " +
+ "parsing to avoid dumping entire set of bans");
+ }
// Apply deletions
_logger.LogInformation(missingBans.Count > 0 ? $"Removing {missingBans.Count} deleted bans..."
diff --git a/CentCom.Server/BanSources/TGMCBanParser.cs b/CentCom.Server/BanSources/TGMCBanParser.cs
new file mode 100644
index 0000000..c44c21f
--- /dev/null
+++ b/CentCom.Server/BanSources/TGMCBanParser.cs
@@ -0,0 +1,66 @@
+using CentCom.Common.Data;
+using CentCom.Common.Models;
+using CentCom.Server.Services;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CentCom.Server.BanSources
+{
+ public class TGMCBanParser : BanParser
+ {
+ public override Dictionary Sources => new Dictionary()
+ {
+ { "tgmc", new BanSource()
+ {
+ Display = "TGMC",
+ Name = "tgmc",
+ RoleplayLevel = RoleplayLevel.Medium
+ } }
+ };
+ public override bool SourceSupportsBanIDs => true;
+ private TGMCBanService _banService;
+ private const int PAGES_PER_BATCH = 3;
+
+ public TGMCBanParser(DatabaseContext dbContext, TGMCBanService banService, ILogger logger) : base(dbContext, logger)
+ {
+ _banService = banService;
+ }
+
+ public override async Task> FetchAllBansAsync()
+ {
+ _logger.LogInformation("Getting all bans for TGMC...");
+ return await _banService.GetBansBatchedAsync();
+ }
+
+ public override async Task> FetchNewBansAsync()
+ {
+ _logger.LogInformation("Getting new bans for TGMC...");
+ var recent = await _dbContext.Bans
+ .Where(x => Sources.Keys.Contains(x.SourceNavigation.Name))
+ .OrderByDescending(x => x.BannedOn)
+ .Take(5)
+ .Include(x => x.JobBans)
+ .Include(x => x.SourceNavigation)
+ .ToListAsync();
+ var foundBans = new List();
+ var page = 1;
+
+ while (true)
+ {
+ var batch = await _banService.GetBansBatchedAsync(page, PAGES_PER_BATCH);
+ foundBans.AddRange(batch);
+ if (batch.Count() == 0 || batch.Any(x => recent.Any(y => y.BannedOn == x.BannedOn && y.CKey == y.CKey)))
+ {
+ break;
+ }
+ }
+
+ return foundBans;
+ }
+ }
+}
diff --git a/CentCom.Server/CentCom.Server.csproj b/CentCom.Server/CentCom.Server.csproj
index bf06107..e6d5e94 100644
--- a/CentCom.Server/CentCom.Server.csproj
+++ b/CentCom.Server/CentCom.Server.csproj
@@ -3,9 +3,9 @@
Exe
netcoreapp3.1
- 1.0.5.0
- 1.0.5.0
- 1.0.5
+ 1.0.6.0
+ 1.0.6.0
+ 1.0.6
diff --git a/CentCom.Server/Extensions/BanExtensions.cs b/CentCom.Server/Extensions/BanExtensions.cs
new file mode 100644
index 0000000..0ec21c1
--- /dev/null
+++ b/CentCom.Server/Extensions/BanExtensions.cs
@@ -0,0 +1,48 @@
+using CentCom.Common.Models;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace CentCom.Server.Extensions
+{
+ public static class BanExtensions
+ {
+ private static Regex _keyReplacePattern = new Regex(@"[^a-z0-9]");
+
+ public static void MakeKeysCanonical(this Ban ban)
+ {
+ ban.CKey = ban.CKey == null ? null : GetCanonicalKey(ban.CKey);
+ ban.BannedBy = ban.BannedBy == null ? null : GetCanonicalKey(ban.BannedBy);
+ ban.UnbannedBy = ban.UnbannedBy == null ? null : GetCanonicalKey(ban.UnbannedBy);
+ }
+
+ public static string GetCanonicalKey(string raw)
+ {
+ if (raw == null)
+ {
+ throw new ArgumentNullException(nameof(raw));
+ }
+
+ return _keyReplacePattern.Replace(raw.ToLower(), "");
+ }
+
+ public static string CleanJob(string job)
+ {
+ return job.ToLower();
+ }
+
+ public static bool AddJob(this Ban ban, string job)
+ {
+ return ban.JobBans.Add(new JobBan() { Job = CleanJob(job), BanId = ban.Id, BanNavigation = ban });
+ }
+
+ public static void AddJobRange(this Ban ban, IEnumerable jobs)
+ {
+ foreach (var job in jobs)
+ {
+ ban.AddJob(job);
+ }
+ }
+ }
+}
diff --git a/CentCom.Server/Program.cs b/CentCom.Server/Program.cs
index 54ed2ba..899834b 100644
--- a/CentCom.Server/Program.cs
+++ b/CentCom.Server/Program.cs
@@ -157,6 +157,7 @@ public static void RegisterServices()
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
+ services.AddSingleton();
// Add ban parsers
var parsers = AppDomain.CurrentDomain.GetAssemblies().Aggregate(new List(), (curr, next) =>
diff --git a/CentCom.Server/Services/BeeBanService.cs b/CentCom.Server/Services/BeeBanService.cs
index 570ca97..a46f879 100644
--- a/CentCom.Server/Services/BeeBanService.cs
+++ b/CentCom.Server/Services/BeeBanService.cs
@@ -1,5 +1,6 @@
using CentCom.Common.Models;
using CentCom.Server.Exceptions;
+using CentCom.Server.Extensions;
using Extensions;
using Microsoft.Extensions.Logging;
using RestSharp;
@@ -7,7 +8,6 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -58,10 +58,7 @@ public async Task> GetBansAsync(int page = 1)
if (toAdd.BanType == BanType.Job)
{
- toAdd.JobBans = b["job"].EnumerateArray()
- .Select(x => x.GetString().ToLower())
- .Select(x => new JobBan() { Job = x })
- .ToHashSet();
+ toAdd.AddJobRange(b["job"].EnumerateArray().Select(x => x.GetString()));
}
toReturn.Add(toAdd);
diff --git a/CentCom.Server/Services/FulpBanService.cs b/CentCom.Server/Services/FulpBanService.cs
index f909fb5..4327289 100644
--- a/CentCom.Server/Services/FulpBanService.cs
+++ b/CentCom.Server/Services/FulpBanService.cs
@@ -1,5 +1,6 @@
using CentCom.Common.Models;
using CentCom.Server.Exceptions;
+using CentCom.Server.Extensions;
using Extensions;
using Microsoft.Extensions.Logging;
using RestSharp;
@@ -57,10 +58,7 @@ public async Task> GetBansAsync(int page = 1)
// Add jobs if relevant
if (toAdd.BanType == BanType.Job)
{
- toAdd.JobBans = ban.GetProperty("role").EnumerateArray()
- .Select(x => x.GetString().ToLower())
- .Select(x => new JobBan() { Job = x })
- .ToHashSet();
+ toAdd.AddJobRange(ban.GetProperty("role").EnumerateArray().Select(x => x.GetString()));
}
// Specify UTC
diff --git a/CentCom.Server/Services/TGMCBanService.cs b/CentCom.Server/Services/TGMCBanService.cs
new file mode 100644
index 0000000..f4758fb
--- /dev/null
+++ b/CentCom.Server/Services/TGMCBanService.cs
@@ -0,0 +1,163 @@
+using CentCom.Common.Models;
+using CentCom.Server.Exceptions;
+using CentCom.Server.Extensions;
+using Extensions;
+using Microsoft.Extensions.Logging;
+using RestSharp;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace CentCom.Server.Services
+{
+ ///
+ /// TGMC Ban Service for getting bans from the API
+ ///
+ ///
+ /// Note that the data is provided in a flat tg format, meaning
+ /// that each role in a jobban has its own ban ID. Thus, our strategy
+ /// for using the paging must account for the possibility of a job ban
+ /// spanning two seperate pages.
+ ///
+ public class TGMCBanService
+ {
+ private IRestClient _client;
+ ILogger _logger;
+ private const string BASE_URL = "http://statbus.psykzz.com:8080/api/";
+ private const int RECORDS_PER_PAGE = 100;
+ private static BanSource _banSource = new BanSource() { Name = "tgmc" };
+
+ public TGMCBanService(ILogger logger)
+ {
+ _logger = logger;
+ _client = new RestClient(BASE_URL);
+ }
+
+ public async Task> GetBansAsync(int page = 1)
+ {
+ var request = new RestRequest($"bans/{page}", Method.GET, DataFormat.Json).AddQueryParameter("limit", RECORDS_PER_PAGE.ToString());
+ var response = await _client.ExecuteAsync(request);
+
+ if (response.StatusCode != System.Net.HttpStatusCode.OK)
+ {
+ _logger.LogError($"TGMC website returned a non-200 HTTP response code: {response.StatusCode}, aborting parse.");
+ throw new BanSourceUnavailableException($"TGMC website returned a non-200 HTTP response code: {response.StatusCode}, aborting parse.");
+ }
+
+ var toReturn = new List();
+ var dirtyBans = new List();
+ var content = JsonSerializer.Deserialize>(response.Content);
+ foreach (var bh in content["bans"].EnumerateObject())
+ {
+ var ban = bh.Value;
+
+ // Get ban
+ var toAdd = new Ban()
+ {
+ BanID = bh.Name,
+ BannedBy = ban.GetProperty("admin").GetString(),
+ BannedOn = DateTime.Parse(ban.GetProperty("bantime").ToString()),
+ CKey = ban.GetProperty("ckey").GetString(),
+ Expires = ban.GetProperty("expiration_time").GetString() == null ? (DateTime?)null
+ : DateTime.Parse(ban.GetProperty("expiration_time").GetString()),
+ Reason = ban.GetProperty("reason").ToString(),
+ BanType = ban.GetProperty("role").GetString().ToLower() == "server" ? BanType.Server : BanType.Job,
+ SourceNavigation = _banSource
+ };
+
+ // Specify UTC
+ toAdd.BannedOn = DateTime.SpecifyKind(toAdd.BannedOn, DateTimeKind.Utc);
+ if (toAdd.Expires.HasValue)
+ {
+ toAdd.Expires = DateTime.SpecifyKind(toAdd.Expires.Value, DateTimeKind.Utc);
+ }
+
+ // Add jobban if relevant
+ if (toAdd.BanType == BanType.Job)
+ {
+ toAdd.AddJob(ban.GetProperty("role").GetString());
+ dirtyBans.Add(toAdd);
+ }
+ else
+ {
+ toReturn.Add(toAdd);
+ }
+ }
+
+ // Group jobbans
+ foreach (var group in dirtyBans.GroupBy(x => new { x.BannedOn, x.CKey, x.Reason }))
+ {
+ var firstBan = group.OrderBy(x => x.BanID).First();
+ firstBan.AddJobRange(group.SelectMany(x => x.JobBans).Select(x => x.Job));
+ toReturn.Add(firstBan);
+ }
+
+ return toReturn;
+ }
+
+ public async Task> GetBansBatchedAsync(int startPage = 1, int pages = -1)
+ {
+ var maxPages = await GetNumberOfPagesAsync();
+ var range = Enumerable.Range(startPage, pages != -1 ? Math.Min(startPage + pages, maxPages) : maxPages);
+ var dirtyBans = new ConcurrentBag();
+ await range.AsyncParallelForEach(async page =>
+ {
+ foreach (var b in await GetBansAsync(page))
+ {
+ dirtyBans.Add(b);
+ }
+ }, 12);
+
+ // We have to ensure that our jobs are correctly grouped due to possible errors with paging
+ var cleanBans = new List(dirtyBans.Where(x => x.BanType == BanType.Server));
+ foreach (var group in dirtyBans.Where(x => x.BanType == BanType.Job).GroupBy(x => new { x.BannedOn, x.CKey, x.Reason }))
+ {
+ var firstBan = group.OrderBy(x => x.BanID).First();
+ firstBan.AddJobRange(group.SelectMany(x => x.JobBans).Select(x => x.Job));
+ cleanBans.Add(firstBan);
+ }
+
+ // Check for the possibility of a job ban spanning multiple pages
+ cleanBans = cleanBans.OrderBy(x => int.Parse(x.BanID)).ToList();
+ if (startPage != 1 && cleanBans.First().BanType == BanType.Job)
+ {
+ // Discard the first ban if it is a job ban, as it may be incomplete.
+ // The alternate would be walking backwards in the page list, but that
+ // is not an optimal solution
+ cleanBans.RemoveAt(0);
+ }
+ if (pages != -1 && startPage + pages < maxPages && cleanBans.LastOrDefault()?.BanType == BanType.Job)
+ {
+ // Discard the last ban if it is a job ban as it may be incomplete.
+ // Same reasoning above, except it would require a pagewalk forward.
+ cleanBans.RemoveAt(cleanBans.Count() - 1);
+ }
+
+ return cleanBans;
+ }
+
+ public async Task GetNumberOfPagesAsync()
+ {
+ var request = new RestRequest($"bans/1", Method.GET, DataFormat.Json).AddQueryParameter("limit", RECORDS_PER_PAGE.ToString());
+ var result = await _client.ExecuteAsync(request);
+
+ if (result.StatusCode != System.Net.HttpStatusCode.OK)
+ {
+ throw new Exception($"Unexpected non-200 status code [{result.StatusCode}] when trying to retrieve number of ban pages for TGMC");
+ }
+
+ var content = JsonSerializer.Deserialize>(result.Content);
+ if (content["page"].TryGetProperty("total", out var lastpage))
+ {
+ return lastpage.GetInt32();
+ }
+ else
+ {
+ throw new Exception("Failed to find the last page number in the response from TGMC's API");
+ }
+ }
+ }
+}
diff --git a/CentCom.Server/Services/VgBanService.cs b/CentCom.Server/Services/VgBanService.cs
index 577c782..a9068b2 100644
--- a/CentCom.Server/Services/VgBanService.cs
+++ b/CentCom.Server/Services/VgBanService.cs
@@ -1,12 +1,12 @@
using AngleSharp;
using CentCom.Common.Models;
using CentCom.Server.Exceptions;
+using CentCom.Server.Extensions;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
-using System.Text;
using System.Threading.Tasks;
namespace CentCom.Server.Services
@@ -98,11 +98,10 @@ public async Task> GetBansAsync()
expires = DateTime.SpecifyKind(d, DateTimeKind.Utc);
}
- toReturn.Add(new Ban()
+ var toAdd = new Ban()
{
CKey = ckey,
BanType = BanType.Job,
- JobBans = jobs.Select(x => x.ToLower()).Select(x => new JobBan() { Job = x }).ToHashSet(),
Reason = reason,
BannedBy = bannedBy,
BannedOn = date.UtcDateTime,
@@ -110,7 +109,10 @@ public async Task> GetBansAsync()
IP = ip,
CID = cid,
SourceNavigation = _source
- });
+ };
+
+ toAdd.AddJobRange(jobs);
+ toReturn.Add(toAdd);
}
return toReturn;
diff --git a/CentCom.Test/Ban_EqualsShould.cs b/CentCom.Test/Ban_EqualsShould.cs
index 23e19d5..c39c5ae 100644
--- a/CentCom.Test/Ban_EqualsShould.cs
+++ b/CentCom.Test/Ban_EqualsShould.cs
@@ -1,4 +1,6 @@
using CentCom.Common.Models;
+using CentCom.Common.Models.Equality;
+using CentCom.Server.Extensions;
using System;
using System.Collections.Generic;
using System.Net;
@@ -43,8 +45,9 @@ public void Equals_SameBanDifferentID_ReturnTrue()
SourceNavigation = source
};
- Assert.True(banA == banB, "Two bans equal by internal values should be equal");
- Assert.True(banA.GetHashCode() == banB.GetHashCode(), "Two bans equal by internal values should have equal hashcodes");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(banA, banB), "Two bans equal by internal values should be equal");
+ Assert.True(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans equal by internal values should have equal hashcodes");
}
[Fact]
@@ -90,8 +93,9 @@ public void Equals_SameBanDifferentIDDifferentSource_ReturnFalse()
SourceNavigation = sourceB
};
- Assert.False(banA == banB, "Two bans from different sources should not be equal by internal values");
- Assert.False(banA.GetHashCode() == banB.GetHashCode(), "Two bans from different sources should not have equal hashcodes");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.False(comparer.Equals(banA, banB), "Two bans from different sources should not be equal by internal values");
+ Assert.False(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans from different sources should not have equal hashcodes");
}
[Fact]
@@ -109,8 +113,9 @@ public void Equals_SameBanByBanID_ReturnTrue()
CKey = "different"
};
- Assert.True(banA == banB, "Two bans with BanIDs should be checked for equality by ID");
- Assert.True(banA.GetHashCode() == banB.GetHashCode(), "Two bans with BanIDs that are equal should have equal hashcodes");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(banA, banB), "Two bans with BanIDs should be checked for equality by ID");
+ Assert.True(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans with BanIDs that are equal should have equal hashcodes");
}
[Fact]
@@ -148,8 +153,9 @@ public void Equals_SameBanIDDifferentSource_ReturnFalse()
SourceNavigation = sourceB
};
- Assert.False(banA == banB, "Two bans from different sources should not be equal by BanID");
- Assert.False(banA.GetHashCode() == banB.GetHashCode(), "Two bans from different sources should not have equal hashcodes");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.False(comparer.Equals(banA, banB), "Two bans from different sources should not be equal by BanID");
+ Assert.False(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans from different sources should not have equal hashcodes");
}
[Fact]
@@ -158,25 +164,20 @@ public void Equals_SameBanDifferentJobOrder_ReturnTrue()
var banA = new Ban()
{
Id = 12,
- JobBans = new HashSet()
- {
- new JobBan() { Job = "captain" },
- new JobBan() { Job = "assistant" }
- }
+ BanType = BanType.Job
};
+ banA.AddJobRange(new[] { "detective", "head of security", "security officer", "warden" });
var banB = new Ban()
{
Id = 0,
- JobBans = new HashSet()
- {
- new JobBan() { Job = "assistant" },
- new JobBan() { Job = "captain" }
- }
+ BanType = BanType.Job
};
+ banB.AddJobRange(new[] { "head of security", "warden", "detective", "security officer" });
- Assert.True(banA == banB, "Two bans with the same jobbans in different orders should be equal");
- Assert.True(banA.GetHashCode() == banB.GetHashCode(), "Two bans with the same jobbans in different orders should be equal");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(banA, banB), "Two bans with the same jobbans in different orders should be equal");
+ Assert.True(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans with the same jobbans in different orders should be equal");
}
[Fact]
@@ -194,12 +195,12 @@ public void Equals_SameBanNullVsEmptyJobBans_ReturnTrue()
{
Id = 0,
Source = 15,
- BanType = BanType.Server,
- JobBans = new HashSet()
+ BanType = BanType.Server
};
- Assert.True(banA == banB, "Bans should be equal if the jobbans only differ by null and an empty set");
- Assert.True(banA.GetHashCode() == banB.GetHashCode(), "Bans should have the same hashcode if the jobbans only differ by null and an empty set");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(banA, banB), "Bans should be equal if the jobbans only differ by null and an empty set");
+ Assert.True(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Bans should have the same hashcode if the jobbans only differ by null and an empty set");
}
[Fact]
@@ -229,8 +230,9 @@ public void Equals_SameBansSameIP_ReturnsTrue()
IP = IPAddress.Parse("108.20.220.45")
};
- Assert.True(banA == banB, "Bans should be equal if all values are equal, including IP");
- Assert.True(banA.GetHashCode() == banB.GetHashCode(), "Bans should have the same hashcode if all values are equal, including IP");
+ var comparer = BanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(banA, banB), "Bans should be equal if all values are equal, including IP");
+ Assert.True(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Bans should have the same hashcode if all values are equal, including IP");
}
}
}
diff --git a/CentCom.Test/Ban_GetCanonicalKeyShould.cs b/CentCom.Test/Ban_GetCanonicalKeyShould.cs
index 35a3493..403bbdb 100644
--- a/CentCom.Test/Ban_GetCanonicalKeyShould.cs
+++ b/CentCom.Test/Ban_GetCanonicalKeyShould.cs
@@ -1,4 +1,5 @@
using CentCom.Common.Models;
+using CentCom.Server.Extensions;
using System;
using Xunit;
@@ -10,13 +11,13 @@ public class Ban_GetCanonicalKeyShould
public void GetCanonicalKey_FromRaw_ReturnTrue()
{
var rawKey = "B o bbahbrown";
- Assert.True("bobbahbrown" == Ban.GetCanonicalKey(rawKey));
+ Assert.True("bobbahbrown" == BanExtensions.GetCanonicalKey(rawKey));
}
[Fact]
public void GetCanonicalKey_NullArgument_ThrowsException()
{
- Assert.Throws(() => Ban.GetCanonicalKey(null));
+ Assert.Throws(() => BanExtensions.GetCanonicalKey(null));
}
}
}
diff --git a/CentCom.Test/CentCom.Test.csproj b/CentCom.Test/CentCom.Test.csproj
index 184bf7e..61ace9b 100644
--- a/CentCom.Test/CentCom.Test.csproj
+++ b/CentCom.Test/CentCom.Test.csproj
@@ -21,6 +21,7 @@
+
diff --git a/CentCom.Test/JobBan_EqualsShould.cs b/CentCom.Test/JobBan_EqualsShould.cs
index 9c88e1a..9442eb9 100644
--- a/CentCom.Test/JobBan_EqualsShould.cs
+++ b/CentCom.Test/JobBan_EqualsShould.cs
@@ -1,4 +1,5 @@
using CentCom.Common.Models;
+using CentCom.Common.Models.Equality;
using Xunit;
namespace CentCom.Test
@@ -20,8 +21,9 @@ public void Equals_SameJobBan_ReturnTrue()
Job = "ooc"
};
- Assert.True(jobA == jobB, "Two jobs equal by internal values should be equal");
- Assert.True(jobA.GetHashCode() == jobB.GetHashCode(), "Two jobs equal by internal values should have the same hashcode");
+ var comparer = JobBanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(jobA, jobB), "Two jobs equal by internal values should be equal");
+ Assert.True(comparer.GetHashCode(jobA) == comparer.GetHashCode(jobB), "Two jobs equal by internal values should have the same hashcode");
}
///
@@ -44,8 +46,9 @@ public void Equals_SameJobBan_DifferentID_ReturnTrue()
Job = "ooc"
};
- Assert.True(jobA == jobB, "Two jobs equal by job, even with differing IDs, should be equal");
- Assert.True(jobA.GetHashCode() == jobB.GetHashCode(), "Two jobs equal by job, even with differing ids, should have the same hashcode");
+ var comparer = JobBanEqualityComparer.Instance;
+ Assert.True(comparer.Equals(jobA, jobB), "Two jobs equal by job, even with differing IDs, should be equal");
+ Assert.True(comparer.GetHashCode(jobA) == comparer.GetHashCode(jobB), "Two jobs equal by job, even with differing ids, should have the same hashcode");
}
}
}