578 lines
24 KiB
Forth
578 lines
24 KiB
Forth
module Degenz.InviteTracker
|
|
|
|
open System.Text
|
|
open System.Threading.Tasks
|
|
open DSharpPlus
|
|
open DSharpPlus.Entities
|
|
open DSharpPlus.EventArgs
|
|
open DSharpPlus.SlashCommands
|
|
open Degenz.Messaging
|
|
open Npgsql.FSharp
|
|
open Solnet.Wallet
|
|
|
|
let connStr = GuildEnvironment.connectionString
|
|
let InviteRewardAmount = 300<GBT>
|
|
let InviteLinkButtonText = "Get My Invite Link"
|
|
|
|
type Invite = {
|
|
Code : string
|
|
Inviter : uint64
|
|
Count : int
|
|
}
|
|
|
|
let private mapInvite (reader : RowReader) = {
|
|
Code = reader.string "code"
|
|
Inviter = reader.string "inviter" |> uint64
|
|
Count = reader.int "count"
|
|
}
|
|
|
|
let private getInvites () = async {
|
|
let! invites =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.query "SELECT code, inviter, count FROM invite"
|
|
|> Sql.executeAsync mapInvite
|
|
|> Async.AwaitTask
|
|
return
|
|
invites
|
|
|> List.map (fun inv -> (inv.Code , (inv.Inviter , inv.Count)))
|
|
|> Map.ofList
|
|
}
|
|
|
|
let private getInvitesFromUser discordId = async {
|
|
let! invites =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string discordId) ]
|
|
|> Sql.query """
|
|
SELECT code, count FROM invite
|
|
WHERE inviter = @did AND invite.created_at > NOW() at time zone 'utc' - INTERVAL '72 HOURS'
|
|
"""
|
|
|> Sql.executeAsync (fun read -> {
|
|
Code = read.string "code"
|
|
Inviter = discordId
|
|
Count = read.int "count"
|
|
})
|
|
|> Async.AwaitTask
|
|
return
|
|
invites
|
|
|> List.map (fun inv -> (inv.Code , (inv.Inviter , inv.Count)))
|
|
|> Map.ofList
|
|
}
|
|
|
|
let private createInvite inviter code =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "code" , Sql.string code ; "inviter" , Sql.string (string inviter) ]
|
|
|> Sql.query "INSERT INTO invite (code, inviter) VALUES (@code, @inviter)"
|
|
|> Sql.executeNonQueryAsync
|
|
|> Async.AwaitTask
|
|
|
|
let private addInvitedUser did inviterId code =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "@code" , Sql.string code ; "@did" , Sql.string (string did) ; "@iid" , Sql.string (string inviterId) ]
|
|
|> Sql.query """
|
|
INSERT INTO invited_user (inviter_id, discord_id, invite_id)
|
|
VALUES (@iid, @did, (SELECT id FROM invite WHERE code = @code))
|
|
"""
|
|
|> Sql.executeNonQueryAsync
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
|
|
let private updateInviteCount code count =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "count" , Sql.int count ; "code" , Sql.string code ]
|
|
|> Sql.query "UPDATE invite SET count = @count WHERE code = @code"
|
|
|> Sql.executeNonQueryAsync
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
|
|
let private markInvitedAccepted did =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string did) ]
|
|
|> Sql.query "UPDATE invited_user SET accepted = true, updated_at = timezone('utc'::text, now()) WHERE discord_id = @did"
|
|
|> Sql.executeNonQueryAsync
|
|
|> Async.AwaitTask
|
|
|
|
let private getInviteFromInvitedUser invitedUser =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string invitedUser) ]
|
|
|> Sql.query """
|
|
SELECT code, inviter, count FROM invite
|
|
JOIN invited_user iu ON invite.id = iu.invite_id
|
|
WHERE iu.discord_id = @did
|
|
"""
|
|
|> Sql.executeRowAsync mapInvite
|
|
|> Async.AwaitTask
|
|
|
|
let private removeInvitedUser did =
|
|
try
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string did) ]
|
|
|> Sql.query "DELETE FROM invited_user WHERE discord_id = @did"
|
|
|> Sql.executeNonQueryAsync
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
with _ -> async.Zero ()
|
|
|
|
let private checkUserAlreadyInvited userId = async {
|
|
let! result =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
|
|> Sql.query """
|
|
SELECT id FROM invited_user WHERE discord_id = @did
|
|
"""
|
|
|> Sql.executeAsync (fun read -> read.int "id")
|
|
|> Async.AwaitTask
|
|
|
|
return List.isEmpty result |> not
|
|
}
|
|
|
|
let checkInviteAccepted (userId : uint64) = async {
|
|
let! result =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
|
|> Sql.query "SELECT accepted FROM invited_user WHERE discord_id = @did"
|
|
|> Sql.executeAsync (fun read -> read.bool "accepted")
|
|
|> Async.AwaitTask
|
|
return List.tryHead result |> Option.defaultValue false
|
|
}
|
|
|
|
let private getInviteAttributions userId =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
|
|> Sql.query """
|
|
SELECT count(*) FROM invited_user
|
|
JOIN invite ON invite.id = invited_user.invite_id
|
|
WHERE invite.inviter = @did AND invited_user.accepted = true;
|
|
"""
|
|
|> Sql.executeRowAsync (fun read -> read.int "count")
|
|
|> Async.AwaitTask
|
|
|
|
let getInvitedUsers userId =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
|
|> Sql.query """
|
|
WITH invite AS (SELECT id FROM invite WHERE inviter = @did)
|
|
SELECT discord_id FROM invited_user, invite
|
|
WHERE invite.id = invited_user.invite_id AND invited_user.accepted = true
|
|
ORDER BY invited_user.updated_at DESC, invited_user.created_at DESC LIMIT 10
|
|
"""
|
|
|> Sql.executeAsync (fun read -> read.string "discord_id" |> uint64)
|
|
|> Async.AwaitTask
|
|
|
|
let getInvitedUserCount userId =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
|
|> Sql.query """
|
|
WITH invite AS (SELECT id FROM invite WHERE inviter = @did)
|
|
SELECT count(*) FROM invited_user, invite
|
|
WHERE invite.id = invited_user.invite_id AND invited_user.accepted = true
|
|
"""
|
|
|> Sql.executeRowAsync (fun read -> read.int "count")
|
|
|> Async.AwaitTask
|
|
|
|
let addWalletAddress (userId : uint64) address =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ; "address" , Sql.string address ]
|
|
|> Sql.query """
|
|
UPDATE "user" SET wallet_address = @address WHERE id = @did;
|
|
"""
|
|
|> Sql.executeNonQueryAsync
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
|
|
let getWalletAddress (userId : uint64) =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
|
|> Sql.query """
|
|
SELECT wallet_address FROM "user" WHERE id = @did;
|
|
"""
|
|
|> Sql.executeRowAsync (fun reader -> reader.stringOrNone "wallet_address")
|
|
|> Async.AwaitTask
|
|
|
|
let walletAddressExists (address : string) =
|
|
async {
|
|
let! result =
|
|
connStr
|
|
|> Sql.connect
|
|
|> Sql.parameters [ "address" , Sql.string address ]
|
|
|> Sql.query """
|
|
SELECT wallet_address FROM "user" WHERE wallet_address = @address;
|
|
"""
|
|
|> Sql.executeAsync (fun reader -> reader.stringOrNone "wallet_address")
|
|
|> Async.AwaitTask
|
|
return List.isEmpty result |> not
|
|
}
|
|
|
|
let private listServerInvites (ctx : IDiscordContext) = task {
|
|
let! invites = ctx.GetGuild().GetInvitesAsync()
|
|
let sb = StringBuilder()
|
|
for invite in invites do
|
|
sb.AppendLine($"{invite.Inviter.Username} - {invite.Code}") |> ignore
|
|
let msg =
|
|
DiscordInteractionResponseBuilder()
|
|
.AsEphemeral(true)
|
|
.WithContent("Server Invites\n" + sb.ToString())
|
|
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, msg)
|
|
}
|
|
|
|
let getAttributions userId (ctx : IDiscordContext) =
|
|
task {
|
|
let! total = getInviteAttributions(userId)
|
|
let msg =
|
|
DiscordInteractionResponseBuilder()
|
|
.AsEphemeral(true)
|
|
.WithContent($"<@{userId}> has invited {total} people")
|
|
do! ctx.Respond(InteractionResponseType.ChannelMessageWithSource, msg)
|
|
} :> Task
|
|
|
|
let getInvitedUsersForId (user : DiscordUser) (ctx : IDiscordContext) =
|
|
task {
|
|
do! Messaging.defer ctx
|
|
let! users = getInvitedUsers user.Id
|
|
let! total = getInvitedUserCount user.Id
|
|
let sb = StringBuilder()
|
|
let mutable count = 0
|
|
for user in users do
|
|
count <- count + 1
|
|
sb.AppendLine($"{count}.) <@!{user}>") |> ignore
|
|
let msg =
|
|
let str =
|
|
if users.Length > 0 then
|
|
$"**Total Recruited:** `{total} Degenz`\n**Total Earned:** `{total * InviteRewardAmount} 💰$GBT`\n\n**Last 10 users recruited:**\n{sb}"
|
|
else
|
|
$"You haven't recruited anyone yet, click the `{InviteLinkButtonText}` button to get your invite link and start recruiting!"
|
|
DiscordFollowupMessageBuilder()
|
|
.AsEphemeral(true)
|
|
.WithContent(str)
|
|
do! ctx.FollowUp(msg)
|
|
let user = ctx.GetDiscordMember()
|
|
do! Analytics.recruitedButton total user.Id user.Username (ctx.GetChannel())
|
|
} :> Task
|
|
|
|
let clearInvites (ctx : IDiscordContext) = task {
|
|
let! invites = ctx.GetGuild().GetInvitesAsync()
|
|
do!
|
|
invites
|
|
|> Seq.map (fun invite -> invite.DeleteAsync() |> Async.AwaitTask)
|
|
|> Async.Sequential
|
|
|> Async.Ignore
|
|
}
|
|
|
|
// Discord doesn't have any way to tell you if the user came via an invite, the only way to tell is to compare the
|
|
// cached invites in the DB to the ones in the guild and see if any has been incremented
|
|
let private processNewUser (eventArgs : GuildMemberAddEventArgs) =
|
|
task {
|
|
let! guildInvites = eventArgs.Guild.GetInvitesAsync()
|
|
let! cachedInvites = getInvites ()
|
|
for invite in guildInvites do
|
|
let result = cachedInvites.TryFind(invite.Code)
|
|
match result with
|
|
| Some (inviterId,count) ->
|
|
if invite.Uses > count then
|
|
do! updateInviteCount invite.Code invite.Uses
|
|
try
|
|
match! checkUserAlreadyInvited eventArgs.Member.Id with
|
|
| false ->
|
|
do! addInvitedUser eventArgs.Member.Id inviterId invite.Code |> Async.Ignore
|
|
match! DbService.tryFindPlayer inviterId with
|
|
| Some inviter ->
|
|
do! Analytics.invitedUserEntered invite.Code inviter.DiscordId eventArgs.Member.Id inviter.Name eventArgs.Member.Username
|
|
| None ->
|
|
do! Analytics.invitedUserEntered invite.Code inviterId eventArgs.Member.Id "Unknown" eventArgs.Member.Username
|
|
| true -> ()
|
|
with ex -> printfn $"Tried to add existing user {eventArgs.Member.Id}:{eventArgs.Member.Username} to invites: {ex.Message}"
|
|
| None -> ()
|
|
} :> Task
|
|
|
|
let acceptInvite (guild : DiscordGuild) (user : DiscordMember) =
|
|
task {
|
|
match! checkInviteAccepted user.Id with
|
|
| false ->
|
|
do! markInvitedAccepted user.Id |> Async.Ignore
|
|
try
|
|
let! invite = getInviteFromInvitedUser user.Id
|
|
let! player = DbService.tryFindPlayer invite.Inviter
|
|
match player with
|
|
| Some player ->
|
|
do! DbService.updatePlayerCurrency InviteRewardAmount player.DiscordId |> Async.Ignore
|
|
do! match GuildEnvironment.botClientRecruit with
|
|
| Some recruitBot -> async {
|
|
let builder = DiscordMessageBuilder()
|
|
builder.WithContent($"{user.Username} was recruited and is now a Degen. **{player.Name}** just earned `{InviteRewardAmount} 💰$GBT` for their efforts! - <@!{player.DiscordId}>") |> ignore
|
|
let channel = guild.GetChannel(GuildEnvironment.channelEventsHackerBattle)
|
|
do! recruitBot.SendMessageAsync(channel, builder)
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
}
|
|
| None -> async.Return()
|
|
let role3x = guild.Roles.TryGetValue(GuildEnvironment.roleRecruiter3x) |> snd
|
|
let role2x = guild.Roles.TryGetValue(GuildEnvironment.roleRecruiter2x) |> snd
|
|
let role1x = guild.Roles.TryGetValue(GuildEnvironment.roleRecruiter1x) |> snd
|
|
let! playerMember = guild.GetMemberAsync(invite.Inviter)
|
|
let! totalInvites = getInvitedUserCount player.DiscordId
|
|
if totalInvites >= 10 then
|
|
do! [ playerMember.GrantRoleAsync(role3x) ; playerMember.RevokeRoleAsync(role2x) ; playerMember.RevokeRoleAsync(role1x) ]
|
|
|> List.map Async.AwaitTask
|
|
|> Async.Parallel
|
|
|> Async.Ignore
|
|
elif totalInvites >= 5 then
|
|
do! [ playerMember.GrantRoleAsync(role2x) ; playerMember.RevokeRoleAsync(role1x) ]
|
|
|> List.map Async.AwaitTask
|
|
|> Async.Parallel
|
|
|> Async.Ignore
|
|
else
|
|
do! playerMember.GrantRoleAsync(role1x)
|
|
do! Analytics.invitedUserAccepted invite.Code player.DiscordId user.Id player.Name user.Username
|
|
| None -> return ()
|
|
with _ -> ()
|
|
| true -> return ()
|
|
} :> Task
|
|
|
|
let sendInitialEmbed (ctx : IDiscordContext) =
|
|
async {
|
|
try
|
|
let channel = ctx.GetGuild().GetChannel(GuildEnvironment.channelRecruitment)
|
|
let rewardMsg = $"""
|
|
**__Win $3,000:__**
|
|
🙋 1 invite = 1 entry everyday*
|
|
🎟 $100 daily raffles till mint
|
|
|
|
**__How To Invite:__**
|
|
1️⃣ Click the green button below
|
|
2️⃣ Share your unique link with Friends
|
|
|
|
**__Bonus__**
|
|
💰 Earn an extra {InviteRewardAmount} $GBT for every invite!
|
|
<:purple_fist:986685279031152650> <@#{GuildEnvironment.roleRecruiter1x}> role if you invite 1 or more Degen
|
|
<:red_fist:986685280868249690> <@#{GuildEnvironment.roleRecruiter2x}> role is you invite 5 or more Degen
|
|
<:gold_fist:986685276942377052> <@#{GuildEnvironment.roleRecruiter3x}> role is you invite 10 or more Degen
|
|
|
|
**Every invite increases your chances of winning*
|
|
"""
|
|
let embed =
|
|
DiscordEmbedBuilder()
|
|
.WithColor(DiscordColor.Gold)
|
|
.WithDescription(rewardMsg)
|
|
.WithImageUrl("https://s8.gifyu.com/images/invite-banner-usdcb670496dc3653cb3.png")
|
|
.WithTitle("Invite Degenz")
|
|
|
|
let builder = DiscordMessageBuilder().AddEmbed(embed)
|
|
let btn1 = DiscordButtonComponent(ButtonStyle.Success, $"CreateGuildInvite", InviteLinkButtonText) :> DiscordComponent
|
|
let btn2 = DiscordButtonComponent(ButtonStyle.Primary, $"ShowRecruited", $"Check My Recruits") :> DiscordComponent
|
|
builder.AddComponents [| btn1 ; btn2 |] |> ignore
|
|
|
|
do! GuildEnvironment.botClientRecruit.Value.SendMessageAsync(channel, builder)
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
with e ->
|
|
printfn $"Error trying to get channel Whitelist\n\n{e.Message}"
|
|
} |> Async.RunSynchronously
|
|
|
|
let showWalletStatus (ctx : IDiscordContext) =
|
|
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
|
try
|
|
match! getWalletAddress player.DiscordId with
|
|
| Some address -> do! Messaging.sendFollowUpMessage ctx $"""
|
|
🚀 __Mint Date:__ June 20th
|
|
✅ __Status:__ We have successfully received your wallet address: {address}"""
|
|
| None -> do! Messaging.sendFollowUpMessage ctx "You haven't submitted a wallet yet. Type `/submit`, paste your **Solana Wallet Address**, then press enter"
|
|
with ex ->
|
|
printfn $"{ex.Message}"
|
|
do! Messaging.sendFollowUpMessage ctx "Something went wrong retrieving your wallet address"
|
|
})
|
|
|
|
let sendSubmitEmbed (ctx : IDiscordContext) =
|
|
async {
|
|
try
|
|
let rewardMsg = $"""
|
|
To confirm your **Whitelist** please submit it below:
|
|
|
|
1️⃣ Type `/submit`
|
|
2️⃣ Paste your **Wallet Address**
|
|
3️⃣ Press `Enter`
|
|
|
|
**Check status anytime to double check it worked*"""
|
|
let embed =
|
|
DiscordEmbedBuilder()
|
|
.WithColor(DiscordColor.Teal)
|
|
.WithDescription(rewardMsg)
|
|
.WithImageUrl("https://s8.gifyu.com/images/whitelist-submit-banner7.png")
|
|
.WithTitle("Submit Your Solana Wallet Address")
|
|
|
|
let builder = DiscordMessageBuilder().AddEmbed(embed)
|
|
let btn = DiscordButtonComponent(ButtonStyle.Success, "WalletStatus", "Check Status") :> DiscordComponent
|
|
builder.AddComponents [| btn |] |> ignore
|
|
|
|
let recruitBot = GuildEnvironment.botClientRecruit.Value
|
|
let! channel = recruitBot.GetChannelAsync(GuildEnvironment.channelSubmitWallet) |> Async.AwaitTask
|
|
let! msgs = channel.GetMessagesAsync() |> Async.AwaitTask
|
|
match msgs |> Seq.tryHead with
|
|
| Some msg ->
|
|
if msg.Author.Id = recruitBot.CurrentUser.Id then
|
|
do! msg.ModifyAsync(builder) |> Async.AwaitTask |> Async.Ignore
|
|
| None ->
|
|
do! recruitBot.SendMessageAsync(channel, builder)
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
with e ->
|
|
printfn $"Error trying to get channel Recruit thing\n\n{e.Message}"
|
|
} |> Async.RunSynchronously
|
|
|
|
let handleCreateInvite (ctx : IDiscordContext) =
|
|
task {
|
|
let builder = DiscordInteractionResponseBuilder().AsEphemeral(true)
|
|
do! ctx.Respond(InteractionResponseType.DeferredChannelMessageWithSource, builder)
|
|
|
|
let user = ctx.GetDiscordMember()
|
|
|
|
let! code =
|
|
task {
|
|
let! invites = getInvitesFromUser user.Id
|
|
match invites |> Map.toList with
|
|
| [] ->
|
|
let ( result , channel ) = ctx.GetGuild().Channels.TryGetValue(GuildEnvironment.channelWelcome)
|
|
if result then
|
|
let! invite = channel.CreateInviteAsync(max_age = 259200, unique = true)
|
|
|
|
try do! createInvite (ctx.GetDiscordMember().Id) invite.Code |> Async.Ignore
|
|
with ex -> printfn "%A" ex.Message
|
|
|
|
return invite.Code
|
|
else
|
|
printfn "Error finding Welcome channel"
|
|
return ""
|
|
| invite::_ ->
|
|
return invite |> fst
|
|
}
|
|
|
|
let msg =
|
|
DiscordFollowupMessageBuilder()
|
|
.WithContent($"https://discord.gg/{code}")
|
|
.AsEphemeral(true)
|
|
|
|
do! ctx.FollowUp(msg)
|
|
do! Analytics.recruitLinkButton code user.Id user.Username (ctx.GetChannel())
|
|
} :> Task
|
|
|
|
let handleMemberUpdated (client : DiscordClient) (event : GuildMemberUpdateEventArgs) =
|
|
let addedRole (rolesBefore : DiscordRole seq) (rolesAfter : DiscordRole seq) =
|
|
rolesAfter |> Seq.filter ((fun role -> rolesBefore |> Seq.exists (fun r -> role.Id = r.Id)) >> not)
|
|
task {
|
|
let symmetricDifference = addedRole event.RolesBefore event.RolesAfter |> Seq.toList
|
|
match symmetricDifference with
|
|
| [] -> ()
|
|
| role::_ ->
|
|
if role.Name = "Degen" then
|
|
let (_,guild) = client.Guilds.TryGetValue(GuildEnvironment.guildId)
|
|
do! acceptInvite guild event.Member |> Async.AwaitTask
|
|
return ()
|
|
} :> Task
|
|
|
|
let handleMessageCreated _ (event : MessageCreateEventArgs) =
|
|
task {
|
|
let bot = GuildEnvironment.botClientRecruit.Value
|
|
if event.Channel.Id = GuildEnvironment.channelSubmitWallet && event.Author.Id <> bot.CurrentUser.Id then
|
|
do! Async.Sleep 100
|
|
do! event.Message.DeleteAsync()
|
|
} :> Task
|
|
|
|
let handleGuildMemberAdded _ (eventArgs : GuildMemberAddEventArgs) = processNewUser eventArgs
|
|
|
|
let submitAddress (address : string) (ctx : IDiscordContext) =
|
|
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
|
let pubkey = PublicKey(address)
|
|
try
|
|
if pubkey.IsValid() && pubkey.IsOnCurve() then
|
|
let! maybeAddress = getWalletAddress player.DiscordId
|
|
let msg =
|
|
match maybeAddress with
|
|
| Some storedAddress when storedAddress = address -> "You already provided this wallet address:"
|
|
| Some _ -> "We successfully updated your wallet address:"
|
|
| None -> "We have successfully received your wallet address"
|
|
do! addWalletAddress (ctx.GetDiscordMember().Id) address
|
|
|
|
let user = ctx.GetDiscordMember()
|
|
if ctx.GetDiscordMember().Roles |> Seq.exists (fun role -> role.Id = GuildEnvironment.roleWhitelistPending) then
|
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhitelist)
|
|
do! user.GrantRoleAsync(role) |> Async.AwaitTask
|
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhitelistPending)
|
|
do! user.RevokeRoleAsync(role) |> Async.AwaitTask
|
|
if ctx.GetDiscordMember().Roles |> Seq.exists (fun role -> role.Id = GuildEnvironment.roleWhiteOGPending) then
|
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhiteOG)
|
|
do! user.GrantRoleAsync(role) |> Async.AwaitTask
|
|
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhiteOGPending)
|
|
do! user.RevokeRoleAsync(role) |> Async.AwaitTask
|
|
|
|
do! Messaging.sendFollowUpMessage ctx $"""
|
|
🚀 __Mint Date:__ June 20th
|
|
✅ {msg} {address}
|
|
|
|
Keep an eye on <#{GuildEnvironment.channelAnnouncements}> for updates."""
|
|
|
|
let builder = DiscordMessageBuilder()
|
|
builder.WithContent($"**{ctx.GetDiscordMember().Username}** submitted their wallet address in <#{GuildEnvironment.channelSubmitWallet}> and confirmed whitelist") |> ignore
|
|
let channel = (ctx.GetGuild().GetChannel(GuildEnvironment.channelEventsHackerBattle))
|
|
do! channel.SendMessageAsync(builder)
|
|
|> Async.AwaitTask
|
|
|> Async.Ignore
|
|
do! Analytics.walletSubmit (ctx.GetDiscordMember())
|
|
else
|
|
do! Messaging.sendFollowUpMessage ctx "⚠️ That's not a valid Solana address, please try again"
|
|
do! Analytics.invalidWalletSubmit (ctx.GetDiscordMember())
|
|
with ex ->
|
|
do! Messaging.sendFollowUpMessage ctx "⚠️ That's not a valid Solana address, please try again"
|
|
do! Analytics.invalidWalletSubmit (ctx.GetDiscordMember())
|
|
})
|
|
|
|
type Inviter() =
|
|
inherit ApplicationCommandModule ()
|
|
|
|
let enforceChannel (ctx : IDiscordContext) (fn : IDiscordContext -> Task) =
|
|
match ctx.GetChannel().Id with
|
|
| id when id = GuildEnvironment.channelSubmitWallet -> fn ctx
|
|
| _ ->
|
|
task {
|
|
let msg = $"You must go to <#{GuildEnvironment.channelSubmitWallet}> channel to submit your wallet"
|
|
do! Messaging.sendSimpleResponse ctx msg
|
|
}
|
|
|
|
[<SlashCommand("submit", "Submit your public wallet address")>]
|
|
member this.SubmitAddress (ctx : InteractionContext, [<Option("address", "Wallet address")>] address : string) =
|
|
let isWhitelist (role : DiscordRole) =
|
|
role.Id = GuildEnvironment.roleWhitelistPending || role.Id = GuildEnvironment.roleWhiteOGPending ||
|
|
role.Id = GuildEnvironment.roleWhitelist || role.Id = GuildEnvironment.roleWhiteOG
|
|
if ctx.Member.Roles |> Seq.exists isWhitelist then
|
|
enforceChannel (DiscordInteractionContext ctx) (submitAddress address)
|
|
else
|
|
let msg = $"You currently are not Whitelisted, go to <#{GuildEnvironment.channelWhitelist}> to purchase the role!"
|
|
Messaging.sendSimpleResponse (DiscordInteractionContext ctx) msg
|
|
|> Async.StartAsTask :> Task
|
|
|
|
// [<SlashCommand("recruited", "Get total invites from a specific user")>]
|
|
// member this.ListInvitedPeople (ctx : InteractionContext) =
|
|
// let ictx = DiscordInteractionContext ctx :> IDiscordContext
|
|
// getInvitedUsersForId (ictx.GetDiscordMember()) ictx
|
|
|
|
// [<SlashCommand("invites-list", "List all the invites")>]
|
|
// member this.ListServerInvites (ctx : InteractionContext) =
|
|
// listServerInvites (DiscordInteractionContext ctx)
|
|
|
|
// [<SlashCommand("invites-clear", "Get total invites from a specific user")>]
|
|
// member this.ClearInvites (ctx : InteractionContext) =
|
|
// clearInvites (DiscordInteractionContext ctx)
|
|
|