Merge branch 'master' into dev
This commit is contained in:
commit
36e6225201
@ -105,7 +105,7 @@ let getStoreItems (storeId : string) =
|
||||
|> Sql.connect
|
||||
|> Sql.parameters [ "sid", Sql.string storeId ]
|
||||
|> Sql.query """
|
||||
SELECT store_id,stock,available,limit_stock,i.id,name,description,icon_url,image_url,category,require_role,require_invites,
|
||||
SELECT store_id,stock,available,limit_stock,i.id,name,description,icon_url,image_url,category,require_role,require_invites,sale_end,
|
||||
buy_price,sell_price,rate_limit,expiration,drop_chance,can_trade,can_consume,attack_power,defense_power,class_name,max_stack,mods
|
||||
FROM store_item
|
||||
JOIN item i on store_item.item_id = i.id
|
||||
@ -116,6 +116,7 @@ let getStoreItems (storeId : string) =
|
||||
Stock = reader.int "stock"
|
||||
LimitStock = reader.bool "limit_stock"
|
||||
Available = reader.bool "available"
|
||||
SaleEnd = reader.int64OrNone "sale_end"
|
||||
TotalSold = None
|
||||
RequiresInvites = reader.intOrNone "require_invites"
|
||||
RequiresRole = reader.stringOrNone "require_role" |> Option.map uint64
|
||||
@ -127,7 +128,7 @@ let getAllActiveStoreItems () =
|
||||
connStr
|
||||
|> Sql.connect
|
||||
|> Sql.query """
|
||||
SELECT store_id,stock,available,limit_stock,i.id,name,description,icon_url,image_url,category,require_role,require_invites,
|
||||
SELECT store_id,stock,available,limit_stock,i.id,name,description,icon_url,image_url,category,require_role,require_invites,sale_end,
|
||||
buy_price,sell_price,rate_limit,expiration,drop_chance,can_trade,can_consume,attack_power,defense_power,class_name,max_stack,mods
|
||||
FROM store_item
|
||||
JOIN item i on store_item.item_id = i.id
|
||||
@ -138,6 +139,7 @@ let getAllActiveStoreItems () =
|
||||
Stock = reader.int "stock"
|
||||
LimitStock = reader.bool "limit_stock"
|
||||
Available = reader.bool "available"
|
||||
SaleEnd = reader.int64OrNone "sale_end"
|
||||
TotalSold = None
|
||||
RequiresInvites = reader.intOrNone "require_invites"
|
||||
RequiresRole = reader.stringOrNone "require_role" |> Option.map uint64
|
||||
@ -151,7 +153,7 @@ let getRafflesWithPurchases storeId =
|
||||
|> Sql.parameters [ "sid" , Sql.string storeId ]
|
||||
|> Sql.query """
|
||||
WITH raffles AS
|
||||
(SELECT store_id,stock,available,limit_stock,i.id AS raffle_id,name,description,icon_url,image_url,category,require_role,require_invites,
|
||||
(SELECT store_id,stock,available,limit_stock,i.id AS raffle_id,name,description,icon_url,image_url,category,require_role,require_invites,sale_end,
|
||||
buy_price,sell_price,rate_limit,expiration,drop_chance,can_trade,can_consume,attack_power,defense_power,class_name,max_stack,mods
|
||||
FROM store_item
|
||||
JOIN item i on store_item.item_id = i.id
|
||||
@ -166,6 +168,7 @@ FULL JOIN (SELECT item_id, count(*) AS total FROM inventory_item
|
||||
Stock = reader.int "stock"
|
||||
LimitStock = reader.bool "limit_stock"
|
||||
Available = reader.bool "available"
|
||||
SaleEnd = reader.int64OrNone "sale_end"
|
||||
TotalSold = reader.intOrNone "total"
|
||||
RequiresInvites = reader.intOrNone "require_invites"
|
||||
RequiresRole = reader.stringOrNone "require_role" |> Option.map uint64
|
||||
@ -178,7 +181,7 @@ let getStoreItemBySymbol (itemSymbol : string) =
|
||||
|> Sql.connect
|
||||
|> Sql.parameters [ "iid", Sql.string itemSymbol ]
|
||||
|> Sql.query """
|
||||
SELECT store_id,stock,available,limit_stock,i.id,name,description,icon_url,image_url,category,require_role,require_invites,
|
||||
SELECT store_id,stock,available,limit_stock,i.id,name,description,icon_url,image_url,category,require_role,require_invites,sale_end,
|
||||
buy_price,sell_price,rate_limit,expiration,drop_chance,can_trade,can_consume,attack_power,defense_power,class_name,max_stack,mods
|
||||
FROM store_item
|
||||
JOIN item i on store_item.item_id = i.id
|
||||
@ -189,6 +192,7 @@ let getStoreItemBySymbol (itemSymbol : string) =
|
||||
Stock = reader.int "stock"
|
||||
LimitStock = reader.bool "limit_stock"
|
||||
Available = reader.bool "available"
|
||||
SaleEnd = reader.int64OrNone "sale_end"
|
||||
TotalSold = None
|
||||
RequiresInvites = reader.intOrNone "require_invites"
|
||||
RequiresRole = reader.stringOrNone "require_role" |> Option.map uint64
|
||||
|
@ -144,6 +144,7 @@ type StoreItem = {
|
||||
LimitStock : bool
|
||||
Available : bool
|
||||
TotalSold : int option
|
||||
SaleEnd : int64 option
|
||||
RequiresRole : uint64 option
|
||||
RequiresInvites : int option
|
||||
Item : Item
|
||||
|
@ -53,13 +53,20 @@ let checkDoesntExceedStackCap (item : Item) player =
|
||||
| _ , Some _ -> "You already own this item" |> embedWithError
|
||||
| _ -> Ok ()
|
||||
|
||||
let checkItemSaleStillActive (item : StoreItem) =
|
||||
match item.SaleEnd with
|
||||
| Some time ->
|
||||
let date = DateTimeOffset.FromUnixTimeSeconds(time).DateTime.ToUniversalTime()
|
||||
if DateTime.UtcNow < date then Ok () else $"Sale for {item.Item.Name} has already ended!" |> embedWithError
|
||||
| None -> Ok ()
|
||||
|
||||
let checkSoldItemAlready (item : Item) player =
|
||||
if player.Inventory |> List.exists (fun i -> item.Id = i.Id)
|
||||
then Ok ()
|
||||
else $"{item.Name} not found in your inventory! Looks like you sold it already."
|
||||
|> embedWithError
|
||||
|
||||
let checkHasItemsInArsenal itemType items player =
|
||||
let checkHasItemsInArsenal itemType items =
|
||||
if List.isEmpty items |> not
|
||||
then Ok ()
|
||||
else $"You currently have no {itemType} in your arsenal to sell!"
|
||||
@ -125,6 +132,13 @@ let getItemEmbeds owned (items : StoreItem list) =
|
||||
| _ -> ())
|
||||
// if item.Item.Type = ItemType.Whitelist then
|
||||
// embed.AddField("Mint Allowance", (if item.Item.Id = "WHITEOG" then 2 else 1) |> string, true) |> ignore
|
||||
item.SaleEnd |> Option.iter (fun time ->
|
||||
let date = DateTimeOffset.FromUnixTimeSeconds(time).DateTime.ToUniversalTime()
|
||||
if DateTime.UtcNow < date then
|
||||
embed.AddField("⏰ Closes", $"<t:{time}:R>", true) |> ignore
|
||||
else
|
||||
embed.AddField("🚫 Closed", $"<t:{time}:R>", true) |> ignore)
|
||||
|
||||
item.TotalSold |> Option.iter (fun total -> embed.AddField("Total Sold", string total, true) |> ignore)
|
||||
embed.Color <- WeaponClass.getClassEmbedColor item.Item
|
||||
embed.Title <- titleText
|
||||
@ -142,12 +156,19 @@ let getBuyItemsEmbed storeId player (storeInventory : StoreItem list) =
|
||||
storeInventory
|
||||
|> List.map (fun item ->
|
||||
let owned = player.Inventory |> List.exists (fun i -> i.Id = item.Item.Id)
|
||||
let saleStillOngoing =
|
||||
match item.SaleEnd with
|
||||
| Some time ->
|
||||
let date = DateTimeOffset.FromUnixTimeSeconds(time).DateTime.ToUniversalTime()
|
||||
DateTime.UtcNow < date
|
||||
| None -> true
|
||||
let inStock = item.Available && (item.Stock > 0 || item.LimitStock = false)
|
||||
match owned , inStock with
|
||||
| _ , false ->
|
||||
match owned , inStock , saleStillOngoing with
|
||||
| _ , false , _ ->
|
||||
let msg = if item.Available then "Out of Stock" else "Unavailable"
|
||||
DiscordButtonComponent(WeaponClass.getClassButtonColor item.Item, $"Buy-{item.Item.Id}-{storeId}", $"{item.Item.Name} ({msg})", true)
|
||||
| false , true -> DiscordButtonComponent(WeaponClass.getClassButtonColor item.Item, $"Buy-{item.Item.Id}-{storeId}", $"Buy {item.Item.Name}")
|
||||
| false , true , true -> DiscordButtonComponent(WeaponClass.getClassButtonColor item.Item, $"Buy-{item.Item.Id}-{storeId}", $"Buy {item.Item.Name}")
|
||||
| _ , _ , false -> DiscordButtonComponent(WeaponClass.getClassButtonColor item.Item, $"Buy-{item.Item.Id}-{storeId}", $"Closed {item.Item.Name}", true)
|
||||
| _ ->
|
||||
match checkDoesntExceedStackCap item.Item player with
|
||||
| Ok _ -> DiscordButtonComponent(WeaponClass.getClassButtonColor item.Item, $"Buy-{item.Item.Id}-{storeId}", $"Buy {item.Item.Name}")
|
||||
@ -170,7 +191,7 @@ let purchaseItemEmbed quantity (item : Item) =
|
||||
match item.Type with
|
||||
| ItemType.Jpeg ->
|
||||
let itemName = item.Name.Replace("🎟️", "")
|
||||
embed.Description <- $"Congratulations! You are in the draw for the {itemName}.\n\nThe winner will be announced soon in <#{GuildEnvironment.channelGiveaway}>"
|
||||
embed.Description <- $"Congratulations! You are in the draw for the {itemName}.\n\nWinners announced in <#{GuildEnvironment.channelGiveaway}>"
|
||||
embed.ImageUrl <- item.ImageUrl
|
||||
embed.Thumbnail <- DiscordEmbedBuilder.EmbedThumbnail()
|
||||
embed.Thumbnail.Url <- item.IconUrl
|
||||
@ -261,7 +282,7 @@ let buyForPlayer storeId player (filterBy : ItemType option) (ctx : IDiscordCont
|
||||
let sell itemType getItems (ctx : IDiscordContext) =
|
||||
executePlayerAction ctx (fun player -> async {
|
||||
let items = getItems player.Inventory
|
||||
match checkHasItemsInArsenal itemType items player with
|
||||
match checkHasItemsInArsenal itemType items with
|
||||
| Ok _ -> let itemStore = getSellEmbed items
|
||||
do! ctx.FollowUp(itemStore) |> Async.AwaitTask
|
||||
| Error e -> do! ctx.FollowUp e |> Async.AwaitTask
|
||||
@ -335,6 +356,7 @@ let handleBuyItem (dispatch : IDiscordContext -> Task) (ctx : IDiscordContext) i
|
||||
let storeItem = storeInventory |> List.find (fun si -> si.Item.Id = itemId)
|
||||
do! checkHasSufficientFunds storeItem.Item player
|
||||
do! checkHasStock storeItem
|
||||
do! checkItemSaleStillActive storeItem
|
||||
do! checkDoesntExceedStackCap storeItem.Item player
|
||||
do! checkHasRequiredRole storeItem (ctx.GetDiscordMember())
|
||||
do! checkHasRequiredInvites storeItem player
|
||||
|
@ -68,20 +68,26 @@ let private createInvite inviter code =
|
||||
|> Sql.executeNonQueryAsync
|
||||
|> Async.AwaitTask
|
||||
|
||||
let private addInvitedUser did code count =
|
||||
try
|
||||
let private addInvitedUser did inviterId code =
|
||||
connStr
|
||||
|> Sql.connect
|
||||
|> Sql.executeTransactionAsync [
|
||||
|> 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))
|
||||
"""
|
||||
INSERT INTO invited_user (discord_id, invite_id)
|
||||
VALUES (@did, (SELECT id FROM invite WHERE code = @code));
|
||||
""" , [ [ "@code" , Sql.string code ; "@did" , Sql.string (string did) ] ]
|
||||
"UPDATE invite SET count = @count WHERE code = @code" , [ [ "count" , Sql.int count ; "code" , Sql.string 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
|
||||
with _ -> async.Zero ()
|
||||
|
||||
let private markInvitedAccepted did =
|
||||
connStr
|
||||
@ -129,18 +135,14 @@ let private checkUserAlreadyInvited userId = async {
|
||||
}
|
||||
|
||||
let checkInviteAccepted (userId : uint64) = async {
|
||||
try
|
||||
let! result =
|
||||
connStr
|
||||
|> Sql.connect
|
||||
|> Sql.parameters [ "did" , Sql.string (string userId) ]
|
||||
|> Sql.query "SELECT accepted FROM invited_user WHERE discord_id = @did"
|
||||
|> Sql.executeRowAsync (fun read -> read.bool "accepted")
|
||||
|> Sql.executeAsync (fun read -> read.bool "accepted")
|
||||
|> Async.AwaitTask
|
||||
return result
|
||||
with ex ->
|
||||
printfn "%s %u" ex.Message userId
|
||||
return false
|
||||
return List.tryHead result |> Option.defaultValue false
|
||||
}
|
||||
|
||||
let private getInviteAttributions userId =
|
||||
@ -279,10 +281,20 @@ let private processNewUser (eventArgs : GuildMemberAddEventArgs) =
|
||||
for invite in guildInvites do
|
||||
let result = cachedInvites.TryFind(invite.Code)
|
||||
match result with
|
||||
| Some (_,count) ->
|
||||
| Some (inviterId,count) ->
|
||||
if invite.Uses > count then
|
||||
do! addInvitedUser eventArgs.Member.Id invite.Code invite.Uses |> Async.Ignore
|
||||
do! Analytics.invitedUserEntered invite.Code invite.Inviter.Id eventArgs.Member.Id invite.Inviter.Username eventArgs.Member.Username
|
||||
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
|
||||
|
||||
@ -290,7 +302,7 @@ let acceptInvite (guild : DiscordGuild) (user : DiscordMember) =
|
||||
task {
|
||||
match! checkInviteAccepted user.Id with
|
||||
| false ->
|
||||
let! _ = markInvitedAccepted user.Id |> Async.Ignore
|
||||
do! markInvitedAccepted user.Id |> Async.Ignore
|
||||
try
|
||||
let! invite = getInviteFromInvitedUser user.Id
|
||||
let! player = DbService.tryFindPlayer invite.Inviter
|
||||
@ -310,18 +322,20 @@ let acceptInvite (guild : DiscordGuild) (user : DiscordMember) =
|
||||
let role3x = guild.Roles.TryGetValue(GuildEnvironment.roleRecruiter3x) |> snd
|
||||
let role2x = guild.Roles.TryGetValue(GuildEnvironment.roleRecruiter2x) |> snd
|
||||
let role1x = guild.Roles.TryGetValue(GuildEnvironment.roleRecruiter1x) |> snd
|
||||
match invite.Count with
|
||||
| count when count > 10 ->
|
||||
do! [ user.GrantRoleAsync(role3x) ; user.RevokeRoleAsync(role2x) ; user.RevokeRoleAsync(role1x) ]
|
||||
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
|
||||
| count when count > 5 ->
|
||||
do! [ user.GrantRoleAsync(role2x) ; user.RevokeRoleAsync(role1x) ]
|
||||
elif totalInvites >= 5 then
|
||||
do! [ playerMember.GrantRoleAsync(role2x) ; playerMember.RevokeRoleAsync(role1x) ]
|
||||
|> List.map Async.AwaitTask
|
||||
|> Async.Parallel
|
||||
|> Async.Ignore
|
||||
| _ -> do! user.GrantRoleAsync(role1x)
|
||||
else
|
||||
do! playerMember.GrantRoleAsync(role1x)
|
||||
do! Analytics.invitedUserAccepted invite.Code player.DiscordId user.Id player.Name user.Username
|
||||
| None -> return ()
|
||||
with _ -> ()
|
||||
@ -343,6 +357,9 @@ let sendInitialEmbed (ctx : IDiscordContext) =
|
||||
|
||||
**__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*
|
||||
"""
|
||||
@ -370,7 +387,7 @@ let showWalletStatus (ctx : IDiscordContext) =
|
||||
try
|
||||
match! getWalletAddress player.DiscordId with
|
||||
| Some address -> do! Messaging.sendFollowUpMessage ctx $"""
|
||||
🚀 __Mint Date:__ Mid June
|
||||
🚀 __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 ->
|
||||
@ -473,12 +490,7 @@ let handleMessageCreated _ (event : MessageCreateEventArgs) =
|
||||
do! event.Message.DeleteAsync()
|
||||
} :> Task
|
||||
|
||||
let handleGuildMemberAdded _ (eventArgs : GuildMemberAddEventArgs) =
|
||||
task {
|
||||
let! exists = checkUserAlreadyInvited eventArgs.Member.Id
|
||||
if not exists then
|
||||
do! processNewUser eventArgs
|
||||
} :> Task
|
||||
let handleGuildMemberAdded _ (eventArgs : GuildMemberAddEventArgs) = processNewUser eventArgs
|
||||
|
||||
let submitAddress (address : string) (ctx : IDiscordContext) =
|
||||
PlayerInteractions.executePlayerAction ctx (fun player -> async {
|
||||
@ -505,9 +517,8 @@ let submitAddress (address : string) (ctx : IDiscordContext) =
|
||||
let role = ctx.GetGuild().GetRole(GuildEnvironment.roleWhiteOGPending)
|
||||
do! user.RevokeRoleAsync(role) |> Async.AwaitTask
|
||||
|
||||
|
||||
do! Messaging.sendFollowUpMessage ctx $"""
|
||||
🚀 __Mint Date:__ Mid June
|
||||
🚀 __Mint Date:__ June 20th
|
||||
✅ {msg} {address}
|
||||
|
||||
Keep an eye on <#{GuildEnvironment.channelAnnouncements}> for updates."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user