This commit is contained in:
2026-05-05 16:16:07 +01:00
parent 459973b40c
commit fd9c18d953
11 changed files with 504 additions and 10 deletions

View File

@@ -57,7 +57,7 @@ namespace SkyBot.Commands
builder.embed.HideChangePageArrows = true;
// Home page
builder.AddPage("✦ Help Menu", $"Prefix: {Config.Prefix}");
builder.AddPage("✦ Help Menu", $"Prefix: {Config.Prefix} | <> = required [] = optional");
builder.AddRow()
.AddText("Select a Category")
.WithStyles(EmbedStyles.LabelText)
@@ -77,15 +77,15 @@ namespace SkyBot.Commands
foreach (var (categoryName, cmds, chunkIndex, totalChunks) in allChunks)
{
string? footer = totalChunks > 1
? $"Page {chunkIndex + 1}/{totalChunks} | Prefix: {Config.Prefix}"
: $"Prefix: {Config.Prefix}";
? $"Page {chunkIndex + 1}/{totalChunks} | Prefix: {Config.Prefix} | <> = required [] = optional"
: $"Prefix: {Config.Prefix} | <> = required [] = optional";
builder.AddPage($"✦ {categoryName.ToTitleCase()} Commands", footer);
foreach (var cmd in cmds)
{
builder.AddRow()
.AddButton(cmd.Name)
.AddButton(cmd.Name.ToTitleCase())
.WithStyles(EmbedStyles.CommandBtn)
.OnClickGoToEmbedPage(cmdDetailPage[cmd.Name])
.CloseRow();
@@ -118,7 +118,7 @@ namespace SkyBot.Commands
// Command detail pages
foreach (var cmd in allCmds)
{
builder.AddPage($"✦ {cmd.Name.ToTitleCase()}", $"Prefix: {Config.Prefix}");
builder.AddPage($"✦ {cmd.Name.ToTitleCase()}", $"Prefix: {Config.Prefix} | <> = required [] = optional");
builder.AddRow()
.AddText("Description", cmd.Description)
@@ -141,7 +141,7 @@ namespace SkyBot.Commands
if (cmd.SubCommands.Length > 0)
{
builder.AddRow()
.AddText("Sub-commands", string.Join(", ", cmd.SubCommands.Select(s => s.ToTitleCase())))
.AddText("Sub-commands", string.Join(", ", cmd.SubCommands.Select(s => s)))
.CloseRow();
}

View File

@@ -0,0 +1,107 @@
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using SkyBot.Helpers;
using SkyBot.Models;
using Superpower.Model;
using Valour.Sdk.Models;
using Valour.Sdk.Models.Messages.Embeds;
using Valour.Sdk.Models.Messages.Embeds.Styles;
using Valour.Sdk.Models.Messages.Embeds.Styles.Basic;
using Valour.Sdk.Models.Messages.Embeds.Styles.Flex;
using Valour.Shared.Models;
namespace SkyBot.Commands
{
public class Info : ICommand
{
public string Name => "info";
public string[] Aliases => [];
public string Description => "Shows info about a Planet or User";
public string Category => "Info";
public string Usage => "info <sub> [user]";
public string[] SubCommands => ["planet", "user"];
public async Task Execute(CommandContext ctx)
{
if (ctx.Args.Length == 0)
{
await MessageHelper.ReplyAsync(ctx, "Please specify `planet` or `user`.");
return;
}
switch (ctx.Args[0].ToLower())
{
case "user":
case "u":
await HandleUserInfo(ctx);
break;
case "planet":
case "p":
await HandlePlanetInfo(ctx);
break;
default:
await MessageHelper.ReplyAsync(ctx, "Invalid Option. Use either `planet` or `user`.");
break;
}
}
private async Task HandleUserInfo(CommandContext ctx)
{
long memberId = ctx.Message.Mentions?.Any() == true
? ctx.Message.Mentions.First().TargetId
: long.TryParse(ctx.Args.ElementAtOrDefault(1), out var parsed)
? parsed
: ctx.Member.Id;
PlanetMember member = await ctx.Planet.FetchMemberAsync(memberId);
if (member is null)
{
await MessageHelper.ReplyAsync(ctx, "Could not find member.");
return;
}
var b = new EmbedBuilder()
.AddPage($"{member.Name.Trim()}'s Info")
.WithTitleStyles(new TextColor(member.PrimaryRole.Color))
// .AddMedia(MessageAttachmentType.Image, 64, 64, "image/webp", "avatar.webp", member.GetAvatar(AvatarFormat.Webp64))
// .WithStyles(
// new Position(right: new Size(Unit.Pixels, 8), top: new Size(Unit.Pixels, 8)),
// new Width(new Size(Unit.Pixels, 64)),
// new Height(new Size(Unit.Pixels, 64)),
// new BorderRadius(new Size(Unit.Percent, 50))
// )
.AddRow().AddText("Member ID", member.Id.ToString()).WithStyles(new TextColor("#ff9d00")).CloseRow()
.AddRow().AddText("User ID", member.UserId.ToString()).WithStyles(new TextColor("#ff9d00")).CloseRow()
.AddRow().AddText("Nickname", string.IsNullOrWhiteSpace(member.Nickname) ? "None" : member.Nickname).WithStyles(new TextColor(string.IsNullOrWhiteSpace(member.Nickname) ? "#ffed4a" : member.PrimaryRole.Color)).CloseRow()
.AddRow().AddText("Subscription", string.IsNullOrWhiteSpace(member.User.SubscriptionType) ? "None" : member.User.SubscriptionType).WithStyles(new TextColor(member.User.HasStargazer ? member.User.GetStarColor1() : "#ffed4a")).CloseRow()
.AddRow().AddText("Status", string.IsNullOrWhiteSpace(member.Status) ? "None" : member.Status).WithStyles(new TextColor("#ffed4a")).CloseRow()
.AddRow().AddText("Primary Role", member.PrimaryRole.Name).WithStyles(new TextColor(member.PrimaryRole.Color)).CloseRow()
.AddRow().AddText("Roles", string.Join(", ", member.Roles.Select(r => r.Name))).WithStyles(new TextColor(member.Roles[Random.Shared.Next(member.Roles.Count)].Color)).CloseRow()
.AddRow().AddText("Account Created", member.User.TimeJoined.ToString()).WithStyles(new TextColor("#979797")).CloseRow();
await MessageHelper.ReplyAsync(ctx, null, b.embed);
}
private async Task HandlePlanetInfo(CommandContext ctx)
{
PlanetMember pOwner = await ctx.Planet.FetchMemberByUserAsync(ctx.Planet.OwnerId);
EmbedBuilder b = new EmbedBuilder()
.AddPage($"{ctx.Planet.Name}'s Info")
.AddRow().AddText("Planet ID", ctx.Planet.Id.ToString()).CloseRow()
.AddRow().AddText("Planet Description", ctx.Planet.Description).CloseRow()
.AddRow().AddText("State", ctx.Planet.Public ? ctx.Planet.Discoverable ? "Public (Discoverable)" : "Public (Not Discoverable)" : "Private").CloseRow()
.AddRow().AddText("NSFW", ctx.Planet.Nsfw.ToString()).CloseRow()
.AddRow().AddText("Owner Name (ID)", $"{pOwner.Name} ({pOwner.Id})").CloseRow()
.AddRow().AddText("Members", ctx.Planet.Members.Count.ToString())
.AddText("Channels", ctx.Planet.Channels.Count.ToString())
.AddText("Roles", ctx.Planet.Roles.Count.ToString()).CloseRow()
;
await MessageHelper.ReplyAsync(ctx, null, b.embed);
}
}
}

View File

@@ -0,0 +1,53 @@
using SkyBot.Helpers;
using SkyBot.Models;
using Valour.Sdk.Models;
using Valour.Shared.Authorization;
namespace SkyBot.Commands
{
public class Ban : ICommand
{
public string Name => "ban";
public string[] Aliases => [];
public string Description => "Bans a member from the planet.";
public string Category => "Mod";
public string Usage => "ban <@member> [reason]";
public string[] SubCommands => [];
public async Task Execute(CommandContext ctx)
{
if (!await PermissionHelper.HasPermAsync(ctx.Member, [PlanetPermissions.Ban]))
{
await MessageHelper.ReplyAsync(ctx, $"You dont have permission to execute this command.");
return;
}
if (!await PermissionHelper.HasPermAsync(ctx.Planet.MyMember, [PlanetPermissions.Ban]))
{
await MessageHelper.ReplyAsync(ctx, $"I don't have permission to ban members.");
return;
}
if (ctx.Message.Mentions?.Any() != true && ctx.Args.Length < 1)
{
await MessageHelper.ReplyAsync(ctx, "Mention a member or enter their ID to ban them.");
return;
}
long? targetId = ctx.Message.Mentions?.Any() == true ? ctx.Message.Mentions.First().TargetId : long.TryParse(ctx.Args.ElementAtOrDefault(0), out long parsed) ? parsed : null;
if (targetId is null) {await MessageHelper.ReplyAsync(ctx, "Could not find user."); return;};
User victim = await ctx.Client.UserService.FetchUserAsync(targetId.Value);
if (victim is null) {await MessageHelper.ReplyAsync(ctx, "Could not find user."); return;};
DateTime? expires = ctx.Args.Select(MessageHelper.ParseDuration).FirstOrDefault(x => x != null);
string reason = string.Join(" ", ctx.Args.Skip(1).Where(a => MessageHelper.ParseDuration(a) is null));
if (string.IsNullOrWhiteSpace(reason)) reason = "No reason provided";
await ctx.Planet.BanAsync(victim.Id, reason, expires);
await MessageHelper.ReplyAsync(ctx, $"Banned {victim.NameAndTag}. Reason: `{reason}`. Expires: `{(expires.HasValue ? expires + " UTC" : "Never")}`");
}
}
}

View File

@@ -0,0 +1,83 @@
using System.Drawing;
using SkyBot.Helpers;
using SkyBot.Models;
using Valour.Sdk.Models;
using Valour.Sdk.Models.Messages.Embeds;
using Valour.Sdk.Models.Messages.Embeds.Styles.Basic;
using Valour.Shared.Authorization;
namespace SkyBot.Commands
{
public class Kick : ICommand
{
public string Name => "Kick";
public string[] Aliases => [];
public string Description => "Kicks a member from the planet.";
public string Category => "Mod";
public string Usage => "kick <@member> [reason]";
public string[] SubCommands => [];
public async Task Execute(CommandContext ctx)
{
if (!await PermissionHelper.HasPermAsync(ctx.Member, [PlanetPermissions.Kick]))
{
await MessageHelper.ReplyAsync(ctx, "You don't have permission to execute this command.");
return;
}
if (!await PermissionHelper.HasPermAsync(ctx.Planet.MyMember, [PlanetPermissions.Kick]))
{
await MessageHelper.ReplyAsync(ctx, "I don't have permission to kick members.");
return;
}
if (ctx.Message.Mentions?.Any() != true && ctx.Args.Length < 1)
{
await MessageHelper.ReplyAsync(ctx, "Mention a member or enter their ID to kick them.");
return;
}
long? targetId = ctx.Message.Mentions?.Any() == true ? ctx.Message.Mentions.First().TargetId : long.TryParse(ctx.Args.ElementAtOrDefault(0), out long parsed) ? parsed : null;
if (targetId is null) {await MessageHelper.ReplyAsync(ctx, "Could not find member."); return;};
PlanetMember offender = await ctx.Planet.FetchMemberAsync(targetId.Value);
if (offender is null) {await MessageHelper.ReplyAsync(ctx, "Could not find member."); return;};
string reason = string.Join(" ", ctx.Args.Skip(1));
if (string.IsNullOrWhiteSpace(reason)) reason = "No reason provided";
EmbedBuilder p = new EmbedBuilder()
.AddPage("Member Kick", DateTime.UtcNow.ToString())
.WithTitleStyles(new TextColor("#ff9900"))
.WithFooterStyles(new TextColor("#555555"))
.AddRow()
.AddText("Offender", offender.User.NameAndTag)
.WithStyles(new TextColor("#ff9900"))
.CloseRow()
.AddRow()
.AddText("Issuer", ctx.Member.User.NameAndTag)
.WithStyles(new TextColor("#ff9900"))
.CloseRow()
.AddText("Reason", reason)
.WithStyles(new TextColor("#ff9900"))
.CloseRow();
EmbedBuilder d = new EmbedBuilder()
.AddPage("Kicked from Planet", DateTime.UtcNow.ToString())
.WithTitleStyles(new TextColor("#ff9900"))
.WithFooterStyles(new TextColor("#555555"))
.AddRow()
.AddText("Planet (ID)", $"{ctx.Planet.Name} ({ctx.Planet.Id})")
.WithStyles(new TextColor("#ff9900"))
.CloseRow()
.AddRow()
.AddText("Reason", reason)
.WithStyles(new TextColor("#ff9900"))
.CloseRow();
await offender.User.SendDirectMessageAsync(ctx.Client, null, d.embed);
await offender.DeleteAsync();
await MessageHelper.ReplyAsync(ctx, null, p.embed);
}
};
}

163
SkyBot/Commands/RP/Emote.cs Normal file
View File

@@ -0,0 +1,163 @@
using System.Text.Json;
using SkyBot.Helpers;
using SkyBot.Models;
using Valour.Sdk.Models;
using Valour.Shared.Models;
namespace SkyBot.Commands
{
public class Emote : ICommand
{
public string Name => "emote";
public string[] Aliases => ["e", "action"];
public string Description => "RP emote actions.";
public string Category => "RP";
public string Usage => "emote <action> [@user]";
public string[] SubCommands => ["angry", "baka", "bite", "blowkiss", "blush", "bonk", "carry", "clap", "cry", "cuddle", "dance", "facepalm", "happy", "holdhand", "hug", "kiss", "laugh", "lurk", "nom", "nya", "pat", "poke", "pout", "punch", "run", "shocked", "sleep", "smug", "spin", "tableflip", "teehee", "tickle", "wave", "wink", "yawn"];
private static readonly HttpClient _http = new()
{
DefaultRequestHeaders = { { "User-Agent", "SkyBot/1.0 (https://skyjoshua.xyz, https://valour.gg)" } }
};
public async Task Execute(CommandContext ctx)
{
switch (ctx.Args.ElementAtOrDefault(0)?.ToLower())
{
case "angry": await SendAction(ctx, "angry", "{0} is angry at {1}! 😠", "{0} is angry! 😠", false); break;
case "baka": await SendAction(ctx, "baka", "{0} calls {1} a baka!", "Please mention someone who is a baka!", true); break;
case "bite": await SendAction(ctx, "bite", "{0} bites {1}!", "Please mention someone to bite!", true); break;
case "blowkiss": await SendAction(ctx, "blowkiss", "{0} blows a kiss to {1}!", "Please mention someone to blow a kiss too!", true); break;
case "blush": await SendAction(ctx, "blush", "{0} is blushing at {1}!", "{0} is blushing!", false); break;
case "bonk": await SendAction(ctx, "bonk", "{0} bonks {1}!", "Please mention someone to bonk!", true); break;
case "carry": await SendAction(ctx, "carry", "{0} carries {1}!", "Please mention someone to carry!", true); break;
case "clap": await SendAction(ctx, "clap", "{0} claps for {1}!", "{0} is clapping!", false); break;
case "cry": await SendAction(ctx, "cry", "{0} is crying because of {1}!", "{0} is crying!", false); break;
case "cuddle": await SendAction(ctx, "cuddle", "{0} cuddles with {1}!", "Please mention someone to cuddle!", true); break;
case "dance": await SendAction(ctx, "dance", "{0} dances with {1}!", "{0} is dancing!", false); break;
case "facepalm": await SendAction(ctx, "facepalm", "{0} facepalms at {1}!", "{0} facepalms!", false); break;
case "happy": await SendAction(ctx, "happy", "{0} is happy with {1}!", "{0} is happy!", false); break;
case "holdhand": await SendAction(ctx, "handhold", "{0} holds hands with {1}!", "Please mention someone to hold hands with!", true); break;
case "hug": await SendAction(ctx, "hug", "{0} hugs {1}!", "Please mention someone to hug!", true); break;
case "kiss": await SendAction(ctx, "kiss", "{0} kisses {1}!", "Please mention someone to kiss!", true); break;
case "laugh": await SendAction(ctx, "laugh", "{0} laughs at {1}!", "{0} is laughing!", false); break;
case "lurk": await SendAction(ctx, "lurk", "{0} lurks around {1}!", "{0} is lurking!", false); break;
case "nom": await SendAction(ctx, "nom", "{0} noms on {1}!", "{0} is nomming!", false); break;
case "nya": await SendAction(ctx, "nya", "{0} nyas at {1}!", "{0} nyas!", false); break;
case "pat": await SendAction(ctx, "pat", "{0} gives {1} headpats!", "Please mention someone to give heatpats too!", true); break;
case "poke": await SendAction(ctx, "poke", "{0} pokes {1}!", "Please mention someone to poke!", true); break;
case "pout": await SendAction(ctx, "pout", "{0} pouts at {1}!", "{0} is pouting!", false); break;
case "punch": await SendAction(ctx, "punch", "{0} punches {1}!", "Please mention someone to punch!", true); break;
case "run": await SendAction(ctx, "run", "{0} runs away from {1}!", "{0} runs away!", false); break;
case "shocked": await SendAction(ctx, "shocked", "{0} is shocked by {1}!", "{0} is shocked!", false); break;
case "sleep": await SendAction(ctx, "sleep", "{0} falls asleep on {1}!", "{0} is sleeping! zzz...", false); break;
case "smug": await SendAction(ctx, "smug", "{0} looks smug at {1}!", "{0} is feeling smug!", false); break;
case "spin": await SendAction(ctx, "spin", "{0} spins {1} around!", "{0} is spinning!", false); break;
case "tableflip": await SendAction(ctx, "tableflip", "{0} flips the table at {1}! (╯°□°)╯︵ ┻━┻", "{0} flips the table! (╯°□°)╯︵ ┻━┻", false); break;
case "teehee": await SendAction(ctx, "teehee", "{0} teehees at {1}!", "{0} teehees~", false); break;
case "tickle": await SendAction(ctx, "tickle", "{0} tickles {1}!", "Please mention someone to tickle!", true); break;
case "wave": await SendAction(ctx, "wave", "{0} waves at {1}!", "{0} waves!", false); break;
case "wink": await SendAction(ctx, "wink", "{0} winks at {1}! ;)", "{0} winks! ;)", false); break;
case "yawn": await SendAction(ctx, "yawn", "{0} yawns at {1}!", "{0} is yawning!", false); break;
default:
await MessageHelper.ReplyAsync(ctx, $"Unknown emote. Usage: `{Config.Prefix}emote <action>`\nActions: {string.Join(", ", SubCommands)}");
break;
}
}
private static async Task SendAction(CommandContext ctx, string apiAction, string withTarget, string withoutTarget, bool requiresTarget = false)
{
string? target = null;
if (ctx.Message.ReplyToId is not null)
{
var replied = await ctx.Message.FetchReplyMessageAsync();
if (replied is not null)
{
var author = await replied.FetchAuthorAsync();
if (author is not null)
target = author.Name;
}
}
if (target is null && ctx.Args.Length > 1)
target = string.Join(" ", ctx.Args[1..]);
if (requiresTarget && target is null)
{
await MessageHelper.ReplyAsync(ctx, withoutTarget);
return;
}
await ctx.Channel.SendIsTyping();
string json;
try
{
json = await _http.GetStringAsync($"https://nekos.best/api/v2/{apiAction}");
}
catch
{
await MessageHelper.ReplyAsync(ctx, $"Could not fetch a {apiAction} gif. Try again later.");
return;
}
using var doc = JsonDocument.Parse(json);
string gifUrl = doc.RootElement.GetProperty("results")[0].GetProperty("url").GetString()!;
byte[] gifBytes;
try
{
gifBytes = await _http.GetByteArrayAsync(gifUrl);
}
catch
{
await MessageHelper.ReplyAsync(ctx, $"Could not download the {apiAction} gif. Try again later.");
return;
}
int width = 0, height = 0;
if (gifBytes.Length >= 10)
{
width = gifBytes[6] | (gifBytes[7] << 8);
height = gifBytes[8] | (gifBytes[9] << 8);
}
string cdnUrl;
try
{
using var form = new MultipartFormDataContent();
using var fileContent = new ByteArrayContent(gifBytes);
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/gif");
form.Add(fileContent, "file", $"{apiAction}.gif");
var uploadResult = await ctx.Planet.Node.PostMultipartDataWithResponse<string>("upload/image", form);
if (!uploadResult.Success)
{
await MessageHelper.ReplyAsync(ctx, $"Could not upload the {apiAction} gif. Try again later.");
return;
}
cdnUrl = uploadResult.Data!;
}
catch
{
await MessageHelper.ReplyAsync(ctx, $"Could not upload the {apiAction} gif. Try again later.");
return;
}
string sender = ctx.Member.Nickname ?? ctx.Member.User?.Name ?? "Unknown";
string text = target is not null
? string.Format(withTarget, sender, target)
: string.Format(withoutTarget, sender);
var attachment = new MessageAttachment(MessageAttachmentType.Image)
{
Location = cdnUrl,
MimeType = "image/gif",
FileName = $"{apiAction}.gif",
Width = width,
Height = height
};
await MessageHelper.ReplyAsync(ctx, text, attachments: [attachment]);
}
}
}

View File

@@ -9,7 +9,7 @@ namespace SkyBot.Commands
public string[] Aliases => ["marry"];
public string Description => "Marriage system — propose, check status, or divorce.";
public string Category => "RP";
public string Usage => "marriage <sub>";
public string Usage => "marriage <action>";
public string[] SubCommands => ["propose", "status", "divorce", "force"];
public async Task Execute(CommandContext ctx)
@@ -130,7 +130,7 @@ namespace SkyBot.Commands
long partnerId = marriage.SpouseId;
DateTimeOffset dt = DateTimeOffset.FromUnixTimeMilliseconds(marriage.MarriedAt);
string marriedAt = $"{dt.OrdinalDay()} {dt:MMMM yyyy HH:mm} UTC";
await MessageHelper.ReplyAsync(ctx, $"{name} is married to «@u-{partnerId}»!\nThey got married: {marriedAt}");
await MessageHelper.ReplyAsync(ctx, $"{name} is married to «@u-{partnerId}»!\nThey got married: `{marriedAt}`");
}
}

View File

@@ -10,6 +10,7 @@ namespace SkyBot.Helpers
private static readonly Size PadH = new(Unit.Pixels, 6);
private static readonly Size FitContent = new(Unit.FitContent);
public static StyleBase[] LabelText => [
new TextColor("#a0a0b8"),
new FontWeight(600),

View File

@@ -28,7 +28,7 @@ namespace SkyBot.Helpers
return $"{dt.Day}{suffix}";
}
public static async Task<TaskResult<Message>> ReplyAsync(CommandContext ctx, string? content, Embed? embed = null, bool reply = false)
public static async Task<TaskResult<Message>> ReplyAsync(CommandContext ctx, string? content, Embed? embed = null, bool reply = false, IEnumerable<MessageAttachment>? attachments = null)
{
long? replyToId = reply ? ctx.Message.ReplyToId : ctx.Message.Id;
@@ -46,6 +46,12 @@ namespace SkyBot.Helpers
if (embed is not null)
msg.SetEmbed(embed);
if (attachments is not null)
{
msg.Attachments ??= [];
msg.Attachments.AddRange(attachments);
}
return await ctx.Client.MessageService.SendMessage(msg);
}
@@ -56,5 +62,24 @@ namespace SkyBot.Helpers
return await channel.Planet.Node.PutAsyncWithResponse<Message>($"api/messages/{message.Id}", message);
}
public static DateTime? ParseDuration(string input)
{
if (string.IsNullOrWhiteSpace(input)) return null;
var unit = input[^1];
if (!int.TryParse(input[..^1], out int value)) return null;
return unit switch
{
'm' => DateTime.UtcNow.AddMinutes(value),
'h' => DateTime.UtcNow.AddHours(value),
'd' => DateTime.UtcNow.AddDays(value),
'w' => DateTime.UtcNow.AddDays(value * 7),
'M' => DateTime.UtcNow.AddMonths(value),
'y' => DateTime.UtcNow.AddYears(value),
_ => null
};
}
};
};

View File

@@ -0,0 +1,33 @@
using Valour.Sdk.Models;
using Valour.Shared;
namespace SkyBot.Helpers
{
public static class PlanetHelper
{
public static Task<TaskResult<PlanetBan>> BanAsync(this Planet planet, long targetUserId, string reason, DateTime? expires = null)
{
var ban = new PlanetBan(planet.Client)
{
PlanetId = planet.Id,
IssuerId = planet.Client.Me.Id,
TargetId = targetUserId,
Reason = reason,
TimeCreated = DateTime.UtcNow,
TimeExpires = expires
};
return ban.CreateAsync();
}
public static async Task<PlanetBan?> FindBanAsync(this Planet planet, long targetUserId)
{
var engine = planet.GetBanQueryEngine();
await foreach (var ban in engine)
{
if (ban.TargetId == targetUserId)
return ban;
}
return null;
}
}
}

View File

@@ -0,0 +1,29 @@
using SkyBot.Models;
using Valour.Sdk.Client;
using Valour.Sdk.Models;
using Valour.Sdk.Models.Messages.Embeds;
using Valour.Shared;
namespace SkyBot.Helpers
{
public static class UserHelper
{
public static async Task<TaskResult<Message>> SendDirectMessageAsync(this User user, ValourClient client, string? content, Embed? embed = null)
{
var channelResult = await client.PrimaryNode.GetJsonAsync<Channel>($"api/channels/direct/byUser/{user.Id}");
if (!channelResult.Success)
return new TaskResult<Message>(false, "Could not open DM channel.");
var msg = new Message(client)
{
Content = content,
ChannelId = channelResult.Data.Id,
AuthorUserId = client.Me.Id,
Fingerprint = Guid.NewGuid().ToString()
};
msg.SetEmbed(embed);
return await client.MessageService.SendMessage(msg);
}
}
}

View File

@@ -5,7 +5,7 @@
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>0.3.2.0</Version>
<Version>0.3.3.0</Version>
</PropertyGroup>
<ItemGroup>