diff --git a/app/http/endpoints/api/panel/multipanelmessagedata.go b/app/http/endpoints/api/panel/multipanelmessagedata.go index 727ce41..221a8cb 100644 --- a/app/http/endpoints/api/panel/multipanelmessagedata.go +++ b/app/http/endpoints/api/panel/multipanelmessagedata.go @@ -2,9 +2,9 @@ package api import ( "github.com/TicketsBot/GoPanel/botcontext" + "github.com/TicketsBot/GoPanel/utils/types" "github.com/TicketsBot/database" "github.com/rxdn/gdl/objects/channel/embed" - "github.com/rxdn/gdl/objects/guild/emoji" "github.com/rxdn/gdl/objects/interaction/component" "github.com/rxdn/gdl/rest" "github.com/rxdn/gdl/utils" @@ -58,17 +58,12 @@ func (d *multiPanelMessageData) send(ctx *botcontext.BotContext, panels []databa if d.SelectMenu { options := make([]component.SelectOption, len(panels)) for i, panel := range panels { - var emote *emoji.Emoji - if panel.ReactionEmote != "" { - emote = &emoji.Emoji{ - Name: panel.ReactionEmote, - } - } + emoji := types.NewEmoji(panel.EmojiName, panel.EmojiId).IntoGdl() options[i] = component.SelectOption{ Label: panel.ButtonLabel, Value: panel.CustomId, - Emoji: emote, + Emoji: emoji, } } @@ -88,18 +83,13 @@ func (d *multiPanelMessageData) send(ctx *botcontext.BotContext, panels []databa } else { buttons := make([]component.Component, len(panels)) for i, panel := range panels { - var buttonEmoji *emoji.Emoji - if panel.ReactionEmote != "" { - buttonEmoji = &emoji.Emoji{ - Name: panel.ReactionEmote, - } - } + emoji := types.NewEmoji(panel.EmojiName, panel.EmojiId).IntoGdl() buttons[i] = component.BuildButton(component.Button{ Label: panel.ButtonLabel, CustomId: panel.CustomId, Style: component.ButtonStyle(panel.ButtonStyle), - Emoji: buttonEmoji, + Emoji: emoji, }) } diff --git a/app/http/endpoints/api/panel/panelcreate.go b/app/http/endpoints/api/panel/panelcreate.go index 2a12696..67d9133 100644 --- a/app/http/endpoints/api/panel/panelcreate.go +++ b/app/http/endpoints/api/panel/panelcreate.go @@ -2,17 +2,18 @@ package api import ( "errors" - "fmt" "github.com/TicketsBot/GoPanel/botcontext" dbclient "github.com/TicketsBot/GoPanel/database" "github.com/TicketsBot/GoPanel/rpc" "github.com/TicketsBot/GoPanel/rpc/cache" "github.com/TicketsBot/GoPanel/utils" + "github.com/TicketsBot/GoPanel/utils/types" "github.com/TicketsBot/common/collections" "github.com/TicketsBot/common/premium" "github.com/TicketsBot/database" "github.com/gin-gonic/gin" "github.com/rxdn/gdl/objects/channel" + "github.com/rxdn/gdl/objects/guild/emoji" "github.com/rxdn/gdl/objects/interaction/component" "github.com/rxdn/gdl/rest/request" "regexp" @@ -29,7 +30,7 @@ type panelBody struct { Content string `json:"content"` Colour uint32 `json:"colour"` CategoryId uint64 `json:"category_id,string"` - Emote string `json:"emote"` + Emoji types.Emoji `json:"emote"` WelcomeMessage *string `json:"welcome_message"` Mentions []string `json:"mentions"` WithDefaultTeam bool `json:"default_team"` @@ -42,11 +43,6 @@ type panelBody struct { } func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData { - var emoji *string - if p.Emote != "" { - emoji = &p.Emote - } - return panelMessageData{ ChannelId: p.ChannelId, Title: p.Title, @@ -55,7 +51,7 @@ func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelM Colour: int(p.Colour), ImageUrl: p.ImageUrl, ThumbnailUrl: p.ThumbnailUrl, - Emoji: emoji, + Emoji: p.getEmoji(), ButtonStyle: p.ButtonStyle, ButtonLabel: p.ButtonLabel, IsPremium: isPremium, @@ -111,26 +107,33 @@ func CreatePanel(ctx *gin.Context) { customId := utils.RandString(80) - emoji, _ := data.getEmoji() // already validated - data.Emote = emoji - messageData := data.IntoPanelMessageData(customId, premiumTier > premium.None) msgId, err := messageData.send(&botContext) if err != nil { var unwrapped request.RestError if errors.As(err, &unwrapped) && unwrapped.StatusCode == 403 { - ctx.AbortWithStatusJSON(500, utils.ErrorStr("I do not have permission to send messages in the specified channel")) + ctx.JSON(500, utils.ErrorStr("I do not have permission to send messages in the specified channel")) } else { // TODO: Most appropriate error? - ctx.AbortWithStatusJSON(500, gin.H{ - "success": false, - "error": err.Error(), - }) + ctx.JSON(500, utils.ErrorJson(err)) } return } + var emojiId *uint64 + var emojiName *string + { + emoji := data.getEmoji() + if emoji != nil { + emojiName = &emoji.Name + + if emoji.Id.Value != 0 { + emojiId = &emoji.Id.Value + } + } + } + // Store in DB panel := database.Panel{ MessageId: msgId, @@ -140,7 +143,8 @@ func CreatePanel(ctx *gin.Context) { Content: data.Content, Colour: int32(data.Colour), TargetCategory: data.CategoryId, - ReactionEmote: emoji, + EmojiId: emojiId, + EmojiName: emojiName, WelcomeMessage: data.WelcomeMessage, WithDefaultTeam: data.WithDefaultTeam, CustomId: customId, @@ -208,6 +212,11 @@ func CreatePanel(ctx *gin.Context) { var urlRegex = regexp.MustCompile(`^https?://([-a-zA-Z0-9@:%._+~#=]{1,256})\.[a-zA-Z0-9()]{1,63}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)$`) func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { + botContext, err := botcontext.ContextForGuild(guildId) + if err != nil { + return false // TODO: Log error + } + if !p.verifyTitle() { ctx.AbortWithStatusJSON(400, gin.H{ "success": false, @@ -227,34 +236,22 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { channels := cache.Instance.GetGuildChannels(guildId) if !p.verifyChannel(channels) { - ctx.AbortWithStatusJSON(400, gin.H{ - "success": false, - "error": "Invalid channel", - }) + ctx.JSON(400, utils.ErrorStr("Invalid channel")) return false } if !p.verifyCategory(channels) { - ctx.AbortWithStatusJSON(400, gin.H{ - "success": false, - "error": "Invalid channel category", - }) + ctx.JSON(400, utils.ErrorStr("Invalid channel category")) return false } - if p.Emote != "" { // Allow no emoji - _, validEmoji := p.getEmoji() - if !validEmoji { - ctx.AbortWithStatusJSON(400, gin.H{ - "success": false, - "error": "Invalid emoji. Simply use the emoji itself, or the emoji's name from Discord.", - }) - return false - } + if !p.verifyEmoji(botContext, guildId) { + ctx.JSON(400, utils.ErrorStr("Invalid emoji")) + return false } if !p.verifyWelcomeMessage() { - ctx.AbortWithStatusJSON(400, gin.H{ + ctx.JSON(400, gin.H{ "success": false, "error": "Welcome message must be blank or between 1 - 4096 characters", }) @@ -262,7 +259,7 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { } if !p.verifyImageUrl() || !p.verifyThumbnailUrl() { - ctx.AbortWithStatusJSON(400, gin.H{ + ctx.JSON(400, gin.H{ "success": false, "error": "Image URL must be between 1 - 255 characters and a valid URL", }) @@ -270,7 +267,7 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { } if !p.verifyButtonStyle() { - ctx.AbortWithStatusJSON(400, gin.H{ + ctx.JSON(400, gin.H{ "success": false, "error": "Invalid button style", }) @@ -278,20 +275,19 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { } if !p.verifyButtonLabel() { - ctx.AbortWithStatusJSON(400, utils.ErrorStr("Button labels cannot be longer than 80 characters")) + ctx.JSON(400, utils.ErrorStr("Button labels cannot be longer than 80 characters")) return false } - fmt.Printf("label: %s\n", p.ButtonLabel) { valid, err := p.verifyTeams(guildId) if err != nil { - ctx.AbortWithStatusJSON(500, utils.ErrorJson(err)) + ctx.JSON(500, utils.ErrorJson(err)) return false } if !valid { - ctx.AbortWithStatusJSON(400, utils.ErrorStr("Invalid teams provided")) + ctx.JSON(400, utils.ErrorStr("Invalid teams provided")) return false } } @@ -299,12 +295,12 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { { ok, err := p.verifyFormId(guildId) if err != nil { - ctx.AbortWithStatusJSON(500, utils.ErrorJson(err)) + ctx.JSON(500, utils.ErrorJson(err)) return false } if !ok { - ctx.AbortWithStatusJSON(400, utils.ErrorStr("Guild ID for form does not match")) + ctx.JSON(400, utils.ErrorStr("Guild ID for form does not match")) return false } } @@ -332,12 +328,9 @@ func (p *panelBody) verifyContent() bool { return true } -func (p *panelBody) getEmoji() (emoji string, ok bool) { - p.Emote = strings.TrimSpace(p.Emote) - p.Emote = strings.Replace(p.Emote, ":", "", -1) - - emoji, ok = utils.GetEmoji(p.Emote) - return +// Data must be validated before calling this function +func (p *panelBody) getEmoji() *emoji.Emoji { + return p.Emoji.IntoGdl() } func (p *panelBody) verifyChannel(channels []channel.Channel) bool { @@ -364,6 +357,45 @@ func (p *panelBody) verifyCategory(channels []channel.Channel) bool { return valid } +func (p *panelBody) verifyEmoji(ctx botcontext.BotContext, guildId uint64) bool { + if p.Emoji.IsCustomEmoji { + if p.Emoji.Id == nil { + return false + } + + emoji, err := ctx.GetGuildEmoji(guildId, *p.Emoji.Id) + if err != nil { // TODO: Log + return false + } + + if emoji.Id.Value == 0 { + return false + } + + if emoji.Name != p.Emoji.Name { + return false + } + + return true + } else { + if len(p.Emoji.Name) == 0 { + return true + } + + // Convert from :emoji: to unicode if we need to + name := strings.TrimSpace(p.Emoji.Name) + name = strings.Replace(name, ":", "", -1) + + unicode, ok := utils.GetEmoji(name) + if !ok { + return false + } + + p.Emoji.Name = unicode + return true + } +} + func (p *panelBody) verifyWelcomeMessage() bool { return p.WelcomeMessage == nil || (len(*p.WelcomeMessage) > 0 && len(*p.WelcomeMessage) <= 4096) } diff --git a/app/http/endpoints/api/panel/paneldelete.go b/app/http/endpoints/api/panel/paneldelete.go index c0b1fb1..1e37e10 100644 --- a/app/http/endpoints/api/panel/paneldelete.go +++ b/app/http/endpoints/api/panel/paneldelete.go @@ -1,8 +1,12 @@ package api import ( + "fmt" "github.com/TicketsBot/GoPanel/botcontext" "github.com/TicketsBot/GoPanel/database" + "github.com/TicketsBot/GoPanel/rpc" + "github.com/TicketsBot/GoPanel/utils" + "github.com/TicketsBot/common/premium" "github.com/gin-gonic/gin" "github.com/rxdn/gdl/rest" "strconv" @@ -13,57 +17,89 @@ func DeletePanel(ctx *gin.Context) { botContext, err := botcontext.ContextForGuild(guildId) if err != nil { - ctx.AbortWithStatusJSON(500, gin.H{ - "success": false, - "error": err.Error(), - }) + ctx.JSON(500, utils.ErrorJson(err)) return } panelId, err := strconv.Atoi(ctx.Param("panelid")) if err != nil { - ctx.AbortWithStatusJSON(400, gin.H{ - "success": false, - "error": err.Error(), - }) + ctx.JSON(400, utils.ErrorJson(err)) return } panel, err := database.Client.Panel.GetById(panelId) if err != nil { - ctx.JSON(500, gin.H{ - "success": false, - "error": err.Error(), - }) + ctx.JSON(500, utils.ErrorJson(err)) return } // verify panel belongs to guild if panel.GuildId != guildId { - ctx.AbortWithStatusJSON(403, gin.H{ - "success": false, - "error": "Guild ID doesn't match", - }) + ctx.JSON(403, utils.ErrorStr("Guild ID doesn't match")) return } - if err := database.Client.Panel.Delete(panelId); err != nil { - ctx.JSON(500, gin.H{ - "success": false, - "error": err.Error(), - }) + // Get any multi panels this panel is part of to use later + multiPanels, err := database.Client.MultiPanelTargets.GetMultiPanels(panelId) + if err != nil { + fmt.Println(err.Error()) + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + if err := database.Client.Panel.Delete(panelId); err != nil { + ctx.JSON(500, utils.ErrorJson(err)) return } if err := rest.DeleteMessage(botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil { - ctx.JSON(500, gin.H{ - "success": false, - "error": err.Error(), - }) + ctx.JSON(500, utils.ErrorJson(err)) return } - ctx.JSON(200, gin.H{ - "success": true, - }) + // Get premium tier + premiumTier, err := rpc.PremiumClient.GetTierByGuildId(guildId, true, botContext.Token, botContext.RateLimiter) + if err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + // Update all multi panels messages to remove the button + for i, multiPanel := range multiPanels { + // Only update 5 multi-panels maximum: Prevent DoS + if i >= 5 { + break + } + + panels, err := database.Client.MultiPanelTargets.GetPanels(multiPanel.Id) + if err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + messageData := multiPanelMessageData{ + Title: multiPanel.Title, + Content: multiPanel.Content, + Colour: multiPanel.Colour, + ChannelId: multiPanel.ChannelId, + SelectMenu: multiPanel.SelectMenu, + IsPremium: premiumTier > premium.None, + } + + messageId, err := messageData.send(&botContext, panels) + if err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + if err := database.Client.MultiPanels.UpdateMessageId(multiPanel.Id, messageId); err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + // Delete old panel + _ = rest.DeleteMessage(botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId) + } + + ctx.JSON(200, utils.SuccessResponse) } diff --git a/app/http/endpoints/api/panel/panellist.go b/app/http/endpoints/api/panel/panellist.go index d398851..c85d954 100644 --- a/app/http/endpoints/api/panel/panellist.go +++ b/app/http/endpoints/api/panel/panellist.go @@ -3,6 +3,7 @@ package api import ( "context" dbclient "github.com/TicketsBot/GoPanel/database" + "github.com/TicketsBot/GoPanel/utils/types" "github.com/TicketsBot/database" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" @@ -12,9 +13,10 @@ import ( func ListPanels(ctx *gin.Context) { type panelResponse struct { database.Panel - Mentions []string `json:"mentions"` - //Teams []database.SupportTeam `json:"teams"` - Teams []int `json:"teams"` + UseCustomEmoji bool `json:"use_custom_emoji"` + Emoji types.Emoji `json:"emote"` + Mentions []string `json:"mentions"` + Teams []int `json:"teams"` } guildId := ctx.Keys["guildid"].(uint64) @@ -72,9 +74,11 @@ func ListPanels(ctx *gin.Context) { } wrapped[i] = panelResponse{ - Panel: p, - Mentions: mentions, - Teams: teamIds, + Panel: p, + UseCustomEmoji: p.EmojiId != nil, + Emoji: types.NewEmoji(p.EmojiName, p.EmojiId), + Mentions: mentions, + Teams: teamIds, } return nil diff --git a/app/http/endpoints/api/panel/panelmessagedata.go b/app/http/endpoints/api/panel/panelmessagedata.go index c537824..3f8871e 100644 --- a/app/http/endpoints/api/panel/panelmessagedata.go +++ b/app/http/endpoints/api/panel/panelmessagedata.go @@ -3,6 +3,7 @@ package api import ( "github.com/TicketsBot/GoPanel/botcontext" "github.com/TicketsBot/database" + "github.com/rxdn/gdl/objects" "github.com/rxdn/gdl/objects/channel/embed" "github.com/rxdn/gdl/objects/guild/emoji" "github.com/rxdn/gdl/objects/interaction/component" @@ -12,18 +13,27 @@ import ( type panelMessageData struct { ChannelId uint64 - Title, Content, CustomId string - Colour int - ImageUrl, ThumbnailUrl, Emoji *string - ButtonStyle component.ButtonStyle - ButtonLabel string - IsPremium bool + Title, Content, CustomId string + Colour int + ImageUrl, ThumbnailUrl *string + Emoji *emoji.Emoji + ButtonStyle component.ButtonStyle + ButtonLabel string + IsPremium bool } func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData { - var emoji *string - if panel.ReactionEmote != "" { - emoji = &panel.ReactionEmote + var emote *emoji.Emoji + if panel.EmojiName != nil && *panel.EmojiName == "" { // No emoji = nil + id := objects.NewNullSnowflake() + if panel.EmojiId != nil { + id = objects.NewNullableSnowflake(*panel.EmojiId) + } + + emote = &emoji.Emoji{ + Id: id, + Name: *panel.EmojiName, + } } return panelMessageData{ @@ -34,7 +44,7 @@ func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData Colour: int(panel.Colour), ImageUrl: panel.ImageUrl, ThumbnailUrl: panel.ThumbnailUrl, - Emoji: emoji, + Emoji: emote, ButtonStyle: component.ButtonStyle(panel.ButtonStyle), ButtonLabel: panel.ButtonLabel, IsPremium: isPremium, @@ -59,13 +69,6 @@ func (p *panelMessageData) send(ctx *botcontext.BotContext) (uint64, error) { e.SetFooter("Powered by ticketsbot.net", "https://ticketsbot.net/assets/img/logo.png") } - var buttonEmoji *emoji.Emoji - if p.Emoji != nil { - buttonEmoji = &emoji.Emoji{ - Name: *p.Emoji, - } - } - data := rest.CreateMessageData{ Embeds: []*embed.Embed{e}, Components: []component.Component{ @@ -73,7 +76,7 @@ func (p *panelMessageData) send(ctx *botcontext.BotContext) (uint64, error) { Label: p.ButtonLabel, CustomId: p.CustomId, Style: p.ButtonStyle, - Emoji: buttonEmoji, + Emoji: p.Emoji, Url: nil, Disabled: false, })), diff --git a/app/http/endpoints/api/panel/panelupdate.go b/app/http/endpoints/api/panel/panelupdate.go index 4f316f7..599c9b2 100644 --- a/app/http/endpoints/api/panel/panelupdate.go +++ b/app/http/endpoints/api/panel/panelupdate.go @@ -53,49 +53,23 @@ func UpdatePanel(ctx *gin.Context) { return } - // check if this will break a multi-panel; - // first, get any multipanels this panel belongs to - multiPanels, err := dbclient.Client.MultiPanelTargets.GetMultiPanels(existing.PanelId) - if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) - return - } - premiumTier, err := rpc.PremiumClient.GetTierByGuildId(guildId, true, botContext.Token, botContext.RateLimiter) if err != nil { ctx.JSON(500, utils.ErrorJson(err)) return } - for _, multiPanel := range multiPanels { - panels, err := dbclient.Client.MultiPanelTargets.GetPanels(multiPanel.Id) - if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) - return - } + var emojiId *uint64 + var emojiName *string + { + emoji := data.getEmoji() + if emoji != nil { + emojiName = &emoji.Name - messageData := multiPanelMessageData{ - Title: multiPanel.Title, - Content: multiPanel.Content, - Colour: multiPanel.Colour, - ChannelId: multiPanel.ChannelId, - SelectMenu: multiPanel.SelectMenu, - IsPremium: premiumTier > premium.None, + if emoji.Id.Value != 0 { + emojiId = &emoji.Id.Value + } } - - messageId, err := messageData.send(&botContext, panels) - if err != nil { - ctx.JSON(500, utils.ErrorJson(err)) - return - } - - if err := dbclient.Client.MultiPanels.UpdateMessageId(multiPanel.Id, messageId); err != nil { - ctx.JSON(500, utils.ErrorJson(err)) - return - } - - // Delete old panel - _ = rest.DeleteMessage(botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId) } // check if we need to update the message @@ -103,13 +77,13 @@ func UpdatePanel(ctx *gin.Context) { existing.ChannelId != data.ChannelId || existing.Content != data.Content || existing.Title != data.Title || - existing.ReactionEmote != data.Emote || + (existing.EmojiId == nil && emojiId != nil || existing.EmojiId != nil && emojiId == nil || (existing.EmojiId != nil && emojiId != nil && *existing.EmojiId != *emojiId)) || + (existing.EmojiName == nil && emojiName != nil || existing.EmojiName != nil && emojiName == nil || (existing.EmojiName != nil && emojiName != nil && *existing.EmojiName != *emojiName)) || existing.ImageUrl != data.ImageUrl || existing.ThumbnailUrl != data.ThumbnailUrl || component.ButtonStyle(existing.ButtonStyle) != data.ButtonStyle || existing.ButtonLabel != data.ButtonLabel - emoji, _ := data.getEmoji() // already validated newMessageId := existing.MessageId if shouldUpdateMessage { @@ -141,7 +115,8 @@ func UpdatePanel(ctx *gin.Context) { Content: data.Content, Colour: int32(data.Colour), TargetCategory: data.CategoryId, - ReactionEmote: emoji, + EmojiName: emojiName, + EmojiId: emojiId, WelcomeMessage: data.WelcomeMessage, WithDefaultTeam: data.WithDefaultTeam, CustomId: existing.CustomId, @@ -199,5 +174,51 @@ func UpdatePanel(ctx *gin.Context) { return } + // Update multi panels + + // check if this will break a multi-panel; + // first, get any multipanels this panel belongs to + multiPanels, err := dbclient.Client.MultiPanelTargets.GetMultiPanels(existing.PanelId) + if err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + for i, multiPanel := range multiPanels { + // Only update 5 multi-panels maximum: Prevent DoS + if i >= 5 { + break + } + + panels, err := dbclient.Client.MultiPanelTargets.GetPanels(multiPanel.Id) + if err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + messageData := multiPanelMessageData{ + Title: multiPanel.Title, + Content: multiPanel.Content, + Colour: multiPanel.Colour, + ChannelId: multiPanel.ChannelId, + SelectMenu: multiPanel.SelectMenu, + IsPremium: premiumTier > premium.None, + } + + messageId, err := messageData.send(&botContext, panels) + if err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + if err := dbclient.Client.MultiPanels.UpdateMessageId(multiPanel.Id, messageId); err != nil { + ctx.JSON(500, utils.ErrorJson(err)) + return + } + + // Delete old panel + _ = rest.DeleteMessage(botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId) + } + ctx.JSON(200, utils.SuccessResponse) } diff --git a/botcontext/botcontext.go b/botcontext/botcontext.go index 068ad37..291d2e7 100644 --- a/botcontext/botcontext.go +++ b/botcontext/botcontext.go @@ -101,6 +101,19 @@ func (ctx BotContext) GetGuildRoles(guildId uint64) (roles []guild.Role, err err return } +func (ctx BotContext) GetGuildEmoji(guildId, emojiId uint64) (emoji.Emoji, error) { + if emoji, ok := cache.Instance.GetEmoji(guildId); ok { + return emoji, nil + } + + emoji, err := rest.GetGuildEmoji(ctx.Token, ctx.RateLimiter, guildId, emojiId) + if err == nil { + go cache.Instance.StoreEmoji(emoji, guildId) + } + + return emoji, err +} + func (ctx BotContext) GetGuildEmojis(guildId uint64) (emojis []emoji.Emoji, err error) { if emojis := cache.Instance.GetGuildEmojis(guildId); len(emojis) > 0 { return emojis, nil diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 81d60b4..7d10704 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,7 +27,8 @@ "rollup-plugin-livereload": "^2.0.0", "rollup-plugin-svelte": "^7.1.0", "rollup-plugin-terser": "^7.0.0", - "svelte": "^3.48.0" + "svelte": "^3.48.0", + "svelte-toggle": "^3.1.0" } }, "node_modules/@babel/code-frame": { @@ -3169,6 +3170,12 @@ "resolved": "https://registry.npmjs.org/svelte-tabs/-/svelte-tabs-1.1.0.tgz", "integrity": "sha512-bCynxgET2uvqpB6xf/dVyqHjzmumRURQyh2QqXlrki8NxzO7h2WghF8qgpb5qeB5NTX1bMU+9Q5Hf5ey2WLaMg==" }, + "node_modules/svelte-toggle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/svelte-toggle/-/svelte-toggle-3.1.0.tgz", + "integrity": "sha512-2gzDDMDhM+ImDaLEZVlnlHVY1340Y368tT4Qk5IwLnCeRJ4zV3cVwliVGacoHy7iCDukcGXzKwDzG/hTTcaljg==", + "dev": true + }, "node_modules/terser": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", @@ -5593,6 +5600,12 @@ "resolved": "https://registry.npmjs.org/svelte-tabs/-/svelte-tabs-1.1.0.tgz", "integrity": "sha512-bCynxgET2uvqpB6xf/dVyqHjzmumRURQyh2QqXlrki8NxzO7h2WghF8qgpb5qeB5NTX1bMU+9Q5Hf5ey2WLaMg==" }, + "svelte-toggle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/svelte-toggle/-/svelte-toggle-3.1.0.tgz", + "integrity": "sha512-2gzDDMDhM+ImDaLEZVlnlHVY1340Y368tT4Qk5IwLnCeRJ4zV3cVwliVGacoHy7iCDukcGXzKwDzG/hTTcaljg==", + "dev": true + }, "terser": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5fd6213..6e8f2fe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,7 +20,8 @@ "rollup-plugin-livereload": "^2.0.0", "rollup-plugin-svelte": "^7.1.0", "rollup-plugin-terser": "^7.0.0", - "svelte": "^3.48.0" + "svelte": "^3.48.0", + "svelte-toggle": "^3.1.0" }, "dependencies": { "axios": "^0.21.4", diff --git a/frontend/src/components/form/EmojiInput.svelte b/frontend/src/components/form/EmojiInput.svelte index d26c9ff..d90b9a0 100644 --- a/frontend/src/components/form/EmojiInput.svelte +++ b/frontend/src/components/form/EmojiInput.svelte @@ -5,7 +5,9 @@
{#if !disabled} - +
+ +
{/if}
@@ -49,9 +51,14 @@ border-left: none; color: white; z-index: 2; + height: 100%; } :global(.svelte-emoji-picker__trigger:active) { background-color: #2e3136 !important; } + + .picker-wrapper { + max-height: 40px; + } \ No newline at end of file diff --git a/frontend/src/components/form/Slider.svelte b/frontend/src/components/form/Slider.svelte index 55486c0..8de13ec 100644 --- a/frontend/src/components/form/Slider.svelte +++ b/frontend/src/components/form/Slider.svelte @@ -1,6 +1,6 @@
- + console.log('b')} />
diff --git a/frontend/src/components/manage/PanelCreationForm.svelte b/frontend/src/components/manage/PanelCreationForm.svelte index 76c7f4a..74defff 100644 --- a/frontend/src/components/manage/PanelCreationForm.svelte +++ b/frontend/src/components/manage/PanelCreationForm.svelte @@ -33,7 +33,12 @@
- + +
{#if data.use_custom_emoji}