@@ -1,17 +1,15 @@
using Discord ;
using Discord.Interactions ;
using LightlessSync.API.Data.Enum ;
using LightlessSync.API.Dto.Group ;
using LightlessSync.API.Dto.User ;
using LightlessSyncShared.Data ;
using LightlessSyncShared.Models ;
using LightlessSyncShared.Services ;
using LightlessSyncShared.Utils ;
using LightlessSyncShared.Utils.Configuration ;
using Microsoft.EntityFrameworkCore ;
using Prometheus ;
using LightlessSyncShared.Models ;
using LightlessSyncShared.Utils ;
using LightlessSyncShared.Services ;
using StackExchange.Redis ;
using System.Net.Http.Json ;
using LightlessSync.API.Data.Enum ;
using LightlessSyncShared.Utils.Configuration ;
using LightlessSync.API.Dto.User ;
namespace LightlessSyncServices.Discord ;
@@ -45,56 +43,7 @@ public class LightlessModule : InteractionModuleBase
{
EmbedBuilder eb = new ( ) ;
using var scope = _services . CreateScope ( ) ;
var db = scope . ServiceProvider . GetRequiredService < LightlessDbContext > ( ) ;
await using ( db . ConfigureAwait ( false ) )
{
eb = await HandleUserInfo ( eb , db , Context . User . Id , secondaryUid , discordUser ? . Id ? ? null , uid ) ;
string uidToGet = await GetUserUID ( db , secondaryUid , discordUser ? . Id ? ? null , uid ) . ConfigureAwait ( false ) ;
var profileData = await GetUserProfileData ( db , uidToGet ) . ConfigureAwait ( false ) ;
if ( profileData ! = null )
{
byte [ ] profileImage = GetProfileImage ( profileData ) ;
byte [ ] bannerImage = GetBannerImage ( profileData ) ;
using MemoryStream profileImgStream = new ( profileImage ) ;
using MemoryStream bannerImgStream = new ( bannerImage ) ;
eb . WithThumbnailUrl ( "attachment://profileimage.png" ) ;
eb . WithImageUrl ( "attachment://bannerimage.png" ) ;
await RespondWithFilesAsync (
new [ ] { new FileAttachment ( profileImgStream , "profileimage.png" ) , new FileAttachment ( bannerImgStream , "bannerimage.png" ) } ,
embeds : new [ ] { eb . Build ( ) } ,
ephemeral : true ) . ConfigureAwait ( false ) ;
}
else
{
await RespondAsync (
embeds : new [ ] { eb . Build ( ) } ,
ephemeral : true ) . ConfigureAwait ( false ) ;
}
}
}
catch ( Exception ex )
{
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( "An error occured" ) ;
eb . WithDescription ( "Please report this error to bug-reports: " + Environment . NewLine + ex . Message + Environment . NewLine + ex . StackTrace + Environment . NewLine ) ;
await RespondAsync ( embeds : new Embed [ ] { eb . Build ( ) } , ephemeral : true ) . ConfigureAwait ( false ) ;
}
}
[SlashCommand("groupinfo", "Shows you your group profile information")]
public async Task GroupInfo ( [ Summary ( "gid" , "ADMIN ONLY: GID to check for" ) ] string? uid = null )
{
_logger . LogInformation ( "SlashCommand:{userId}:{Method}" ,
Context . Interaction . User . Id , nameof ( GroupInfo ) ) ;
try
{
EmbedBuilder eb = new ( ) ;
//eb = await HandleUserInfo(eb, Context.User.Id, secondaryUid, discordUser?.Id ?? null, uid);
eb = await HandleUserInfo ( eb , Context . User . Id , secondaryUid , discordUser ? . Id ? ? null , uid ) ;
await RespondAsync ( embeds : new [ ] { eb . Build ( ) } , ephemeral : true ) . ConfigureAwait ( false ) ;
}
@@ -161,10 +110,10 @@ public class LightlessModule : InteractionModuleBase
var testUri = new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , "/msgc/sendMessage" ) ;
using ( await c . PostAsJsonAsync (
await c . PostAsJsonAsync (
new Uri ( _lightlessServicesConfiguration . GetValue < Uri > ( nameof ( ServicesConfiguration . MainServerAddress ) ) , "/msgc/sendMessage" ) ,
new ClientMessage ( messageType , message , uid ? ? string . Empty )
) . ConfigureAwait ( false ) ) { }
) . ConfigureAwait ( false ) ;
var discordChannelForMessages = _lightlessServicesConfiguration . GetValueOrDefault < ulong? > ( nameof ( ServicesConfiguration . DiscordChannelForMessages ) , null ) ;
if ( uid = = null & & discordChannelForMessages ! = null )
@@ -197,47 +146,20 @@ public class LightlessModule : InteractionModuleBase
}
}
[SlashCommand("serviceunban ", "ADMIN ONLY: Unban a user by their discord ID or user ID [CHOOSE ONE ONLY] ")]
public async Task ServiceU nban(
[Summary("discord_id", "Discord ID to unban")] string? discordId = null ,
[Summary("uid", "UID to unban")] string? uid = null
)
[SlashCommand("unbanbydiscord ", "ADMIN ONLY: Unban a user by their discord ID")]
public async Task UnbanByDiscord ( [ Summary ( "discord_id" , "Discord ID to u nban" ) ] string discordId )
{
_logger . LogInformation ( "SlashCommand:{userId}:{Method}:{params}" ,
Context . Interaction . User . Id , nameof ( ServiceUnban ) ,
string . Join ( "," , new [ ] { $"{nameof(discordId)}:{discordId}" , $"{nameof(uid)}:{uid}" } ) ) ;
Context . Interaction . User . Id , nameof ( UnbanByDiscord ) ,
string . Join ( "," , new [ ] { $"{nameof(discordId)}:{discordId}" } ) ) ;
try
{
using HttpClient c = new HttpClient ( ) ;
c . DefaultRequestHeaders . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , _serverTokenGenerator . Token ) ;
string endpoint ;
UnbanRequest unbanRequest ;
if ( ! string . IsNullOrEmpty ( uid ) )
{
endpoint = "/user/unbanUID" ;
unbanRequest = new UnbanRequest ( uid , string . Empty ) ;
}
else if ( ! string . IsNullOrEmpty ( discordId ) )
{
endpoint = "/user/unbanDiscord" ;
unbanRequest = new UnbanRequest ( string . Empty , discordId ) ;
}
else
{
await RespondAsync ( "You must provide either a UID or Discord ID." , ephemeral : true ) . ConfigureAwait ( false ) ;
return ;
}
using ( await c . PostAsJsonAsync (
new Uri ( _lightlessServicesConfiguration . GetValue < Uri > ( nameof ( ServicesConfiguration . MainServerAddress ) ) , endpoint ) ,
unbanRequest ) . ConfigureAwait ( false ) )
{
}
await c . PostAsJsonAsync ( new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , "/user/unbanDiscord" ) , new UnbanRequest ( string . Empty , discordId ) )
. ConfigureAwait ( false ) ;
var discordChannelForMessages = _lightlessServicesConfiguration . GetValueOrDefault < ulong? > ( nameof ( ServicesConfiguration . DiscordChannelForMessages ) , null ) ;
if ( discordChannelForMessages ! = null )
{
@@ -246,12 +168,10 @@ public class LightlessModule : InteractionModuleBase
{
var embedColor = Color . Blue ;
String idToUse = ! string . IsNullOrEmpty ( uid ) ? uid : discordId ;
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( "Unban Alert!" ) ;
eb . WithColor ( embedColor ) ;
eb . WithDescription ( idToUse + " has been unbanned" ) ;
eb . WithDescription ( discordId + " has been unbanned" ) ;
await discordChannel . SendMessageAsync ( embed : eb . Build ( ) ) . ConfigureAwait ( false ) ;
}
@@ -268,20 +188,64 @@ public class LightlessModule : InteractionModuleBase
}
}
[SlashCommand("serviceban ", "ADMIN ONLY: ban a user by their uid")]
public async Task ServiceBan ( [ Summary ( "uid" , "uid to ban" ) ] string uid )
[SlashCommand("unbanbyuid ", "ADMIN ONLY: Un ban a user by their uid")]
public async Task UnbanByUID ( [ Summary ( "uid" , "uid to un ban" ) ] string uid )
{
_logger . LogInformation ( "SlashCommand:{userId}:{Method}:{params}" ,
Context . Interaction . User . Id , nameof ( ServiceBan ) ,
Context . Interaction . User . Id , nameof ( UnbanByUID ) ,
string . Join ( "," , new [ ] { $"{nameof(uid)}:{uid}" } ) ) ;
try
{
using HttpClient c = new HttpClient ( ) ;
var testUri = new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , "/user/unbanDiscord" ) ;
c . DefaultRequestHeaders . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , _serverTokenGenerator . Token ) ;
await c . PostAsJsonAsync ( new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , "/user/unbanUID" ) , new UnbanRequest ( uid , string . Empty ) )
. ConfigureAwait ( false ) ;
var discordChannelForMessages = _lightlessServicesConfiguration . GetValueOrDefault < ulong? > ( nameof ( ServicesConfiguration . DiscordChannelForMessages ) , null ) ;
if ( discordChannelForMessages ! = null )
{
var discordChannel = await Context . Guild . GetChannelAsync ( discordChannelForMessages . Value ) . ConfigureAwait ( false ) as IMessageChannel ;
if ( discordChannel ! = null )
{
var embedColor = Color . Blue ;
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( "Unban Alert!" ) ;
eb . WithColor ( embedColor ) ;
eb . WithDescription ( uid + " has been unbanned" ) ;
await discordChannel . SendMessageAsync ( embed : eb . Build ( ) ) . ConfigureAwait ( false ) ;
}
}
await RespondAsync ( "Message sent" , ephemeral : true ) . ConfigureAwait ( false ) ;
}
catch ( Exception ex )
{
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( "An error occured" ) ;
eb . WithDescription ( "Please report this: " + Environment . NewLine + ex . Message + Environment . NewLine + ex . StackTrace + Environment . NewLine ) ;
await RespondAsync ( embeds : new Embed [ ] { eb . Build ( ) } , ephemeral : true ) . ConfigureAwait ( false ) ;
}
}
[SlashCommand("markforban", "ADMIN ONLY: ban a user by their uid")]
public async Task MarkUidForBan ( [ Summary ( "uid" , "uid to ban" ) ] string uid )
{
_logger . LogInformation ( "SlashCommand:{userId}:{Method}:{params}" ,
Context . Interaction . User . Id , nameof ( MarkUidForBan ) ,
string . Join ( "," , new [ ] { $"{nameof(uid)}:{uid}" } ) ) ;
try
{
using HttpClient c = new HttpClient ( ) ;
c . DefaultRequestHeaders . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , _serverTokenGenerator . Token ) ;
using ( await c . PostAsJsonAsync ( new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
await c . PostAsJsonAsync ( new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , "/user/ban" ) , new BanRequest ( uid ) )
. ConfigureAwait ( false ) ) { }
. ConfigureAwait ( false ) ;
var discordChannelForMessages = _lightlessServicesConfiguration . GetValueOrDefault < ulong? > ( nameof ( ServicesConfiguration . DiscordChannelForMessages ) , null ) ;
if ( discordChannelForMessages ! = null )
{
@@ -310,100 +274,6 @@ public class LightlessModule : InteractionModuleBase
}
}
[SlashCommand("toggleuserprofile", "ADMIN ONLY: disable a user profile by their uid")]
public async Task ToggleUserProfile (
[Summary("uid", "uid to disable")] string uid ,
[Summary("toggle", "Enable or Disable the profile")]
[Choice("Enable", "Enable")]
[Choice("Disable", "Disable")] string toggle
)
{
_logger . LogInformation ( "SlashCommand:{userId}:{Method}:{params}" ,
Context . Interaction . User . Id , nameof ( ToggleUserProfile ) ,
string . Join ( "," , new [ ] { $"{nameof(uid)}:{uid}" } ) ) ;
try
{
using HttpClient c = new HttpClient ( ) ;
c . DefaultRequestHeaders . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , _serverTokenGenerator . Token ) ;
string endpoint = string . Equals ( toggle , "Enable" , StringComparison . Ordinal ) ? "/user/enableProfile" : "/user/disableProfile" ;
using ( await c . PostAsJsonAsync ( new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , endpoint ) , new UserProfileAvailabilityRequest ( uid ) )
. ConfigureAwait ( false ) ) { }
var discordChannelForMessages = _lightlessServicesConfiguration . GetValueOrDefault < ulong? > ( nameof ( ServicesConfiguration . DiscordChannelForMessages ) , null ) ;
if ( discordChannelForMessages ! = null )
{
var discordChannel = await Context . Guild . GetChannelAsync ( discordChannelForMessages . Value ) . ConfigureAwait ( false ) as IMessageChannel ;
if ( discordChannel ! = null )
{
var embedColor = Color . Blue ;
var action = string . Equals ( toggle , "Enable" , StringComparison . Ordinal ) ? "enabled" : "disabled" ;
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( $"Profile {action}" ) ;
eb . WithColor ( embedColor ) ;
eb . WithDescription ( $"{uid}'s profile has been {action}" ) ;
await discordChannel . SendMessageAsync ( embed : eb . Build ( ) ) . ConfigureAwait ( false ) ;
}
}
await RespondAsync ( "Message sent" , ephemeral : true ) . ConfigureAwait ( false ) ;
}
catch ( Exception ex )
{
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( "An error occured" ) ;
eb . WithDescription ( "Please report this: " + Environment . NewLine + ex . Message + Environment . NewLine + ex . StackTrace + Environment . NewLine ) ;
await RespondAsync ( embeds : new Embed [ ] { eb . Build ( ) } , ephemeral : true ) . ConfigureAwait ( false ) ;
}
}
[SlashCommand("togglegroupprofile", "ADMIN ONLY: toggle a group profile by their gid")]
public async Task ToggleGroupProfile (
[Summary("gid", "gid to disable")] string gid ,
[Summary("toggle", "Enable or Disable the profile")]
[Choice("Enable", "Enable")]
[Choice("Disable", "Disable")] string toggle
)
{
_logger . LogInformation ( "SlashCommand:{userId}:{Method}:{params}" ,
Context . Interaction . User . Id , nameof ( ToggleUserProfile ) ,
string . Join ( "," , new [ ] { $"{nameof(gid)}:{gid}" } ) ) ;
try
{
using HttpClient c = new HttpClient ( ) ;
c . DefaultRequestHeaders . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , _serverTokenGenerator . Token ) ;
string endpoint = string . Equals ( toggle , "Enable" , StringComparison . Ordinal ) ? "/group/enableProfile" : "/group/disableProfile" ;
using ( await c . PostAsJsonAsync ( new Uri ( _lightlessServicesConfiguration . GetValue < Uri >
( nameof ( ServicesConfiguration . MainServerAddress ) ) , endpoint ) , new GroupProfileAvailabilityRequest ( gid ) )
. ConfigureAwait ( false ) ) { }
var discordChannelForMessages = _lightlessServicesConfiguration . GetValueOrDefault < ulong? > ( nameof ( ServicesConfiguration . DiscordChannelForMessages ) , null ) ;
if ( discordChannelForMessages ! = null )
{
var discordChannel = await Context . Guild . GetChannelAsync ( discordChannelForMessages . Value ) . ConfigureAwait ( false ) as IMessageChannel ;
if ( discordChannel ! = null )
{
var embedColor = Color . Blue ;
var action = string . Equals ( toggle , "Enable" , StringComparison . Ordinal ) ? "enabled" : "disabled" ;
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( $"Profile {action}" ) ;
eb . WithColor ( embedColor ) ;
eb . WithDescription ( $"{gid}'s profile has been {action}" ) ;
await discordChannel . SendMessageAsync ( embed : eb . Build ( ) ) . ConfigureAwait ( false ) ;
}
}
await RespondAsync ( "Message sent" , ephemeral : true ) . ConfigureAwait ( false ) ;
}
catch ( Exception ex )
{
EmbedBuilder eb = new ( ) ;
eb . WithTitle ( "An error occured" ) ;
eb . WithDescription ( "Please report this: " + Environment . NewLine + ex . Message + Environment . NewLine + ex . StackTrace + Environment . NewLine ) ;
await RespondAsync ( embeds : new Embed [ ] { eb . Build ( ) } , ephemeral : true ) . ConfigureAwait ( false ) ;
}
}
public async Task < Embed > HandleUserAdd ( string desiredUid , ulong discordUserId )
{
var embed = new EmbedBuilder ( ) ;
@@ -449,9 +319,11 @@ public class LightlessModule : InteractionModuleBase
return embed . Build ( ) ;
}
private async Task < EmbedBuilder > HandleUserInfo ( EmbedBuilder eb , LightlessDbContext db , ulong id , string? secondaryUserUid = null , ulong? optionalUser = null , string? uid = null )
private async Task < EmbedBuilder > HandleUserInfo ( EmbedBuilder eb , ulong id , string? secondaryUserUid = null , ulong? optionalUser = null , string? uid = null )
{
bool showForSecondaryUser = secondaryUserUid ! = null ;
using var scope = _services . CreateScope ( ) ;
await using var db = scope . ServiceProvider . GetRequiredService < LightlessDbContext > ( ) ;
var primaryUser = await db . LodeStoneAuth . Include ( u = > u . User ) . SingleOrDefaultAsync ( u = > u . DiscordId = = id ) . ConfigureAwait ( false ) ;
@@ -510,7 +382,6 @@ public class LightlessModule : InteractionModuleBase
var auth = await db . Auth . Include ( u = > u . PrimaryUser ) . SingleOrDefaultAsync ( u = > u . UserUID = = dbUser . UID ) . ConfigureAwait ( false ) ;
var groups = await db . Groups . Where ( g = > g . OwnerUID = = dbUser . UID ) . ToListAsync ( ) . ConfigureAwait ( false ) ;
var groupsJoined = await db . GroupPairs . Where ( g = > g . GroupUserUID = = dbUser . UID ) . ToListAsync ( ) . ConfigureAwait ( false ) ;
var profile = await db . UserProfileData . Where ( u = > u . UserUID = = dbUser . UID ) . SingleOrDefaultAsync ( ) . ConfigureAwait ( false ) ;
var identity = await _connectionMultiplexer . GetDatabase ( ) . StringGetAsync ( "UID:" + dbUser . UID ) . ConfigureAwait ( false ) ;
eb . WithTitle ( "User Information" ) ;
@@ -533,14 +404,6 @@ public class LightlessModule : InteractionModuleBase
eb . AddField ( "Secondary UIDs" , string . Join ( Environment . NewLine , secondaryUIDs ) ) ;
}
}
if ( profile ! = null )
{
eb . AddField ( "Profile Description" , string . IsNullOrEmpty ( profile . UserDescription ) ? "(No description set)" : profile . UserDescription ) ;
eb . AddField ( "Profile NSFW" , profile . IsNSFW ) ;
eb . AddField ( "Profile Disabled" , profile . ProfileDisabled ) ;
eb . AddField ( "Profile Flagged for Report" , profile . FlaggedForReport ) ;
eb . AddField ( "Profile Tags" , profile . Tags ! = null & & profile . Tags . Length > 0 ? string . Join ( ", " , profile . Tags ) : "(No tags set)" ) ;
}
eb . AddField ( "Last Online (UTC)" , dbUser . LastLoggedIn . ToString ( "U" ) ) ;
eb . AddField ( "Currently online " , ! string . IsNullOrEmpty ( identity ) ) ;
eb . AddField ( "Hashed Secret Key" , auth . HashedKey ) ;
@@ -563,62 +426,4 @@ public class LightlessModule : InteractionModuleBase
return eb ;
}
private async Task < string > GetUserUID ( LightlessDbContext db , string? secondaryUserUid = null , ulong? optionalUser = null , string? uid = null )
{
var primaryUser = await db . LodeStoneAuth . Include ( u = > u . User ) . SingleOrDefaultAsync ( u = > u . DiscordId = = Context . User . Id ) . ConfigureAwait ( false ) ;
ulong userToCheckForDiscordId = Context . User . Id ;
if ( ( optionalUser ! = null | | uid ! = null ) )
{
LodeStoneAuth userInDb = null ;
if ( optionalUser ! = null )
{
userInDb = await db . LodeStoneAuth . Include ( u = > u . User ) . SingleOrDefaultAsync ( u = > u . DiscordId = = optionalUser ) . ConfigureAwait ( false ) ;
}
else if ( uid ! = null )
{
userInDb = await db . LodeStoneAuth . Include ( u = > u . User ) . SingleOrDefaultAsync ( u = > u . User . UID = = uid | | u . User . Alias = = uid ) . ConfigureAwait ( false ) ;
}
if ( userInDb = = null )
{
throw new Exception ( "The Discord user has no valid Lightless account" ) ;
}
userToCheckForDiscordId = userInDb . DiscordId ;
}
var lodestoneUser = await db . LodeStoneAuth . Include ( u = > u . User ) . SingleOrDefaultAsync ( u = > u . DiscordId = = userToCheckForDiscordId ) . ConfigureAwait ( false ) ;
var dbUser = lodestoneUser . User ;
if ( secondaryUserUid ! = null )
{
dbUser = ( await db . Auth . Include ( u = > u . User ) . SingleOrDefaultAsync ( u = > u . PrimaryUserUID = = dbUser . UID & & u . UserUID = = secondaryUserUid ) ) ? . User ;
if ( dbUser = = null )
{
throw new Exception ( $"A secondary UID {secondaryUserUid} was not found attached to your primary UID {primaryUser.User.UID}." ) ;
}
}
return dbUser . UID ;
}
private byte [ ] GetProfileImage ( UserProfileData profile )
{
if ( profile ! = null & & profile . Base64ProfileImage ! = null & & profile . Base64ProfileImage . Length > 0 )
{
return Convert . FromBase64String ( profile . Base64ProfileImage ) ;
}
return Array . Empty < byte > ( ) ;
}
private byte [ ] GetBannerImage ( UserProfileData profile )
{
if ( profile ! = null & & profile . Base64BannerImage ! = null & & profile . Base64BannerImage . Length > 0 )
{
return Convert . FromBase64String ( profile . Base64BannerImage ) ;
}
return Array . Empty < byte > ( ) ;
}
private async Task < UserProfileData > GetUserProfileData ( LightlessDbContext db , string uid )
{
var profile = await db . UserProfileData . Where ( u = > u . UserUID = = uid ) . SingleOrDefaultAsync ( ) . ConfigureAwait ( false ) ;
return profile ;
}
}