chore: code cleanup (mostly whitespace / remove unused imports)
This commit is contained in:
parent
56155782c3
commit
7afba4ea95
@ -11,5 +11,4 @@ public record MessageRequest
|
|||||||
public Embed[]? Embeds { get; set; }
|
public Embed[]? Embeds { get; set; }
|
||||||
public MessageComponent[]? Components { get; set; }
|
public MessageComponent[]? Components { get; set; }
|
||||||
public Message.Reference? MessageReference { get; set; }
|
public Message.Reference? MessageReference { get; set; }
|
||||||
|
|
||||||
}
|
}
|
@ -19,6 +19,7 @@ namespace PluralKit.API;
|
|||||||
public class PrivateController: PKControllerBase
|
public class PrivateController: PKControllerBase
|
||||||
{
|
{
|
||||||
private readonly RedisService _redis;
|
private readonly RedisService _redis;
|
||||||
|
|
||||||
public PrivateController(IServiceProvider svc) : base(svc)
|
public PrivateController(IServiceProvider svc) : base(svc)
|
||||||
{
|
{
|
||||||
_redis = svc.GetRequiredService<RedisService>();
|
_redis = svc.GetRequiredService<RedisService>();
|
||||||
|
@ -2,12 +2,9 @@ using System.Reflection;
|
|||||||
|
|
||||||
using Autofac;
|
using Autofac;
|
||||||
|
|
||||||
using App.Metrics.AspNetCore;
|
|
||||||
|
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Diagnostics;
|
using Microsoft.AspNetCore.Diagnostics;
|
||||||
using Microsoft.AspNetCore.Mvc.Versioning;
|
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -100,7 +97,9 @@ public class Startup
|
|||||||
.As<IConfiguration>();
|
.As<IConfiguration>();
|
||||||
builder.RegisterModule(new ConfigModule<ApiConfig>("API"));
|
builder.RegisterModule(new ConfigModule<ApiConfig>("API"));
|
||||||
builder.RegisterModule(new LoggingModule("api",
|
builder.RegisterModule(new LoggingModule("api",
|
||||||
cfg: new LoggerConfiguration().Filter.ByExcluding(exc => exc.Exception is PKError || exc.Exception.IsUserError())));
|
cfg: new LoggerConfiguration().Filter.ByExcluding(
|
||||||
|
exc => exc.Exception is PKError || exc.Exception.IsUserError()
|
||||||
|
)));
|
||||||
// builder.RegisterModule(new MetricsModule("API"));
|
// builder.RegisterModule(new MetricsModule("API"));
|
||||||
builder.RegisterModule<DataStoreModule>();
|
builder.RegisterModule<DataStoreModule>();
|
||||||
builder.RegisterModule<APIModule>();
|
builder.RegisterModule<APIModule>();
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
using System.Net.WebSockets;
|
|
||||||
|
|
||||||
using App.Metrics;
|
using App.Metrics;
|
||||||
|
|
||||||
using Autofac;
|
using Autofac;
|
||||||
@ -123,7 +121,11 @@ public class Bot
|
|||||||
{
|
{
|
||||||
Activities = new[]
|
Activities = new[]
|
||||||
{
|
{
|
||||||
new Activity {Name = "Restarting... (please wait)", Type = ActivityType.Game}
|
new Activity
|
||||||
|
{
|
||||||
|
Name = "Restarting... (please wait)",
|
||||||
|
Type = ActivityType.Game
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Status = GatewayStatusUpdate.UserStatus.Idle
|
Status = GatewayStatusUpdate.UserStatus.Idle
|
||||||
})));
|
})));
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using App.Metrics;
|
using App.Metrics;
|
||||||
using App.Metrics.Gauge;
|
|
||||||
using App.Metrics.Meter;
|
using App.Metrics.Meter;
|
||||||
using App.Metrics.Timer;
|
using App.Metrics.Timer;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ public partial class CommandTree
|
|||||||
await ctx.Reply(
|
await ctx.Reply(
|
||||||
$"{Emojis.Error} Unknown command `pk;{ctx.FullCommand().Truncate(100)}`. Perhaps you meant to use one of the following commands?\n{commandListStr}\n\nFor a full list of possible commands, see <https://pluralkit.me/commands>.");
|
$"{Emojis.Error} Unknown command `pk;{ctx.FullCommand().Truncate(100)}`. Perhaps you meant to use one of the following commands?\n{commandListStr}\n\nFor a full list of possible commands, see <https://pluralkit.me/commands>.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PrintCommandExpectedError(Context ctx, params Command[] potentialCommands)
|
private async Task PrintCommandExpectedError(Context ctx, params Command[] potentialCommands)
|
||||||
{
|
{
|
||||||
var commandListStr = CreatePotentialCommandList(potentialCommands);
|
var commandListStr = CreatePotentialCommandList(potentialCommands);
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
using Humanizer;
|
|
||||||
|
|
||||||
using Myriad.Builders;
|
using Myriad.Builders;
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
using PluralKit.Core;
|
using PluralKit.Core;
|
||||||
|
|
||||||
namespace PluralKit.Bot;
|
namespace PluralKit.Bot;
|
||||||
|
@ -1,15 +1,11 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
using Humanizer;
|
|
||||||
|
|
||||||
using Myriad.Builders;
|
using Myriad.Builders;
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
using PluralKit.Core;
|
using PluralKit.Core;
|
||||||
|
|
||||||
namespace PluralKit.Bot;
|
namespace PluralKit.Bot;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
using Myriad.Extensions;
|
|
||||||
using Myriad.Rest.Exceptions;
|
using Myriad.Rest.Exceptions;
|
||||||
using Myriad.Rest.Types;
|
using Myriad.Rest.Types;
|
||||||
using Myriad.Rest.Types.Requests;
|
using Myriad.Rest.Types.Requests;
|
||||||
|
@ -5,8 +5,6 @@ using Humanizer;
|
|||||||
using Myriad.Builders;
|
using Myriad.Builders;
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
using PluralKit.Core;
|
using PluralKit.Core;
|
||||||
|
|
||||||
namespace PluralKit.Bot;
|
namespace PluralKit.Bot;
|
||||||
|
@ -323,6 +323,7 @@ public class MemberEdit
|
|||||||
}
|
}
|
||||||
|
|
||||||
private string boldIf(string str, bool condition) => condition ? $"**{str}**" : str;
|
private string boldIf(string str, bool condition) => condition ? $"**{str}**" : str;
|
||||||
|
|
||||||
private async Task<EmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target)
|
private async Task<EmbedBuilder> CreateMemberNameInfoEmbed(Context ctx, PKMember target)
|
||||||
{
|
{
|
||||||
var lcx = ctx.LookupContextFor(target.System);
|
var lcx = ctx.LookupContextFor(target.System);
|
||||||
|
@ -20,6 +20,7 @@ namespace PluralKit.Bot;
|
|||||||
public class ProxiedMessage
|
public class ProxiedMessage
|
||||||
{
|
{
|
||||||
private static readonly Duration EditTimeout = Duration.FromMinutes(10);
|
private static readonly Duration EditTimeout = Duration.FromMinutes(10);
|
||||||
|
|
||||||
// private readonly IDiscordCache _cache;
|
// private readonly IDiscordCache _cache;
|
||||||
private readonly IClock _clock;
|
private readonly IClock _clock;
|
||||||
|
|
||||||
|
@ -3,10 +3,6 @@ using System.Text.RegularExpressions;
|
|||||||
using Myriad.Builders;
|
using Myriad.Builders;
|
||||||
using Myriad.Types;
|
using Myriad.Types;
|
||||||
|
|
||||||
using NodaTime;
|
|
||||||
using NodaTime.Text;
|
|
||||||
using NodaTime.TimeZones;
|
|
||||||
|
|
||||||
using PluralKit.Core;
|
using PluralKit.Core;
|
||||||
|
|
||||||
namespace PluralKit.Bot;
|
namespace PluralKit.Bot;
|
||||||
@ -479,9 +475,10 @@ public class SystemEdit
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new PKSyntaxError(
|
throw new PKSyntaxError("This system does not have a banner image set."
|
||||||
"This system does not have a banner image set." + (isOwnSystem ? "Set one by attaching an image to this command, or by passing an image URL or @mention." : ""));
|
+ (isOwnSystem ? "Set one by attaching an image to this command, or by passing an image URL or @mention." : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,7 +511,6 @@ public class SystemEdit
|
|||||||
? ctx.Reply(msg, new EmbedBuilder().Image(new Embed.EmbedImage(img.Url)).Build())
|
? ctx.Reply(msg, new EmbedBuilder().Image(new Embed.EmbedImage(img.Url)).Build())
|
||||||
: ctx.Reply(msg));
|
: ctx.Reply(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Delete(Context ctx, PKSystem target)
|
public async Task Delete(Context ctx, PKSystem target)
|
||||||
|
@ -52,12 +52,7 @@ public class MessageCreated: IEventHandler<MessageCreateEvent>
|
|||||||
_dmCache = dmCache;
|
_dmCache = dmCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for now, only return error messages for explicit commands
|
public ulong? ErrorChannelFor(MessageCreateEvent evt, ulong userId) => evt.ChannelId;
|
||||||
public ulong? ErrorChannelFor(MessageCreateEvent evt, ulong userId)
|
|
||||||
{
|
|
||||||
return evt.ChannelId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsDuplicateMessage(Message msg) =>
|
private bool IsDuplicateMessage(Message msg) =>
|
||||||
// We consider a message duplicate if it has the same ID as the previous message that hit the gateway
|
// We consider a message duplicate if it has the same ID as the previous message that hit the gateway
|
||||||
_lastMessageCache.GetLastMessage(msg.ChannelId)?.Current.Id == msg.Id;
|
_lastMessageCache.GetLastMessage(msg.ChannelId)?.Current.Id == msg.Id;
|
||||||
|
@ -63,7 +63,8 @@ public class ProxyService
|
|||||||
if (autoproxySettings.AutoproxyMode == AutoproxyMode.Latch && IsUnlatch(message))
|
if (autoproxySettings.AutoproxyMode == AutoproxyMode.Latch && IsUnlatch(message))
|
||||||
{
|
{
|
||||||
// "unlatch"
|
// "unlatch"
|
||||||
await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new() {
|
await _repo.UpdateAutoproxy(ctx.SystemId.Value, guild.Id, null, new()
|
||||||
|
{
|
||||||
AutoproxyMember = null
|
AutoproxyMember = null
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
|
@ -18,8 +18,8 @@ public class ErrorMessageService
|
|||||||
// globally rate limit errors for now, don't want to spam users when something breaks
|
// globally rate limit errors for now, don't want to spam users when something breaks
|
||||||
private static readonly Duration MinErrorInterval = Duration.FromSeconds(10);
|
private static readonly Duration MinErrorInterval = Duration.FromSeconds(10);
|
||||||
private static readonly Duration IntervalFromStartup = Duration.FromMinutes(2);
|
private static readonly Duration IntervalFromStartup = Duration.FromMinutes(2);
|
||||||
private readonly ILogger _logger;
|
|
||||||
|
|
||||||
|
private readonly ILogger _logger;
|
||||||
private readonly BotConfig _botConfig;
|
private readonly BotConfig _botConfig;
|
||||||
private readonly IMetrics _metrics;
|
private readonly IMetrics _metrics;
|
||||||
private readonly DiscordApiClient _rest;
|
private readonly DiscordApiClient _rest;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
using Myriad.Cache;
|
|
||||||
using Myriad.Gateway;
|
using Myriad.Gateway;
|
||||||
using Myriad.Rest;
|
using Myriad.Rest;
|
||||||
|
|
||||||
@ -10,11 +9,11 @@ namespace PluralKit.Bot;
|
|||||||
|
|
||||||
public class PrivateChannelService
|
public class PrivateChannelService
|
||||||
{
|
{
|
||||||
|
private static readonly Dictionary<ulong, ulong> _channelsCache = new();
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ModelRepository _repo;
|
private readonly ModelRepository _repo;
|
||||||
private readonly DiscordApiClient _rest;
|
private readonly DiscordApiClient _rest;
|
||||||
|
|
||||||
private static Dictionary<ulong, ulong> _channelsCache = new();
|
|
||||||
public PrivateChannelService(ILogger logger, ModelRepository repo, DiscordApiClient rest)
|
public PrivateChannelService(ILogger logger, ModelRepository repo, DiscordApiClient rest)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
@ -169,7 +169,8 @@ public static class ContextUtils
|
|||||||
if (currentPage < 0) currentPage += pageCount;
|
if (currentPage < 0) currentPage += pageCount;
|
||||||
|
|
||||||
// If we can, remove the user's reaction (so they can press again quickly)
|
// If we can, remove the user's reaction (so they can press again quickly)
|
||||||
if ((await ctx.BotPermissions).HasFlag(PermissionSet.ManageMessages)) try
|
if ((await ctx.BotPermissions).HasFlag(PermissionSet.ManageMessages))
|
||||||
|
try
|
||||||
{
|
{
|
||||||
await ctx.Rest.DeleteUserReaction(msg.ChannelId, msg.Id, reaction.Emoji, reaction.UserId);
|
await ctx.Rest.DeleteUserReaction(msg.ChannelId, msg.Id, reaction.Emoji, reaction.UserId);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ using App.Metrics;
|
|||||||
|
|
||||||
using Dapper;
|
using Dapper;
|
||||||
|
|
||||||
using Npgsql;
|
|
||||||
|
|
||||||
using SqlKata;
|
using SqlKata;
|
||||||
|
|
||||||
namespace PluralKit.Core;
|
namespace PluralKit.Core;
|
||||||
@ -82,9 +80,11 @@ internal partial class Database: IDatabase
|
|||||||
var query = _compiler.Compile(q);
|
var query = _compiler.Compile(q);
|
||||||
using var conn = await Obtain();
|
using var conn = await Obtain();
|
||||||
using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName)))
|
using (_metrics.Measure.Timer.Time(CoreMetrics.DatabaseQuery, new MetricTags("Query", queryName)))
|
||||||
|
{
|
||||||
await foreach (var val in conn.QueryStreamAsync<T>(query.Sql, query.NamedBindings))
|
await foreach (var val in conn.QueryStreamAsync<T>(query.Sql, query.NamedBindings))
|
||||||
yield return val;
|
yield return val;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the procedures (message_context and proxy_members, as of writing) have their own metrics tracking elsewhere
|
// the procedures (message_context and proxy_members, as of writing) have their own metrics tracking elsewhere
|
||||||
// still, including them here for consistency
|
// still, including them here for consistency
|
||||||
|
@ -30,8 +30,8 @@ as $$
|
|||||||
system.id as system_id,
|
system.id as system_id,
|
||||||
system.is_deleting,
|
system.is_deleting,
|
||||||
guild.log_channel,
|
guild.log_channel,
|
||||||
(channel_id = any(guild.blacklist)) as in_blacklist,
|
(channel_id = any (guild.blacklist)) as in_blacklist,
|
||||||
(channel_id = any(guild.log_blacklist)) as in_log_blacklist,
|
(channel_id = any (guild.log_blacklist)) as in_log_blacklist,
|
||||||
coalesce(guild.log_cleanup_enabled, false),
|
coalesce(guild.log_cleanup_enabled, false),
|
||||||
coalesce(system_guild.proxy_enabled, true) as proxy_enabled,
|
coalesce(system_guild.proxy_enabled, true) as proxy_enabled,
|
||||||
system_last_switch.switch as last_switch,
|
system_last_switch.switch as last_switch,
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
|
||||||
using Dapper;
|
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace PluralKit.Core;
|
namespace PluralKit.Core;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using Dapper.Contrib.Extensions;
|
using Dapper.Contrib.Extensions;
|
||||||
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
@ -90,7 +89,8 @@ public static class PKSystemExt
|
|||||||
ctx == LookupContext.ByOwner ? system.DescriptionPrivacy.ToJsonString() : null);
|
ctx == LookupContext.ByOwner ? system.DescriptionPrivacy.ToJsonString() : null);
|
||||||
o.Add("member_list_privacy",
|
o.Add("member_list_privacy",
|
||||||
ctx == LookupContext.ByOwner ? system.MemberListPrivacy.ToJsonString() : null);
|
ctx == LookupContext.ByOwner ? system.MemberListPrivacy.ToJsonString() : null);
|
||||||
o.Add("group_list_privacy", ctx == LookupContext.ByOwner ? system.GroupListPrivacy.ToJsonString() : null);
|
o.Add("group_list_privacy",
|
||||||
|
ctx == LookupContext.ByOwner ? system.GroupListPrivacy.ToJsonString() : null);
|
||||||
o.Add("front_privacy", ctx == LookupContext.ByOwner ? system.FrontPrivacy.ToJsonString() : null);
|
o.Add("front_privacy", ctx == LookupContext.ByOwner ? system.FrontPrivacy.ToJsonString() : null);
|
||||||
o.Add("front_history_privacy",
|
o.Add("front_history_privacy",
|
||||||
ctx == LookupContext.ByOwner ? system.FrontHistoryPrivacy.ToJsonString() : null);
|
ctx == LookupContext.ByOwner ? system.FrontHistoryPrivacy.ToJsonString() : null);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
|
|
||||||
using SqlKata;
|
using SqlKata;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
using NodaTime;
|
|
||||||
|
|
||||||
using SqlKata;
|
using SqlKata;
|
||||||
|
|
||||||
namespace PluralKit.Core;
|
namespace PluralKit.Core;
|
||||||
|
@ -24,6 +24,7 @@ public class LoggingModule: Module
|
|||||||
public LoggingModule(string component, Action<LoggerConfiguration> fn = null, LoggerConfiguration cfg = null)
|
public LoggingModule(string component, Action<LoggerConfiguration> fn = null, LoggerConfiguration cfg = null)
|
||||||
{
|
{
|
||||||
_component = component;
|
_component = component;
|
||||||
|
// todo: this is messy and not really used anywhere...?
|
||||||
_fn = fn ?? (_ => { });
|
_fn = fn ?? (_ => { });
|
||||||
_cfg = cfg ?? new LoggerConfiguration();
|
_cfg = cfg ?? new LoggerConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ public static class Limits
|
|||||||
public static readonly int MaxMemberCount = 1000;
|
public static readonly int MaxMemberCount = 1000;
|
||||||
public static readonly int MaxGroupCount = 250;
|
public static readonly int MaxGroupCount = 250;
|
||||||
public static int WarnThreshold(int limit) => limit - 50;
|
public static int WarnThreshold(int limit) => limit - 50;
|
||||||
|
|
||||||
public static readonly int MaxDescriptionLength = 1000;
|
public static readonly int MaxDescriptionLength = 1000;
|
||||||
public static readonly int MaxProxyTagLength = 100;
|
public static readonly int MaxProxyTagLength = 100;
|
||||||
public static readonly int MaxSwitchMemberCount = 150;
|
public static readonly int MaxSwitchMemberCount = 150;
|
||||||
|
@ -4,7 +4,7 @@ namespace PluralKit.Core;
|
|||||||
|
|
||||||
public static class Proto
|
public static class Proto
|
||||||
{
|
{
|
||||||
private static Dictionary<string, MessageParser> _parser = new();
|
private static readonly Dictionary<string, MessageParser> _parser = new();
|
||||||
|
|
||||||
public static byte[] Marshal(this IMessage message) => message.ToByteArray();
|
public static byte[] Marshal(this IMessage message) => message.ToByteArray();
|
||||||
|
|
||||||
@ -12,11 +12,11 @@ public static class Proto
|
|||||||
{
|
{
|
||||||
var type = typeof(T).ToString();
|
var type = typeof(T).ToString();
|
||||||
if (_parser.ContainsKey(type))
|
if (_parser.ContainsKey(type))
|
||||||
return (T)_parser[type].ParseFrom(message);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
return (T)_parser[type].ParseFrom(message);
|
||||||
|
}
|
||||||
|
|
||||||
_parser.Add(type, new MessageParser<T>(() => new T()));
|
_parser.Add(type, new MessageParser<T>(() => new T()));
|
||||||
return Unmarshal<T>(message);
|
return Unmarshal<T>(message);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,5 +22,4 @@ public static class Metrics
|
|||||||
Context = "Bot",
|
Context = "Bot",
|
||||||
MeasurementUnit = Unit.Items
|
MeasurementUnit = Unit.Items
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user