module Degenz.Admin open System open System.IO open System.Threading.Tasks open DSharpPlus open DSharpPlus.Entities open DSharpPlus.EventArgs open DSharpPlus.SlashCommands open DSharpPlus.SlashCommands.Attributes open Degenz.Messaging open Npgsql.FSharp type InitEmbeds = | Dojo = 0 | Whitelist = 1 | Slots = 2 let handleGuildDownloadReady (_ : DiscordClient) (event : GuildDownloadCompletedEventArgs) = task { let ( _ , guild ) = event.Guilds.TryGetValue(GuildEnvironment.guildId) let! commands = guild.GetApplicationCommandsAsync() let ( _ , adminRole ) = guild.Roles.TryGetValue(GuildEnvironment.roleAdmin) let permission = DiscordApplicationCommandPermission(adminRole, true) let commands = commands |> Seq.map (fun com -> DiscordGuildApplicationCommandPermissions(com.Id, [ permission ])) do! guild.BatchEditApplicationCommandPermissionsAsync(commands) |> Async.AwaitTask |> Async.Ignore } :> Task let sendEmbed embed (ctx : IDiscordContext) = task { match embed with | InitEmbeds.Dojo -> Trainer.sendInitialEmbed ctx | InitEmbeds.Whitelist -> InviteTracker.sendInitialEmbed ctx | InitEmbeds.Slots -> SlotMachine.sendInitialEmbedFromSlashCommand ctx | _ -> () do! Messaging.sendSimpleResponse ctx "Sent!" } :> Task let getAllReactions (msg : DiscordMessage) = task { let mutable listOfUsers = ResizeArray(512) for reaction in msg.Reactions do let mutable count = 0 for r in 0..reaction.Count / 100 do let rs = if count > 0 then msg.GetReactionsAsync(reaction.Emoji, 100, listOfUsers.[listOfUsers.Count - 1].Id) |> Async.AwaitTask |> Async.RunSynchronously else msg.GetReactionsAsync(reaction.Emoji, 100) |> Async.AwaitTask |> Async.RunSynchronously listOfUsers.AddRange(rs) printfn $"Emoji {reaction.Emoji.Name} - {reaction.Count} - Total users: {rs.Count} - Page {count}" count <- count + 1 do! Async.Sleep 2000 return listOfUsers |> List.ofSeq |> List.map (fun (user : DiscordUser) -> {| Id = user.Id ; FullName = $"{user.Username}#{user.Discriminator}" |}) |> List.distinctBy (fun u -> u.Id) |> List.map (fun user -> $"{user.Id},{user.FullName}") |> String.concat "\n" |> (+) "Discord Id Num,Username\n" } let getUserInvites userIds = GuildEnvironment.connectionString |> Sql.connect |> Sql.parameters [ "dids" , Sql.stringArray (userIds |> List.toArray) ] |> Sql.query """ SELECT usr.display_name, inviter, count(invite_id) AS total_invites FROM invite JOIN invited_user iu ON invite.id = iu.invite_id JOIN "user" usr ON invite.inviter = usr.discord_id WHERE iu.accepted = true AND inviter = ANY (@dids) GROUP BY inviter, usr.display_name ORDER BY total_invites DESC; """ |> Sql.executeAsync (fun read -> {| Username = read.string "display_name" ; DiscordId = read.string "discord_id" |> uint64 ; TotalInvites = read.int "total_invites" |}) |> Async.AwaitTask let getMessageReactions (channel : DiscordChannel) (message : string) (ctx : IDiscordContext) = task { do! Messaging.defer ctx let ( result , mId ) = UInt64.TryParse(message) if result then let! msg = channel.GetMessageAsync(message |> uint64) |> Async.AwaitTask let! reactions = getAllReactions msg let builder = DiscordFollowupMessageBuilder() use ms = new MemoryStream(Text.Encoding.ASCII.GetBytes(reactions)) :> Stream let dict = Collections.Generic.Dictionary() dict.Add("users.csv", ms) builder.AddFiles(dict) |> ignore do! ctx.FollowUp(builder) else do! Messaging.sendSimpleResponse ctx $"The message ID provided was not a valid: {message}" } :> Task //let getUserInvitesTable (channel : DiscordChannel) (message : string) (ctx : IDiscordContext) = let getUserInvitesTable (ctx : IDiscordContext) = task { do! Messaging.defer ctx printfn $"Trying this out" try let! invites = getUserInvites [ "90588624566886400" ; "822834227467780136" ] printfn $"Total Invites? \n{invites}" let builder = DiscordFollowupMessageBuilder() builder.Content <- $"%A{invites}" do! ctx.FollowUp(builder) with ex -> printfn $"exception {ex.Message}" } :> Task type AdminBot() = inherit ApplicationCommandModule () let enforceAdmin (ctx : IDiscordContext) (adminFn : IDiscordContext -> Task) = let isAdmin = Seq.exists (fun (role : DiscordRole) -> role.Id = GuildEnvironment.roleAdmin) (ctx.GetDiscordMember().Roles) if isAdmin then adminFn ctx else Messaging.sendSimpleResponse ctx $"You are not admin" |> Async.StartAsTask :> Task [] member this.GetAttributions (ctx : InteractionContext, [] user : DiscordUser) = enforceAdmin (DiscordInteractionContext ctx) (InviteTracker.getInvitedUsersForId user) [] member this.SetStock (ctx : InteractionContext, [] amount : int64) = enforceAdmin (DiscordInteractionContext ctx) (InviteTracker.setWhitelistStock (int amount)) [] member this.SendEmbedToChannel (ctx : InteractionContext, [] embed : InitEmbeds) = enforceAdmin (DiscordInteractionContext ctx) (sendEmbed embed) [] member this.GetMessageReactions (ctx : InteractionContext, [] channel : DiscordChannel, [] messageId : string) = enforceAdmin (DiscordInteractionContext ctx) (getMessageReactions channel messageId) [] member this.GetInvitesTable (ctx : InteractionContext) = enforceAdmin (DiscordInteractionContext ctx) getUserInvitesTable