Refactored for 'ticket number' naming

Added 'ban help identifiers' to list known identifiers
Fixed some typos and restructured some logic
This commit is contained in:
Chris 2020-11-29 16:22:37 +10:30
parent af9957f8ec
commit 514d7ac041
2 changed files with 90 additions and 63 deletions

View file

@ -13,10 +13,10 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
* If there is no section called "Upcoming changes" below this line, please add one with `## Upcoming changes` as the first line, and then a bulleted item directly after with the first change.
## Upcoming Changes
* Overhauled Bans system. Bans are now based on 'identifiers'.(@QuiCM)
* The old Bans table (`Bans`) has been deprecated. New bans will go in `PlayerBans`. Use `/ban convert` to convert to the new system.
* Overhauled Bans system. Bans are now based on 'identifiers'. (@QuiCM)
* The old Bans table (`Bans`) has been deprecated. New bans will go in `PlayerBans`. Old bans will be converted automatically to the new system.
* All old ban routes in REST are now redirected. Please use `/v3/bans/*` for REST-based ban management.
* TShock recognizes and acts upon 4 main identifiers: UUID, IP, Player Name, Account name. This can be extended by plugins.
* TShock recognizes and acts upon 4 main identifiers: UUID, IP, Player Name, Account name. This can be extended by plugins. New identifiers can be added to the `ban help identifiers` output by registering them in `TShockAPI.DB.Identifier.Register(string, string)`
* By default, bans are no longer removed upon expiry or 'deletion'. Instead, they remain in the system. A new ban for an indentifier can be added once an existing ban has expired.
* Server Console now understands Terraria color codes (e.g., `[c/FF00FF:Words]`) and prints the colored text to the console. Note that console colors are limited and thus only approximations. (@QuiCM)
* Fixed a bug in `/sudo` that prevented quoted arguments being forwarded properly. Example: `/sudo /user group "user name" "user group"` should now work correctly. (@QuiCM)

View file

@ -1269,6 +1269,7 @@ namespace TShockAPI
{
//Ban syntax:
// ban add <target> [reason] [duration] [flags (default: -a -u -ip)]
// Duration is in the format 0d0h0m0s. Any part can be ignored. E.g., 1s is a valid ban time, as is 1d1s, etc. If no duration is specified, ban is permanent
// Valid flags: -a (ban account name), -u (ban UUID), -n (ban character name), -ip (ban IP address), -e (exact, ban the identifier provided as 'target')
// Unless -e is passed to the command, <target> is assumed to be a player or player index.
// ban del <ban ID>
@ -1277,6 +1278,8 @@ namespace TShockAPI
// Displays a paginated list of bans
// ban details <ban ID>
// Target is expected to be a ban Unique ID
//ban help [command]
// Provides extended help on specific ban commands
void Help()
{
@ -1292,6 +1295,7 @@ namespace TShockAPI
args.Player.SendMessage($"ban {"del".Color(Utils.RedHighlight)} <Ban ID>", Color.White);
args.Player.SendMessage($"ban {"list".Color(Utils.RedHighlight)}", Color.White);
args.Player.SendMessage($"ban {"details".Color(Utils.RedHighlight)} <Ban ID>", Color.White);
args.Player.SendMessage($"Quick usage: {"ban add".Color(Utils.BoldHighlight)} {args.Player.Name.Color(Utils.RedHighlight)} \"Griefing\"", Color.White);
args.Player.SendMessage($"For more info, use {"ban help".Color(Utils.BoldHighlight)} {"command".Color(Utils.RedHighlight)}", Color.White);
}
@ -1305,6 +1309,7 @@ namespace TShockAPI
args.Player.SendMessage($"{"ban add".Color(Utils.BoldHighlight)} <{"Target".Color(Utils.RedHighlight)}> [{"Reason".Color(Utils.BoldHighlight)}] [{"Duration".Color(Utils.PinkHighlight)}] [{"Flags".Color(Utils.GreenHighlight)}]", Color.White);
args.Player.SendMessage($"- {"Duration".Color(Utils.PinkHighlight)}: uses the format {"0d0m0s".Color(Utils.PinkHighlight)} to determine the length of the ban.", Color.White);
args.Player.SendMessage($" Eg a value of {"10d30m0s".Color(Utils.PinkHighlight)} would represent 10 days, 30 minutes, 0 seconds.", Color.White);
args.Player.SendMessage($" If no duration is provided, the ban will be permanent.", Color.White);
args.Player.SendMessage($"- {"Flags".Color(Utils.GreenHighlight)}: -a (account name), -u (UUID), -n (character name), -ip (IP address), -e (exact, {"Target".Color(Utils.RedHighlight)} will be treated as identifier)", Color.White);
args.Player.SendMessage($" Unless {"-e".Color(Utils.GreenHighlight)} is passed to the command, {"Target".Color(Utils.RedHighlight)} is assumed to be a player or player index", Color.White);
args.Player.SendMessage($" If no {"Flags".Color(Utils.GreenHighlight)} are specified, the command uses {"-a -u -ip".Color(Utils.GreenHighlight)} by default.", Color.White);
@ -1314,8 +1319,8 @@ namespace TShockAPI
case "del":
args.Player.SendMessage("", Color.White);
args.Player.SendMessage("Ban Del Syntax", Color.White);
args.Player.SendMessage($"{"ban del".Color(Utils.BoldHighlight)} <{"Ban ID".Color(Utils.RedHighlight)}>", Color.White);
args.Player.SendMessage($"- {"Ban IDs".Color(Utils.RedHighlight)}s are provided when you add a ban, and can be found with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
args.Player.SendMessage($"{"ban del".Color(Utils.BoldHighlight)} <{"Ticket Number".Color(Utils.RedHighlight)}>", Color.White);
args.Player.SendMessage($"- {"Ticket Number".Color(Utils.RedHighlight)}s are provided when you add a ban, and can also be viewed with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
args.Player.SendMessage($"Example usage: {"ban del".Color(Utils.BoldHighlight)} {"12345".Color(Utils.RedHighlight)}", Color.White);
break;
@ -1330,11 +1335,33 @@ namespace TShockAPI
case "details":
args.Player.SendMessage("", Color.White);
args.Player.SendMessage("Ban Details Syntax", Color.White);
args.Player.SendMessage($"{"ban details".Color(Utils.BoldHighlight)} <{"Ban ID".Color(Utils.RedHighlight)}>", Color.White);
args.Player.SendMessage($"- {"Ban IDs".Color(Utils.RedHighlight)}s are provided when you add a ban, and can be found with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
args.Player.SendMessage($"{"ban details".Color(Utils.BoldHighlight)} <{"Ticket Number".Color(Utils.RedHighlight)}>", Color.White);
args.Player.SendMessage($"- {"Ticket Number".Color(Utils.RedHighlight)}s are provided when you add a ban, and can be found with the {"ban list".Color(Utils.BoldHighlight)} command.", Color.White);
args.Player.SendMessage($"Example usage: {"ban details".Color(Utils.BoldHighlight)} {"12345".Color(Utils.RedHighlight)}", Color.White);
break;
case "identifiers":
if (!PaginationTools.TryParsePageNumber(args.Parameters, 2, args.Player, out int pageNumber))
{
args.Player.SendMessage($"Invalid page number. Page number should be numeric.", Color.White);
return;
}
var idents = from ident in Identifier.Available
select $"{ident.Color(Utils.RedHighlight)} - {ident.Description}";
args.Player.SendMessage("", Color.White);
PaginationTools.SendPage(args.Player, pageNumber, idents.ToList(),
new PaginationTools.Settings
{
HeaderFormat = "Available identifiers ({0}/{1}):",
FooterFormat = "Type {0}ban help identifiers {{0}} for more.".SFormat(Specifier),
NothingToDisplayString = "There are currently no available identifiers.",
HeaderTextColor = Color.White,
LineTextColor = Color.White
});
break;
default:
args.Player.SendMessage($"Unknown ban command. Try {"add".Color(Utils.RedHighlight)}, {"del".Color(Utils.RedHighlight)}, {"list".Color(Utils.RedHighlight)}, or {"details".Color(Utils.RedHighlight)}.", Color.White);
break;
@ -1349,7 +1376,7 @@ namespace TShockAPI
args.Player.SendMessage($"{"Banned by:".Color(Utils.BoldHighlight)} {ban.BanningUser.Color(Utils.GreenHighlight)} on {ban.BanDateTime.ToString("yyyy/MM/dd").Color(Utils.RedHighlight)} ({ban.GetPrettyTimeSinceBanString().Color(Utils.YellowHighlight)} ago)", Color.White);
if (ban.ExpirationDateTime < DateTime.UtcNow)
{
args.Player.SendMessage($"{"Banned expired:".Color(Utils.BoldHighlight)} {ban.ExpirationDateTime.ToString("yyyy/MM/dd").Color(Utils.RedHighlight)} ({ban.GetPrettyExpirationString().Color(Utils.YellowHighlight)} ago)", Color.White);
args.Player.SendMessage($"{"Ban expired:".Color(Utils.BoldHighlight)} {ban.ExpirationDateTime.ToString("yyyy/MM/dd").Color(Utils.RedHighlight)} ({ban.GetPrettyExpirationString().Color(Utils.YellowHighlight)} ago)", Color.White);
}
else
{
@ -1363,10 +1390,26 @@ namespace TShockAPI
remaining = $"{ban.GetPrettyExpirationString().Color(Utils.YellowHighlight)} remaining";
}
args.Player.SendMessage($"{"Banned expires:".Color(Utils.BoldHighlight)} {ban.ExpirationDateTime.ToString("yyyy/MM/dd").Color(Utils.RedHighlight)} ({remaining})", Color.White);
args.Player.SendMessage($"{"Ban expires:".Color(Utils.BoldHighlight)} {ban.ExpirationDateTime.ToString("yyyy/MM/dd").Color(Utils.RedHighlight)} ({remaining})", Color.White);
}
}
AddBanResult DoBan(string ident, string reason, DateTime expiration)
{
AddBanResult banResult = TShock.Bans.InsertBan(ident, reason, args.Player.Account.Name, DateTime.UtcNow, expiration);
if (banResult.Ban != null)
{
args.Player.SendSuccessMessage($"Ban added. Ticket Number {banResult.Ban.TicketNumber.Color(Utils.GreenHighlight)} was created for identifier {ident.Color(Utils.WhiteHighlight)}.");
}
else
{
args.Player.SendWarningMessage($"Failed to add ban for identifier: {ident.Color(Utils.WhiteHighlight)}");
args.Player.SendWarningMessage($"Reason: {banResult.Message}");
}
return banResult;
}
void AddBan()
{
if (!args.Parameters.TryGetValue(1, out string target))
@ -1381,17 +1424,23 @@ namespace TShockAPI
bool banName = args.Parameters.Any(p => p == "-n");
bool banIp = args.Parameters.Any(p => p == "-ip");
List<string> flags = new List<string>() { "-e", "-a", "-u", "-n", "-ip" };
string reason = "Banned.";
string duration = null;
DateTime expiration = DateTime.MaxValue;
AddBanResult banResult;
//This is hacky, but because the flag values can go at any parameter, this is forcing the ordering of 'reason' and 'duration'
//while still allowing them to be arbitrarily placed in the parameter list
//This is hacky. We want flag values to be independent of order so we must force the consecutive ordering of the 'reason' and 'duration' parameters,
//while still allowing them to be placed arbitrarily in the parameter list.
//As an example, the following parameter lists (and more) should all be acceptable:
//-u "reason" -a duration -ip
//"reason" duration -u -a -ip
//-u -a -ip "reason" duration
//-u -a -ip
for (int i = 2; i < args.Parameters.Count; i++)
{
var param = args.Parameters[i];
if (param != "-e" && param != "-a" && param != "-u" && param != "-n" && param != "-ip")
if (!flags.Contains(param))
{
reason = param;
break;
@ -1400,7 +1449,7 @@ namespace TShockAPI
for (int i = 3; i < args.Parameters.Count; i++)
{
var param = args.Parameters[i];
if (param != "-e" && param != "-a" && param != "-u" && param != "-n" && param != "-ip")
if (!flags.Contains(param))
{
duration = param;
break;
@ -1418,18 +1467,11 @@ namespace TShockAPI
banAccount = banUuid = banIp = true;
}
reason = reason ?? "Banned";
if (exactTarget)
{
banResult = TShock.Bans.InsertBan(target, reason ?? "Banned", args.Player.Account.Name, DateTime.UtcNow, expiration);
if (banResult.Ban != null)
{
args.Player.SendSuccessMessage($"Ban added. Ticket Number: {banResult.Ban.TicketNumber}.");
DisplayBanDetails(banResult.Ban);
}
else
{
args.Player.SendErrorMessage($"Failed to add ban. {banResult.Message}");
}
DoBan(target, reason, expiration);
return;
}
@ -1448,50 +1490,34 @@ namespace TShockAPI
}
var player = players[0];
string banReason = null;
void DoBan(string ident)
{
banResult = TShock.Bans.InsertBan(ident, reason, args.Player.Account.Name, DateTime.UtcNow, expiration);
if (banResult.Ban != null)
{
args.Player.SendSuccessMessage($"Ban Ticket Number {banResult.Ban.TicketNumber.Color(Utils.GreenHighlight)} created for identifier {ident}.");
banReason = banResult.Ban.Reason;
}
else
{
args.Player.SendWarningMessage($"Ban skipped for identifier: {ident}");
args.Player.SendWarningMessage($"Reason: {banResult.Message}");
}
}
AddBanResult banResult = null;
if (banAccount)
{
if (player.Account != null)
{
DoBan($"{Identifier.Account}{player.Account.Name}");
banResult = DoBan($"{Identifier.Account}{player.Account.Name}", reason, expiration);
}
}
if (banUuid)
{
DoBan($"{Identifier.UUID}{player.UUID}");
banResult = DoBan($"{Identifier.UUID}{player.UUID}", reason, expiration);
}
if (banName)
{
DoBan($"{Identifier.Name}{player.Name}");
banResult = DoBan($"{Identifier.Name}{player.Name}", reason, expiration);
}
if (banIp)
{
DoBan($"{Identifier.IP}{player.IP}");
banResult = DoBan($"{Identifier.IP}{player.IP}", reason, expiration);
}
//Using the ban reason to determine if a ban actually happened or not is messy, but it works
if (banReason != null)
if (banResult?.Ban != null)
{
player.Disconnect($"You have been banned: {banReason}.");
player.Disconnect($"You have been banned: {banResult.Ban.Reason}.");
}
}
@ -1505,13 +1531,14 @@ namespace TShockAPI
if (!int.TryParse(target, out int banId))
{
args.Player.SendMessage($"Invalid Ban ID. Refer to {"ban help del".Color(Utils.BoldHighlight)} for details on how to use the {"ban del".Color(Utils.BoldHighlight)} command", Color.White);
args.Player.SendMessage($"Invalid Ticket Number. Refer to {"ban help del".Color(Utils.BoldHighlight)} for details on how to use the {"ban del".Color(Utils.BoldHighlight)} command", Color.White);
return;
}
if (TShock.Bans.RemoveBan(banId))
{
args.Player.SendSuccessMessage($"Ban {banId} has now been marked as expired.");
TShock.Log.ConsoleInfo($"Ban {banId} has been revoked by {args.Player.Account.Name}.");
args.Player.SendSuccessMessage($"Ban {banId.Color(Utils.GreenHighlight)} has now been marked as expired.");
}
else
{
@ -1519,20 +1546,20 @@ namespace TShockAPI
}
}
string PickColorForBan(Ban ban)
{
double hoursRemaining = (ban.ExpirationDateTime - DateTime.UtcNow).TotalHours;
double hoursTotal = (ban.ExpirationDateTime - ban.BanDateTime).TotalHours;
double percentRemaining = TShock.Utils.Clamp(hoursRemaining / hoursTotal, 100, 0);
int red = TShock.Utils.Clamp((int)(255 * 2.0f * percentRemaining), 255, 0);
int green = TShock.Utils.Clamp((int)(255 * (2.0f * (1 - percentRemaining))), 255, 0);
return $"{red:X2}{green:X2}{0:X2}";
}
void ListBans()
{
string PickColorForBan(Ban ban)
{
double hoursRemaining = (ban.ExpirationDateTime - DateTime.UtcNow).TotalHours;
double hoursTotal = (ban.ExpirationDateTime - ban.BanDateTime).TotalHours;
double percentRemaining = TShock.Utils.Clamp(hoursRemaining / hoursTotal, 100, 0);
int red = TShock.Utils.Clamp((int)(255 * 2.0f * percentRemaining), 255, 0);
int green = TShock.Utils.Clamp((int)(255 * (2.0f * (1 - percentRemaining))), 255, 0);
return $"{red:X2}{green:X2}{0:X2}";
}
if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out int pageNumber))
{
args.Player.SendMessage($"Invalid Ban List syntax. Refer to {"ban help list".Color(Utils.BoldHighlight)} for details on how to use the {"ban list".Color(Utils.BoldHighlight)} command", Color.White);
@ -1563,7 +1590,7 @@ namespace TShockAPI
if (!int.TryParse(target, out int banId))
{
args.Player.SendMessage($"Invalid Ban ID. Refer to {"ban help details".Color(Utils.BoldHighlight)} for details on how to use the {"ban details".Color(Utils.BoldHighlight)} command", Color.White);
args.Player.SendMessage($"Invalid Ticket Number. Refer to {"ban help details".Color(Utils.BoldHighlight)} for details on how to use the {"ban details".Color(Utils.BoldHighlight)} command", Color.White);
return;
}
@ -1571,7 +1598,7 @@ namespace TShockAPI
if (ban == null)
{
args.Player.SendErrorMessage("No ban found matching the given identifier");
args.Player.SendErrorMessage("No bans found matching the provided ticket number");
return;
}