Added admin-only .warndelete command

This commit is contained in:
Toastie (DCS Team) 2024-07-27 19:13:39 +12:00
parent e4cc5f4e80
commit 9094b4e144
Signed by: toastie_t0ast
GPG key ID: 27F3B6855AFD40A4
5 changed files with 176 additions and 114 deletions

View file

@ -273,6 +273,31 @@ public partial class Administration
.SendAsync(); .SendAsync();
} }
[Cmd]
[RequireContext(ContextType.Guild)]
[UserPerm(GuildPerm.Administrator)]
public Task WarnDelete(IGuildUser user, int index)
=> WarnDelete(user.Id, index);
[Cmd]
[RequireContext(ContextType.Guild)]
[UserPerm(GuildPermission.Administrator)]
public async Task WarnDelete(ulong userId, int index)
{
if (--index < 0)
return;
var warn = await _service.WarnDelete(userId, index);
if (warn is null)
{
await Response().Error(strs.warning_not_found).SendAsync();
return;
}
await Response().Confirm(strs.warning_deleted(Format.Bold(index.ToString()))).SendAsync();
}
[Cmd] [Cmd]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
[UserPerm(GuildPerm.BanMembers)] [UserPerm(GuildPerm.BanMembers)]
@ -286,6 +311,7 @@ public partial class Administration
{ {
if (index < 0) if (index < 0)
return; return;
var success = await _service.WarnClearAsync(ctx.Guild.Id, userId, index, ctx.User.ToString()); var success = await _service.WarnClearAsync(ctx.Guild.Id, userId, index, ctx.User.ToString());
var userStr = Format.Bold((ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()); var userStr = Format.Bold((ctx.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString());
if (index == 0) if (index == 0)

View file

@ -89,9 +89,10 @@ public class UserPunishService : IEService, IReadyExecutor
{ {
ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments; ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
previousCount = uow.Set<Warning>().ForId(guildId, userId) previousCount = uow.Set<Warning>()
.Where(w => !w.Forgiven && w.UserId == userId) .ForId(guildId, userId)
.Sum(x => x.Weight); .Where(w => !w.Forgiven && w.UserId == userId)
.Sum(x => x.Weight);
uow.Set<Warning>().Add(warn); uow.Set<Warning>().Add(warn);
@ -103,7 +104,7 @@ public class UserPunishService : IEService, IReadyExecutor
var totalCount = previousCount + weight; var totalCount = previousCount + weight;
var p = ps.Where(x => x.Count > previousCount && x.Count <= totalCount) var p = ps.Where(x => x.Count > previousCount && x.Count <= totalCount)
.MaxBy(x => x.Count); .MaxBy(x => x.Count);
if (p is not null) if (p is not null)
{ {
@ -244,33 +245,33 @@ public class UserPunishService : IEService, IReadyExecutor
{ {
await using var uow = _db.GetDbContext(); await using var uow = _db.GetDbContext();
var cleared = await uow.Set<Warning>() var cleared = await uow.Set<Warning>()
.Where(x => uow.Set<GuildConfig>() .Where(x => uow.Set<GuildConfig>()
.Any(y => y.GuildId == x.GuildId .Any(y => y.GuildId == x.GuildId
&& y.WarnExpireHours > 0 && y.WarnExpireHours > 0
&& y.WarnExpireAction == WarnExpireAction.Clear) && y.WarnExpireAction == WarnExpireAction.Clear)
&& x.Forgiven == false && x.Forgiven == false
&& x.DateAdded && x.DateAdded
< DateTime.UtcNow.AddHours(-uow.Set<GuildConfig>() < DateTime.UtcNow.AddHours(-uow.Set<GuildConfig>()
.Where(y => x.GuildId == y.GuildId) .Where(y => x.GuildId == y.GuildId)
.Select(y => y.WarnExpireHours) .Select(y => y.WarnExpireHours)
.First())) .First()))
.UpdateAsync(_ => new() .UpdateAsync(_ => new()
{ {
Forgiven = true, Forgiven = true,
ForgivenBy = "expiry" ForgivenBy = "expiry"
}); });
var deleted = await uow.Set<Warning>() var deleted = await uow.Set<Warning>()
.Where(x => uow.Set<GuildConfig>() .Where(x => uow.Set<GuildConfig>()
.Any(y => y.GuildId == x.GuildId .Any(y => y.GuildId == x.GuildId
&& y.WarnExpireHours > 0 && y.WarnExpireHours > 0
&& y.WarnExpireAction == WarnExpireAction.Delete) && y.WarnExpireAction == WarnExpireAction.Delete)
&& x.DateAdded && x.DateAdded
< DateTime.UtcNow.AddHours(-uow.Set<GuildConfig>() < DateTime.UtcNow.AddHours(-uow.Set<GuildConfig>()
.Where(y => x.GuildId == y.GuildId) .Where(y => x.GuildId == y.GuildId)
.Select(y => y.WarnExpireHours) .Select(y => y.WarnExpireHours)
.First())) .First()))
.DeleteAsync(); .DeleteAsync();
if (cleared > 0 || deleted > 0) if (cleared > 0 || deleted > 0)
{ {
@ -293,21 +294,21 @@ public class UserPunishService : IEService, IReadyExecutor
if (config.WarnExpireAction == WarnExpireAction.Clear) if (config.WarnExpireAction == WarnExpireAction.Clear)
{ {
await uow.Set<Warning>() await uow.Set<Warning>()
.Where(x => x.GuildId == guildId .Where(x => x.GuildId == guildId
&& x.Forgiven == false && x.Forgiven == false
&& x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours)) && x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours))
.UpdateAsync(_ => new() .UpdateAsync(_ => new()
{ {
Forgiven = true, Forgiven = true,
ForgivenBy = "expiry" ForgivenBy = "expiry"
}); });
} }
else if (config.WarnExpireAction == WarnExpireAction.Delete) else if (config.WarnExpireAction == WarnExpireAction.Delete)
{ {
await uow.Set<Warning>() await uow.Set<Warning>()
.Where(x => x.GuildId == guildId .Where(x => x.GuildId == guildId
&& x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours)) && x.DateAdded < DateTime.UtcNow.AddHours(-config.WarnExpireHours))
.DeleteAsync(); .DeleteAsync();
} }
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();
@ -425,8 +426,8 @@ public class UserPunishService : IEService, IReadyExecutor
{ {
using var uow = _db.GetDbContext(); using var uow = _db.GetDbContext();
return uow.GuildConfigsForId(guildId, gc => gc.Include(x => x.WarnPunishments)) return uow.GuildConfigsForId(guildId, gc => gc.Include(x => x.WarnPunishments))
.WarnPunishments.OrderBy(x => x.Count) .WarnPunishments.OrderBy(x => x.Count)
.ToArray(); .ToArray();
} }
public (IReadOnlyCollection<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill( public (IReadOnlyCollection<(string Original, ulong? Id, string Reason)> Bans, int Missing) MassKill(
@ -436,20 +437,20 @@ public class UserPunishService : IEService, IReadyExecutor
var gusers = guild.Users; var gusers = guild.Users;
//get user objects and reasons //get user objects and reasons
var bans = people.Split("\n") var bans = people.Split("\n")
.Select(x => .Select(x =>
{ {
var split = x.Trim().Split(" "); var split = x.Trim().Split(" ");
var reason = string.Join(" ", split.Skip(1)); var reason = string.Join(" ", split.Skip(1));
if (ulong.TryParse(split[0], out var id)) if (ulong.TryParse(split[0], out var id))
return (Original: split[0], Id: id, Reason: reason); return (Original: split[0], Id: id, Reason: reason);
return (Original: split[0], return (Original: split[0],
gusers.FirstOrDefault(u => u.ToString().ToLowerInvariant() == x)?.Id, gusers.FirstOrDefault(u => u.ToString().ToLowerInvariant() == x)?.Id,
Reason: reason); Reason: reason);
}) })
.ToArray(); .ToArray();
//if user is null, means that person couldn't be found //if user is null, means that person couldn't be found
var missing = bans.Count(x => !x.Id.HasValue); var missing = bans.Count(x => !x.Id.HasValue);
@ -483,11 +484,12 @@ public class UserPunishService : IEService, IReadyExecutor
} }
else if (template is null) else if (template is null)
{ {
uow.Set<BanTemplate>().Add(new() uow.Set<BanTemplate>()
{ .Add(new()
GuildId = guildId, {
Text = text GuildId = guildId,
}); Text = text
});
} }
else else
template.Text = text; template.Text = text;
@ -499,31 +501,31 @@ public class UserPunishService : IEService, IReadyExecutor
{ {
await using var ctx = _db.GetDbContext(); await using var ctx = _db.GetDbContext();
await ctx.Set<BanTemplate>() await ctx.Set<BanTemplate>()
.ToLinqToDBTable() .ToLinqToDBTable()
.InsertOrUpdateAsync(() => new() .InsertOrUpdateAsync(() => new()
{ {
GuildId = guildId, GuildId = guildId,
Text = null, Text = null,
DateAdded = DateTime.UtcNow, DateAdded = DateTime.UtcNow,
PruneDays = pruneDays PruneDays = pruneDays
}, },
old => new() old => new()
{ {
PruneDays = pruneDays PruneDays = pruneDays
}, },
() => new() () => new()
{ {
GuildId = guildId GuildId = guildId
}); });
} }
public async Task<int?> GetBanPruneAsync(ulong guildId) public async Task<int?> GetBanPruneAsync(ulong guildId)
{ {
await using var ctx = _db.GetDbContext(); await using var ctx = _db.GetDbContext();
return await ctx.Set<BanTemplate>() return await ctx.Set<BanTemplate>()
.Where(x => x.GuildId == guildId) .Where(x => x.GuildId == guildId)
.Select(x => x.PruneDays) .Select(x => x.PruneDays)
.FirstOrDefaultAsyncLinqToDB(); .FirstOrDefaultAsyncLinqToDB();
} }
public Task<SmartText> GetBanUserDmEmbed( public Task<SmartText> GetBanUserDmEmbed(
@ -554,18 +556,18 @@ public class UserPunishService : IEService, IReadyExecutor
banReason = string.IsNullOrWhiteSpace(banReason) ? "-" : banReason; banReason = string.IsNullOrWhiteSpace(banReason) ? "-" : banReason;
var repCtx = new ReplacementContext(client, guild) var repCtx = new ReplacementContext(client, guild)
.WithOverride("%ban.mod%", () => moderator.ToString()) .WithOverride("%ban.mod%", () => moderator.ToString())
.WithOverride("%ban.mod.fullname%", () => moderator.ToString()) .WithOverride("%ban.mod.fullname%", () => moderator.ToString())
.WithOverride("%ban.mod.name%", () => moderator.Username) .WithOverride("%ban.mod.name%", () => moderator.Username)
.WithOverride("%ban.mod.discrim%", () => moderator.Discriminator) .WithOverride("%ban.mod.discrim%", () => moderator.Discriminator)
.WithOverride("%ban.user%", () => target.ToString()) .WithOverride("%ban.user%", () => target.ToString())
.WithOverride("%ban.user.fullname%", () => target.ToString()) .WithOverride("%ban.user.fullname%", () => target.ToString())
.WithOverride("%ban.user.name%", () => target.Username) .WithOverride("%ban.user.name%", () => target.Username)
.WithOverride("%ban.user.discrim%", () => target.Discriminator) .WithOverride("%ban.user.discrim%", () => target.Discriminator)
.WithOverride("%reason%", () => banReason) .WithOverride("%reason%", () => banReason)
.WithOverride("%ban.reason%", () => banReason) .WithOverride("%ban.reason%", () => banReason)
.WithOverride("%ban.duration%", .WithOverride("%ban.duration%",
() => duration?.ToString(@"d\.hh\:mm") ?? "perma"); () => duration?.ToString(@"d\.hh\:mm") ?? "perma");
// if template isn't set, use the old message style // if template isn't set, use the old message style
@ -594,4 +596,24 @@ public class UserPunishService : IEService, IReadyExecutor
var output = SmartText.CreateFrom(template); var output = SmartText.CreateFrom(template);
return await _repSvc.ReplaceAsync(output, repCtx); return await _repSvc.ReplaceAsync(output, repCtx);
} }
public async Task<Warning> WarnDelete(ulong userId, int index)
{
await using var uow = _db.GetDbContext();
var warn = await uow.GetTable<Warning>()
.Where(x => x.UserId == userId)
.OrderByDescending(x => x.DateAdded)
.Skip(index)
.FirstOrDefaultAsyncLinqToDB();
if (warn is not null)
{
await uow.GetTable<Warning>()
.Where(x => x.Id == warn.Id)
.DeleteAsync();
}
return warn;
}
} }

View file

@ -947,6 +947,10 @@ warnexpire:
warnclear: warnclear:
- warnclear - warnclear
- warnc - warnc
warndelete:
- warndelete
- warnrm
- warnd
warnpunishlist: warnpunishlist:
- warnpunishlist - warnpunishlist
- warnpl - warnpl

View file

@ -576,7 +576,7 @@ deleterole:
- Awesome Role - Awesome Role
params: params:
- role: - role:
desc: "The role being deleted, as identified by its unique identifier." desc: "The role being deleted, as identified by its id."
rolecolor: rolecolor:
desc: Set a role's color using its hex value. Provide no color in order to see the hex value of the color of the specified role. The role you specify has to be lower in the role hierarchy than your highest role. desc: Set a role's color using its hex value. Provide no color in order to see the hex value of the color of the specified role. The role you specify has to be lower in the role hierarchy than your highest role.
ex: ex:
@ -605,11 +605,11 @@ ban:
- time: - time:
desc: "The duration of the temporary ban." desc: "The duration of the temporary ban."
userId: userId:
desc: "The unique identifier of the user being banned." desc: "The id of the user being banned."
msg: msg:
desc: "The reason for the ban is provided in this message." desc: "The reason for the ban is provided in this message."
- userId: - userId:
desc: "The unique identifier of the user being banned." desc: "The id of the user being banned."
msg: msg:
desc: "The reason for the ban is provided in this message." desc: "The reason for the ban is provided in this message."
- user: - user:
@ -627,7 +627,7 @@ softban:
msg: msg:
desc: "The reason for the ban is described in this string." desc: "The reason for the ban is described in this string."
- userId: - userId:
desc: "The unique identifier for the user being banned and then unbanned." desc: "The id of the user being banned and then unbanned."
msg: msg:
desc: "The reason for the ban is described in this string." desc: "The reason for the ban is described in this string."
kick: kick:
@ -1203,7 +1203,7 @@ userblacklist:
- action: - action:
desc: "The type of operation to perform on the user, either adding or removing them from the blacklist." desc: "The type of operation to perform on the user, either adding or removing them from the blacklist."
id: id:
desc: "The unique identifier of the user to be added, removed, or listed." desc: "The id of the user to be added, removed, or listed."
- action: - action:
desc: "The type of operation to perform on the user, either adding or removing them from the blacklist." desc: "The type of operation to perform on the user, either adding or removing them from the blacklist."
usr: usr:
@ -1223,7 +1223,7 @@ channelblacklist:
- action: - action:
desc: "The type of operation to perform on the channel, either adding it to the blacklist or removing it from it." desc: "The type of operation to perform on the channel, either adding it to the blacklist or removing it from it."
id: id:
desc: "The unique identifier of the channel being added, removed, or listed." desc: "The id of the channel being added, removed, or listed."
serverblacklist: serverblacklist:
desc: |- desc: |-
Either [add]s or [rem]oves a server, or servers specified by an ID from a blacklist. Either [add]s or [rem]oves a server, or servers specified by an ID from a blacklist.
@ -1239,7 +1239,7 @@ serverblacklist:
- action: - action:
desc: "The type of operation to perform on the server(s). It can be either adding or removing them from the blacklist." desc: "The type of operation to perform on the server(s). It can be either adding or removing them from the blacklist."
id: id:
desc: "The unique identifier of the server being added, removed, or listed." desc: "The id of the server being added, removed, or listed."
- action: - action:
desc: "The type of operation to perform on the server(s). It can be either adding or removing them from the blacklist." desc: "The type of operation to perform on the server(s). It can be either adding or removing them from the blacklist."
guild: guild:
@ -1296,7 +1296,7 @@ quoteshow:
- 123 - 123
params: params:
- quoteId: - quoteId:
desc: "The unique identifier for the quote being queried." desc: "The id of the quote being queried."
quotesearch: quotesearch:
desc: 'Shows a random quote given a search query. Partially matches in several ways: 1) Only content of any quote, 2) only by author, 3) keyword and content, 3) or keyword and author' desc: 'Shows a random quote given a search query. Partially matches in several ways: 1) Only content of any quote, 2) only by author, 3) keyword and content, 3) or keyword and author'
ex: ex:
@ -1317,14 +1317,14 @@ quoteid:
- 123456 - 123456
params: params:
- quoteId: - quoteId:
desc: "The unique identifier for the quote to be displayed." desc: "The id of the quote to be displayed."
quotedelete: quotedelete:
desc: Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it. desc: Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it.
ex: ex:
- 123456 - 123456
params: params:
- quoteId: - quoteId:
desc: "The unique identifier for the quote being deleted." desc: "The id of the quote being deleted."
quotedeleteauthor: quotedeleteauthor:
desc: Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required. desc: Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required.
ex: ex:
@ -1822,7 +1822,7 @@ load:
- 5 - 5
params: params:
- id: - id:
desc: "The unique identifier of the playlist to be loaded." desc: "The id of the playlist to be loaded."
playlists: playlists:
desc: Lists all playlists. Paginated, 20 per page. desc: Lists all playlists. Paginated, 20 per page.
ex: ex:
@ -1836,7 +1836,7 @@ playlistshow:
- 1 - 1
params: params:
- id: - id:
desc: "The unique identifier for the playlist to retrieve songs from." desc: "The id of the playlist to retrieve songs from."
page: page:
desc: "The current page number for the pagination." desc: "The current page number for the pagination."
deleteplaylist: deleteplaylist:
@ -2232,7 +2232,7 @@ currencytransaction:
- 3yvd - 3yvd
params: params:
- id: - id:
desc: "The unique identifier for the transaction being queried." desc: "The id of the transaction being queried."
listperms: listperms:
desc: Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. desc: Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions.
ex: ex:
@ -2721,6 +2721,7 @@ slot:
You can specify 'all', 'half' or 'X%' instead of the amount to bet that part of your current balance. You can specify 'all', 'half' or 'X%' instead of the amount to bet that part of your current balance.
ex: ex:
- 5 - 5
- 'all'
params: params:
- amount: - amount:
desc: "The amount of currency to bet." desc: "The amount of currency to bet."
@ -3177,6 +3178,13 @@ warnclear:
desc: "The ID of the user whose warnings are being cleared." desc: "The ID of the user whose warnings are being cleared."
index: index:
desc: "The index of the warning to be cleared, or 0 to clear all warnings." desc: "The index of the warning to be cleared, or 0 to clear all warnings."
warndelete:
desc: Deletes a warning from a user by its index.
ex:
- 3
params:
- index:
desc: "The index of the warning to be deleted."
warnpunishlist: warnpunishlist:
desc: Lists punishments for warnings. desc: Lists punishments for warnings.
ex: ex:
@ -3767,7 +3775,7 @@ expredit:
- 123 I'm a magical girl - 123 I'm a magical girl
params: params:
- id: - id:
desc: "The unique identifier for the expression being edited." desc: "The id of the expression being edited."
message: message:
desc: "The text that will replace the original response in the expression's output." desc: "The text that will replace the original response in the expression's output."
say: say:
@ -4080,7 +4088,7 @@ xpshopbuy:
- type: - type:
desc: "The type of item to purchase, such as a skill or a cosmetic." desc: "The type of item to purchase, such as a skill or a cosmetic."
key: key:
desc: "The unique identifier for the item being purchased." desc: "The id of the item being purchased."
xpshopuse: xpshopuse:
desc: Use a previously purchased item from the xp shop by specifying the type and the key of the item. desc: Use a previously purchased item from the xp shop by specifying the type and the key of the item.
ex: ex:
@ -4090,7 +4098,7 @@ xpshopuse:
- type: - type:
desc: "The type of item to be used, such as an experience point or a skill upgrade." desc: "The type of item to be used, such as an experience point or a skill upgrade."
key: key:
desc: "The unique identifier for the item in the XP shop that you want to use." desc: "The id of the item in the XP shop that you want to use."
bible: bible:
desc: Shows bible verse. You need to supply book name and chapter:verse desc: Shows bible verse. You need to supply book name and chapter:verse
ex: ex:
@ -4118,13 +4126,13 @@ edit:
- '#other-channel 771562360594628608 {{"description":"hello"}}' - '#other-channel 771562360594628608 {{"description":"hello"}}'
params: params:
- messageId: - messageId:
desc: "The unique identifier of the message being edited." desc: "The id of the message being edited."
text: text:
desc: "The new text content of the edited message." desc: "The new text content of the edited message."
- channel: - channel:
desc: "The target channel where the edited message will be sent or updated in." desc: "The target channel where the edited message will be sent or updated in."
messageId: messageId:
desc: "The unique identifier of the message being edited." desc: "The id of the message being edited."
text: text:
desc: "The new text content of the edited message." desc: "The new text content of the edited message."
delete: delete:
@ -4135,13 +4143,13 @@ delete:
- 771562360594628608 5m - 771562360594628608 5m
params: params:
- messageId: - messageId:
desc: "The unique identifier of a specific message within a channel, used to target the deletion operation." desc: "The id of a specific message within a channel, used to target the deletion operation."
time: time:
desc: "The duration after which the message should be automatically deleted." desc: "The duration after which the message should be automatically deleted."
- channel: - channel:
desc: "The channel where the message is located or should be searched for." desc: "The channel where the message is located or should be searched for."
messageId: messageId:
desc: "The unique identifier of a specific message within a channel, used to target the deletion operation." desc: "The id of a specific message within a channel, used to target the deletion operation."
time: time:
desc: "The duration after which the message should be automatically deleted." desc: "The duration after which the message should be automatically deleted."
roleid: roleid:
@ -4294,7 +4302,7 @@ banktake:
- amount: - amount:
desc: "The total value of funds being withdrawn." desc: "The total value of funds being withdrawn."
userId: userId:
desc: "The unique identifier for the user whose account is being accessed." desc: "The id of the user whose account is being accessed."
bankaward: bankaward:
desc: Award the specified amount of currency to a user's bank desc: Award the specified amount of currency to a user's bank
ex: ex:
@ -4485,7 +4493,7 @@ todoedit:
- abc This is an updated entry - abc This is an updated entry
params: params:
- todoId: - todoId:
desc: "The unique identifier for the todo item being edited." desc: "The id of the todo item being edited."
newMessage: newMessage:
desc: "The text of a new task description or update to an existing one." desc: "The text of a new task description or update to an existing one."
todocomplete: todocomplete:
@ -4494,14 +4502,14 @@ todocomplete:
- 4a - 4a
params: params:
- todoId: - todoId:
desc: "The unique identifier for the todo item being marked as completed." desc: "The id of the todo item being marked as completed."
tododelete: tododelete:
desc: Deletes a todo with the specified ID. desc: Deletes a todo with the specified ID.
ex: ex:
- abc - abc
params: params:
- todoId: - todoId:
desc: "The unique identifier for the todo item being deleted." desc: "The id of the todo item being deleted."
todoclear: todoclear:
desc: Deletes all unarchived todos. desc: Deletes all unarchived todos.
ex: ex:
@ -4535,7 +4543,7 @@ todoshow:
- 4a - 4a
params: params:
- todoId: - todoId:
desc: "The unique identifier for the todo item being displayed." desc: "The id of the todo item being displayed."
todoarchivedelete: todoarchivedelete:
desc: Deletes the archived todo list with the specified ID. desc: Deletes the archived todo list with the specified ID.
ex: ex:

View file

@ -702,6 +702,7 @@
"warn_count": "{0} current, {1} total", "warn_count": "{0} current, {1} total",
"warnlog_for": "Warnlog for {0}", "warnlog_for": "Warnlog for {0}",
"warnpl_none": "No punishments set.", "warnpl_none": "No punishments set.",
"warning_not_found": "Warning not found.",
"warn_expire_set_delete": "Warnings will be deleted after {0} days.", "warn_expire_set_delete": "Warnings will be deleted after {0} days.",
"warn_expire_set_clear": "Warnings will be cleared after {0} days.", "warn_expire_set_clear": "Warnings will be cleared after {0} days.",
"warn_expire_reset": "Warnings will no longer expire.", "warn_expire_reset": "Warnings will no longer expire.",
@ -712,6 +713,7 @@
"warn_punish_rem": "Having {0} warnings will no longer trigger a punishment.", "warn_punish_rem": "Having {0} warnings will no longer trigger a punishment.",
"warn_punish_set": "I will apply {0} punishment to users with {1} warnings.", "warn_punish_set": "I will apply {0} punishment to users with {1} warnings.",
"warn_punish_set_timed": "I will apply {0} punishment for {2} to users with {1} warnings.", "warn_punish_set_timed": "I will apply {0} punishment for {2} to users with {1} warnings.",
"warning_deleted": "Warning {0} has been deleted.",
"time_new": "Time", "time_new": "Time",
"timezone": "Timezone", "timezone": "Timezone",
"timezone_db_api_key": "You need to activate your TimezoneDB API key. You can do so by clicking on the link you've received in the email with your API key.", "timezone_db_api_key": "You need to activate your TimezoneDB API key. You can do so by clicking on the link you've received in the email with your API key.",