Custom emojis
This commit is contained in:
parent
5d27ca2583
commit
b8d2bf03ff
@ -2,9 +2,9 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/TicketsBot/GoPanel/botcontext"
|
"github.com/TicketsBot/GoPanel/botcontext"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils/types"
|
||||||
"github.com/TicketsBot/database"
|
"github.com/TicketsBot/database"
|
||||||
"github.com/rxdn/gdl/objects/channel/embed"
|
"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/objects/interaction/component"
|
||||||
"github.com/rxdn/gdl/rest"
|
"github.com/rxdn/gdl/rest"
|
||||||
"github.com/rxdn/gdl/utils"
|
"github.com/rxdn/gdl/utils"
|
||||||
@ -58,17 +58,12 @@ func (d *multiPanelMessageData) send(ctx *botcontext.BotContext, panels []databa
|
|||||||
if d.SelectMenu {
|
if d.SelectMenu {
|
||||||
options := make([]component.SelectOption, len(panels))
|
options := make([]component.SelectOption, len(panels))
|
||||||
for i, panel := range panels {
|
for i, panel := range panels {
|
||||||
var emote *emoji.Emoji
|
emoji := types.NewEmoji(panel.EmojiName, panel.EmojiId).IntoGdl()
|
||||||
if panel.ReactionEmote != "" {
|
|
||||||
emote = &emoji.Emoji{
|
|
||||||
Name: panel.ReactionEmote,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
options[i] = component.SelectOption{
|
options[i] = component.SelectOption{
|
||||||
Label: panel.ButtonLabel,
|
Label: panel.ButtonLabel,
|
||||||
Value: panel.CustomId,
|
Value: panel.CustomId,
|
||||||
Emoji: emote,
|
Emoji: emoji,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,18 +83,13 @@ func (d *multiPanelMessageData) send(ctx *botcontext.BotContext, panels []databa
|
|||||||
} else {
|
} else {
|
||||||
buttons := make([]component.Component, len(panels))
|
buttons := make([]component.Component, len(panels))
|
||||||
for i, panel := range panels {
|
for i, panel := range panels {
|
||||||
var buttonEmoji *emoji.Emoji
|
emoji := types.NewEmoji(panel.EmojiName, panel.EmojiId).IntoGdl()
|
||||||
if panel.ReactionEmote != "" {
|
|
||||||
buttonEmoji = &emoji.Emoji{
|
|
||||||
Name: panel.ReactionEmote,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons[i] = component.BuildButton(component.Button{
|
buttons[i] = component.BuildButton(component.Button{
|
||||||
Label: panel.ButtonLabel,
|
Label: panel.ButtonLabel,
|
||||||
CustomId: panel.CustomId,
|
CustomId: panel.CustomId,
|
||||||
Style: component.ButtonStyle(panel.ButtonStyle),
|
Style: component.ButtonStyle(panel.ButtonStyle),
|
||||||
Emoji: buttonEmoji,
|
Emoji: emoji,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,17 +2,18 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"github.com/TicketsBot/GoPanel/botcontext"
|
"github.com/TicketsBot/GoPanel/botcontext"
|
||||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
"github.com/TicketsBot/GoPanel/rpc"
|
"github.com/TicketsBot/GoPanel/rpc"
|
||||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||||
"github.com/TicketsBot/GoPanel/utils"
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils/types"
|
||||||
"github.com/TicketsBot/common/collections"
|
"github.com/TicketsBot/common/collections"
|
||||||
"github.com/TicketsBot/common/premium"
|
"github.com/TicketsBot/common/premium"
|
||||||
"github.com/TicketsBot/database"
|
"github.com/TicketsBot/database"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rxdn/gdl/objects/channel"
|
"github.com/rxdn/gdl/objects/channel"
|
||||||
|
"github.com/rxdn/gdl/objects/guild/emoji"
|
||||||
"github.com/rxdn/gdl/objects/interaction/component"
|
"github.com/rxdn/gdl/objects/interaction/component"
|
||||||
"github.com/rxdn/gdl/rest/request"
|
"github.com/rxdn/gdl/rest/request"
|
||||||
"regexp"
|
"regexp"
|
||||||
@ -29,7 +30,7 @@ type panelBody struct {
|
|||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
Colour uint32 `json:"colour"`
|
Colour uint32 `json:"colour"`
|
||||||
CategoryId uint64 `json:"category_id,string"`
|
CategoryId uint64 `json:"category_id,string"`
|
||||||
Emote string `json:"emote"`
|
Emoji types.Emoji `json:"emote"`
|
||||||
WelcomeMessage *string `json:"welcome_message"`
|
WelcomeMessage *string `json:"welcome_message"`
|
||||||
Mentions []string `json:"mentions"`
|
Mentions []string `json:"mentions"`
|
||||||
WithDefaultTeam bool `json:"default_team"`
|
WithDefaultTeam bool `json:"default_team"`
|
||||||
@ -42,11 +43,6 @@ type panelBody struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData {
|
func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData {
|
||||||
var emoji *string
|
|
||||||
if p.Emote != "" {
|
|
||||||
emoji = &p.Emote
|
|
||||||
}
|
|
||||||
|
|
||||||
return panelMessageData{
|
return panelMessageData{
|
||||||
ChannelId: p.ChannelId,
|
ChannelId: p.ChannelId,
|
||||||
Title: p.Title,
|
Title: p.Title,
|
||||||
@ -55,7 +51,7 @@ func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelM
|
|||||||
Colour: int(p.Colour),
|
Colour: int(p.Colour),
|
||||||
ImageUrl: p.ImageUrl,
|
ImageUrl: p.ImageUrl,
|
||||||
ThumbnailUrl: p.ThumbnailUrl,
|
ThumbnailUrl: p.ThumbnailUrl,
|
||||||
Emoji: emoji,
|
Emoji: p.getEmoji(),
|
||||||
ButtonStyle: p.ButtonStyle,
|
ButtonStyle: p.ButtonStyle,
|
||||||
ButtonLabel: p.ButtonLabel,
|
ButtonLabel: p.ButtonLabel,
|
||||||
IsPremium: isPremium,
|
IsPremium: isPremium,
|
||||||
@ -111,26 +107,33 @@ func CreatePanel(ctx *gin.Context) {
|
|||||||
|
|
||||||
customId := utils.RandString(80)
|
customId := utils.RandString(80)
|
||||||
|
|
||||||
emoji, _ := data.getEmoji() // already validated
|
|
||||||
data.Emote = emoji
|
|
||||||
|
|
||||||
messageData := data.IntoPanelMessageData(customId, premiumTier > premium.None)
|
messageData := data.IntoPanelMessageData(customId, premiumTier > premium.None)
|
||||||
msgId, err := messageData.send(&botContext)
|
msgId, err := messageData.send(&botContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var unwrapped request.RestError
|
var unwrapped request.RestError
|
||||||
if errors.As(err, &unwrapped) && unwrapped.StatusCode == 403 {
|
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 {
|
} else {
|
||||||
// TODO: Most appropriate error?
|
// TODO: Most appropriate error?
|
||||||
ctx.AbortWithStatusJSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
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
|
// Store in DB
|
||||||
panel := database.Panel{
|
panel := database.Panel{
|
||||||
MessageId: msgId,
|
MessageId: msgId,
|
||||||
@ -140,7 +143,8 @@ func CreatePanel(ctx *gin.Context) {
|
|||||||
Content: data.Content,
|
Content: data.Content,
|
||||||
Colour: int32(data.Colour),
|
Colour: int32(data.Colour),
|
||||||
TargetCategory: data.CategoryId,
|
TargetCategory: data.CategoryId,
|
||||||
ReactionEmote: emoji,
|
EmojiId: emojiId,
|
||||||
|
EmojiName: emojiName,
|
||||||
WelcomeMessage: data.WelcomeMessage,
|
WelcomeMessage: data.WelcomeMessage,
|
||||||
WithDefaultTeam: data.WithDefaultTeam,
|
WithDefaultTeam: data.WithDefaultTeam,
|
||||||
CustomId: customId,
|
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()@:%_+.~#?&//=]*)$`)
|
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 {
|
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() {
|
if !p.verifyTitle() {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.AbortWithStatusJSON(400, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
@ -227,34 +236,22 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool {
|
|||||||
channels := cache.Instance.GetGuildChannels(guildId)
|
channels := cache.Instance.GetGuildChannels(guildId)
|
||||||
|
|
||||||
if !p.verifyChannel(channels) {
|
if !p.verifyChannel(channels) {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.JSON(400, utils.ErrorStr("Invalid channel"))
|
||||||
"success": false,
|
|
||||||
"error": "Invalid channel",
|
|
||||||
})
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.verifyCategory(channels) {
|
if !p.verifyCategory(channels) {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.JSON(400, utils.ErrorStr("Invalid channel category"))
|
||||||
"success": false,
|
|
||||||
"error": "Invalid channel category",
|
|
||||||
})
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Emote != "" { // Allow no emoji
|
if !p.verifyEmoji(botContext, guildId) {
|
||||||
_, validEmoji := p.getEmoji()
|
ctx.JSON(400, utils.ErrorStr("Invalid emoji"))
|
||||||
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !p.verifyWelcomeMessage() {
|
if !p.verifyWelcomeMessage() {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.JSON(400, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": "Welcome message must be blank or between 1 - 4096 characters",
|
"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() {
|
if !p.verifyImageUrl() || !p.verifyThumbnailUrl() {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.JSON(400, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": "Image URL must be between 1 - 255 characters and a valid URL",
|
"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() {
|
if !p.verifyButtonStyle() {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.JSON(400, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"error": "Invalid button style",
|
"error": "Invalid button style",
|
||||||
})
|
})
|
||||||
@ -278,20 +275,19 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !p.verifyButtonLabel() {
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("label: %s\n", p.ButtonLabel)
|
|
||||||
{
|
{
|
||||||
valid, err := p.verifyTeams(guildId)
|
valid, err := p.verifyTeams(guildId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithStatusJSON(500, utils.ErrorJson(err))
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !valid {
|
if !valid {
|
||||||
ctx.AbortWithStatusJSON(400, utils.ErrorStr("Invalid teams provided"))
|
ctx.JSON(400, utils.ErrorStr("Invalid teams provided"))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,12 +295,12 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool {
|
|||||||
{
|
{
|
||||||
ok, err := p.verifyFormId(guildId)
|
ok, err := p.verifyFormId(guildId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithStatusJSON(500, utils.ErrorJson(err))
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,12 +328,9 @@ func (p *panelBody) verifyContent() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *panelBody) getEmoji() (emoji string, ok bool) {
|
// Data must be validated before calling this function
|
||||||
p.Emote = strings.TrimSpace(p.Emote)
|
func (p *panelBody) getEmoji() *emoji.Emoji {
|
||||||
p.Emote = strings.Replace(p.Emote, ":", "", -1)
|
return p.Emoji.IntoGdl()
|
||||||
|
|
||||||
emoji, ok = utils.GetEmoji(p.Emote)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *panelBody) verifyChannel(channels []channel.Channel) bool {
|
func (p *panelBody) verifyChannel(channels []channel.Channel) bool {
|
||||||
@ -364,6 +357,45 @@ func (p *panelBody) verifyCategory(channels []channel.Channel) bool {
|
|||||||
return valid
|
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 {
|
func (p *panelBody) verifyWelcomeMessage() bool {
|
||||||
return p.WelcomeMessage == nil || (len(*p.WelcomeMessage) > 0 && len(*p.WelcomeMessage) <= 4096)
|
return p.WelcomeMessage == nil || (len(*p.WelcomeMessage) > 0 && len(*p.WelcomeMessage) <= 4096)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/TicketsBot/GoPanel/botcontext"
|
"github.com/TicketsBot/GoPanel/botcontext"
|
||||||
"github.com/TicketsBot/GoPanel/database"
|
"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/gin-gonic/gin"
|
||||||
"github.com/rxdn/gdl/rest"
|
"github.com/rxdn/gdl/rest"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -13,57 +17,89 @@ func DeletePanel(ctx *gin.Context) {
|
|||||||
|
|
||||||
botContext, err := botcontext.ContextForGuild(guildId)
|
botContext, err := botcontext.ContextForGuild(guildId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithStatusJSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
panelId, err := strconv.Atoi(ctx.Param("panelid"))
|
panelId, err := strconv.Atoi(ctx.Param("panelid"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithStatusJSON(400, gin.H{
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
panel, err := database.Client.Panel.GetById(panelId)
|
panel, err := database.Client.Panel.GetById(panelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify panel belongs to guild
|
// verify panel belongs to guild
|
||||||
if panel.GuildId != guildId {
|
if panel.GuildId != guildId {
|
||||||
ctx.AbortWithStatusJSON(403, gin.H{
|
ctx.JSON(403, utils.ErrorStr("Guild ID doesn't match"))
|
||||||
"success": false,
|
return
|
||||||
"error": "Guild ID doesn't match",
|
}
|
||||||
})
|
|
||||||
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := database.Client.Panel.Delete(panelId); err != nil {
|
if err := database.Client.Panel.Delete(panelId); err != nil {
|
||||||
ctx.JSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rest.DeleteMessage(botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil {
|
if err := rest.DeleteMessage(botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil {
|
||||||
ctx.JSON(500, gin.H{
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
"success": false,
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.JSON(200, gin.H{
|
// Get premium tier
|
||||||
"success": true,
|
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)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils/types"
|
||||||
"github.com/TicketsBot/database"
|
"github.com/TicketsBot/database"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
@ -12,8 +13,9 @@ import (
|
|||||||
func ListPanels(ctx *gin.Context) {
|
func ListPanels(ctx *gin.Context) {
|
||||||
type panelResponse struct {
|
type panelResponse struct {
|
||||||
database.Panel
|
database.Panel
|
||||||
|
UseCustomEmoji bool `json:"use_custom_emoji"`
|
||||||
|
Emoji types.Emoji `json:"emote"`
|
||||||
Mentions []string `json:"mentions"`
|
Mentions []string `json:"mentions"`
|
||||||
//Teams []database.SupportTeam `json:"teams"`
|
|
||||||
Teams []int `json:"teams"`
|
Teams []int `json:"teams"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +75,8 @@ func ListPanels(ctx *gin.Context) {
|
|||||||
|
|
||||||
wrapped[i] = panelResponse{
|
wrapped[i] = panelResponse{
|
||||||
Panel: p,
|
Panel: p,
|
||||||
|
UseCustomEmoji: p.EmojiId != nil,
|
||||||
|
Emoji: types.NewEmoji(p.EmojiName, p.EmojiId),
|
||||||
Mentions: mentions,
|
Mentions: mentions,
|
||||||
Teams: teamIds,
|
Teams: teamIds,
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"github.com/TicketsBot/GoPanel/botcontext"
|
"github.com/TicketsBot/GoPanel/botcontext"
|
||||||
"github.com/TicketsBot/database"
|
"github.com/TicketsBot/database"
|
||||||
|
"github.com/rxdn/gdl/objects"
|
||||||
"github.com/rxdn/gdl/objects/channel/embed"
|
"github.com/rxdn/gdl/objects/channel/embed"
|
||||||
"github.com/rxdn/gdl/objects/guild/emoji"
|
"github.com/rxdn/gdl/objects/guild/emoji"
|
||||||
"github.com/rxdn/gdl/objects/interaction/component"
|
"github.com/rxdn/gdl/objects/interaction/component"
|
||||||
@ -14,16 +15,25 @@ type panelMessageData struct {
|
|||||||
|
|
||||||
Title, Content, CustomId string
|
Title, Content, CustomId string
|
||||||
Colour int
|
Colour int
|
||||||
ImageUrl, ThumbnailUrl, Emoji *string
|
ImageUrl, ThumbnailUrl *string
|
||||||
|
Emoji *emoji.Emoji
|
||||||
ButtonStyle component.ButtonStyle
|
ButtonStyle component.ButtonStyle
|
||||||
ButtonLabel string
|
ButtonLabel string
|
||||||
IsPremium bool
|
IsPremium bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData {
|
func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData {
|
||||||
var emoji *string
|
var emote *emoji.Emoji
|
||||||
if panel.ReactionEmote != "" {
|
if panel.EmojiName != nil && *panel.EmojiName == "" { // No emoji = nil
|
||||||
emoji = &panel.ReactionEmote
|
id := objects.NewNullSnowflake()
|
||||||
|
if panel.EmojiId != nil {
|
||||||
|
id = objects.NewNullableSnowflake(*panel.EmojiId)
|
||||||
|
}
|
||||||
|
|
||||||
|
emote = &emoji.Emoji{
|
||||||
|
Id: id,
|
||||||
|
Name: *panel.EmojiName,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return panelMessageData{
|
return panelMessageData{
|
||||||
@ -34,7 +44,7 @@ func panelIntoMessageData(panel database.Panel, isPremium bool) panelMessageData
|
|||||||
Colour: int(panel.Colour),
|
Colour: int(panel.Colour),
|
||||||
ImageUrl: panel.ImageUrl,
|
ImageUrl: panel.ImageUrl,
|
||||||
ThumbnailUrl: panel.ThumbnailUrl,
|
ThumbnailUrl: panel.ThumbnailUrl,
|
||||||
Emoji: emoji,
|
Emoji: emote,
|
||||||
ButtonStyle: component.ButtonStyle(panel.ButtonStyle),
|
ButtonStyle: component.ButtonStyle(panel.ButtonStyle),
|
||||||
ButtonLabel: panel.ButtonLabel,
|
ButtonLabel: panel.ButtonLabel,
|
||||||
IsPremium: isPremium,
|
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")
|
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{
|
data := rest.CreateMessageData{
|
||||||
Embeds: []*embed.Embed{e},
|
Embeds: []*embed.Embed{e},
|
||||||
Components: []component.Component{
|
Components: []component.Component{
|
||||||
@ -73,7 +76,7 @@ func (p *panelMessageData) send(ctx *botcontext.BotContext) (uint64, error) {
|
|||||||
Label: p.ButtonLabel,
|
Label: p.ButtonLabel,
|
||||||
CustomId: p.CustomId,
|
CustomId: p.CustomId,
|
||||||
Style: p.ButtonStyle,
|
Style: p.ButtonStyle,
|
||||||
Emoji: buttonEmoji,
|
Emoji: p.Emoji,
|
||||||
Url: nil,
|
Url: nil,
|
||||||
Disabled: false,
|
Disabled: false,
|
||||||
})),
|
})),
|
||||||
|
@ -53,49 +53,23 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
return
|
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)
|
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(guildId, true, botContext.Token, botContext.RateLimiter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.JSON(500, utils.ErrorJson(err))
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, multiPanel := range multiPanels {
|
var emojiId *uint64
|
||||||
panels, err := dbclient.Client.MultiPanelTargets.GetPanels(multiPanel.Id)
|
var emojiName *string
|
||||||
if err != nil {
|
{
|
||||||
ctx.JSON(500, utils.ErrorJson(err))
|
emoji := data.getEmoji()
|
||||||
return
|
if emoji != nil {
|
||||||
}
|
emojiName = &emoji.Name
|
||||||
|
|
||||||
messageData := multiPanelMessageData{
|
if emoji.Id.Value != 0 {
|
||||||
Title: multiPanel.Title,
|
emojiId = &emoji.Id.Value
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we need to update the message
|
// check if we need to update the message
|
||||||
@ -103,13 +77,13 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
existing.ChannelId != data.ChannelId ||
|
existing.ChannelId != data.ChannelId ||
|
||||||
existing.Content != data.Content ||
|
existing.Content != data.Content ||
|
||||||
existing.Title != data.Title ||
|
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.ImageUrl != data.ImageUrl ||
|
||||||
existing.ThumbnailUrl != data.ThumbnailUrl ||
|
existing.ThumbnailUrl != data.ThumbnailUrl ||
|
||||||
component.ButtonStyle(existing.ButtonStyle) != data.ButtonStyle ||
|
component.ButtonStyle(existing.ButtonStyle) != data.ButtonStyle ||
|
||||||
existing.ButtonLabel != data.ButtonLabel
|
existing.ButtonLabel != data.ButtonLabel
|
||||||
|
|
||||||
emoji, _ := data.getEmoji() // already validated
|
|
||||||
newMessageId := existing.MessageId
|
newMessageId := existing.MessageId
|
||||||
|
|
||||||
if shouldUpdateMessage {
|
if shouldUpdateMessage {
|
||||||
@ -141,7 +115,8 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
Content: data.Content,
|
Content: data.Content,
|
||||||
Colour: int32(data.Colour),
|
Colour: int32(data.Colour),
|
||||||
TargetCategory: data.CategoryId,
|
TargetCategory: data.CategoryId,
|
||||||
ReactionEmote: emoji,
|
EmojiName: emojiName,
|
||||||
|
EmojiId: emojiId,
|
||||||
WelcomeMessage: data.WelcomeMessage,
|
WelcomeMessage: data.WelcomeMessage,
|
||||||
WithDefaultTeam: data.WithDefaultTeam,
|
WithDefaultTeam: data.WithDefaultTeam,
|
||||||
CustomId: existing.CustomId,
|
CustomId: existing.CustomId,
|
||||||
@ -199,5 +174,51 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
return
|
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)
|
ctx.JSON(200, utils.SuccessResponse)
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,19 @@ func (ctx BotContext) GetGuildRoles(guildId uint64) (roles []guild.Role, err err
|
|||||||
return
|
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) {
|
func (ctx BotContext) GetGuildEmojis(guildId uint64) (emojis []emoji.Emoji, err error) {
|
||||||
if emojis := cache.Instance.GetGuildEmojis(guildId); len(emojis) > 0 {
|
if emojis := cache.Instance.GetGuildEmojis(guildId); len(emojis) > 0 {
|
||||||
return emojis, nil
|
return emojis, nil
|
||||||
|
15
frontend/package-lock.json
generated
15
frontend/package-lock.json
generated
@ -27,7 +27,8 @@
|
|||||||
"rollup-plugin-livereload": "^2.0.0",
|
"rollup-plugin-livereload": "^2.0.0",
|
||||||
"rollup-plugin-svelte": "^7.1.0",
|
"rollup-plugin-svelte": "^7.1.0",
|
||||||
"rollup-plugin-terser": "^7.0.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": {
|
"node_modules/@babel/code-frame": {
|
||||||
@ -3169,6 +3170,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/svelte-tabs/-/svelte-tabs-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-tabs/-/svelte-tabs-1.1.0.tgz",
|
||||||
"integrity": "sha512-bCynxgET2uvqpB6xf/dVyqHjzmumRURQyh2QqXlrki8NxzO7h2WghF8qgpb5qeB5NTX1bMU+9Q5Hf5ey2WLaMg=="
|
"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": {
|
"node_modules/terser": {
|
||||||
"version": "5.7.0",
|
"version": "5.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/svelte-tabs/-/svelte-tabs-1.1.0.tgz",
|
||||||
"integrity": "sha512-bCynxgET2uvqpB6xf/dVyqHjzmumRURQyh2QqXlrki8NxzO7h2WghF8qgpb5qeB5NTX1bMU+9Q5Hf5ey2WLaMg=="
|
"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": {
|
"terser": {
|
||||||
"version": "5.7.0",
|
"version": "5.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz",
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
"rollup-plugin-livereload": "^2.0.0",
|
"rollup-plugin-livereload": "^2.0.0",
|
||||||
"rollup-plugin-svelte": "^7.1.0",
|
"rollup-plugin-svelte": "^7.1.0",
|
||||||
"rollup-plugin-terser": "^7.0.0",
|
"rollup-plugin-terser": "^7.0.0",
|
||||||
"svelte": "^3.48.0"
|
"svelte": "^3.48.0",
|
||||||
|
"svelte-toggle": "^3.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.21.4",
|
"axios": "^0.21.4",
|
||||||
|
@ -5,7 +5,9 @@
|
|||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<input id="input" class="form-input" placeholder="{placeholder}" disabled="{disabled}" bind:value={value}>
|
<input id="input" class="form-input" placeholder="{placeholder}" disabled="{disabled}" bind:value={value}>
|
||||||
{#if !disabled}
|
{#if !disabled}
|
||||||
|
<div class="picker-wrapper">
|
||||||
<EmojiSelector on:emoji={onUpdate}/>
|
<EmojiSelector on:emoji={onUpdate}/>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -49,9 +51,14 @@
|
|||||||
border-left: none;
|
border-left: none;
|
||||||
color: white;
|
color: white;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.svelte-emoji-picker__trigger:active) {
|
:global(.svelte-emoji-picker__trigger:active) {
|
||||||
background-color: #2e3136 !important;
|
background-color: #2e3136 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.picker-wrapper {
|
||||||
|
max-height: 40px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -1,6 +1,6 @@
|
|||||||
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4} class="switch">
|
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4} class="switch">
|
||||||
<label for="input" class="form-label">{label}</label>
|
<label for="input" class="form-label">{label}</label>
|
||||||
<input id="input" type="checkbox" bind:checked={value} on:change />
|
<input id="input" type="checkbox" bind:checked={value} on:change={() => console.log('b')} />
|
||||||
<span class="slider" />
|
<span class="slider" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -33,7 +33,12 @@
|
|||||||
<label for="emoji-pick-wrapper" class="form-label">Button Emoji</label>
|
<label for="emoji-pick-wrapper" class="form-label">Button Emoji</label>
|
||||||
<div id="emoji-pick-wrapper" class="row">
|
<div id="emoji-pick-wrapper" class="row">
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<Slider label="Custom Emoji" bind:value={data.use_custom_emoji} />
|
<label class="form-label" style="margin-bottom: 0 !important;">Custom Emoji</label>
|
||||||
|
<Toggle hideLabel
|
||||||
|
toggledColor="#66bb6a"
|
||||||
|
untoggledColor="#ccc"
|
||||||
|
bind:toggled={data.use_custom_emoji}
|
||||||
|
on:toggle={handleEmojiTypeChange} />
|
||||||
</div>
|
</div>
|
||||||
{#if data.use_custom_emoji}
|
{#if data.use_custom_emoji}
|
||||||
<!--bind:selectedValue={selectedMentions}
|
<!--bind:selectedValue={selectedMentions}
|
||||||
@ -41,10 +46,12 @@
|
|||||||
<div class="multiselect-super">
|
<div class="multiselect-super">
|
||||||
<Select items={emojis}
|
<Select items={emojis}
|
||||||
Item={EmojiItem}
|
Item={EmojiItem}
|
||||||
|
selectedValue={data.emote}
|
||||||
optionIdentifier="id"
|
optionIdentifier="id"
|
||||||
getSelectionLabel={emojiNameMapper}
|
getSelectionLabel={emojiNameMapper}
|
||||||
getOptionLabel={emojiNameMapper}
|
getOptionLabel={emojiNameMapper}
|
||||||
placeholderAlwaysShow={true} />
|
placeholderAlwaysShow={true}
|
||||||
|
on:select={handleCustomEmojiChange} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<EmojiInput col1=true bind:value={data.emote}/>
|
<EmojiInput col1=true bind:value={data.emote}/>
|
||||||
@ -89,7 +96,7 @@
|
|||||||
on:select={updateTeams}
|
on:select={updateTeams}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
optionIdentifier="id"
|
optionIdentifier="id"
|
||||||
getSelectionLabel={emojiNameMapper}
|
getSelectionLabel={nameMapper}
|
||||||
getOptionLabel={nameMapper}
|
getOptionLabel={nameMapper}
|
||||||
isMulti={true} />
|
isMulti={true} />
|
||||||
</div>
|
</div>
|
||||||
@ -118,7 +125,7 @@
|
|||||||
import Select from 'svelte-select';
|
import Select from 'svelte-select';
|
||||||
import Dropdown from "../form/Dropdown.svelte";
|
import Dropdown from "../form/Dropdown.svelte";
|
||||||
import Checkbox from "../form/Checkbox.svelte";
|
import Checkbox from "../form/Checkbox.svelte";
|
||||||
import Slider from "../form/Slider.svelte";
|
import Toggle from "svelte-toggle";
|
||||||
|
|
||||||
export let guildId;
|
export let guildId;
|
||||||
export let seedDefault = true;
|
export let seedDefault = true;
|
||||||
@ -194,6 +201,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleEmojiTypeChange(e) {
|
||||||
|
let isCustomEmoji = e.detail;
|
||||||
|
if (isCustomEmoji) {
|
||||||
|
data.emote = undefined;
|
||||||
|
} else {
|
||||||
|
data.emote = '📩';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCustomEmojiChange(e) {
|
||||||
|
let emoji = e.detail;
|
||||||
|
data.emote = {
|
||||||
|
id: emoji.id,
|
||||||
|
name: emoji.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function updateColour() {
|
function updateColour() {
|
||||||
data.colour = colourToInt(tempColour);
|
data.colour = colourToInt(tempColour);
|
||||||
}
|
}
|
||||||
@ -223,6 +247,9 @@
|
|||||||
.forEach((mention) => selectedMentions.push(mention));
|
.forEach((mention) => selectedMentions.push(mention));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: data.emote = data.emote;
|
||||||
|
console.log(data.emote)
|
||||||
|
|
||||||
tempColour = intToColour(data.colour);
|
tempColour = intToColour(data.colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,6 +262,7 @@
|
|||||||
//title: 'Open a ticket!',
|
//title: 'Open a ticket!',
|
||||||
//content: 'By clicking the button, a ticket will be opened for you.',
|
//content: 'By clicking the button, a ticket will be opened for you.',
|
||||||
colour: 0x2ECC71,
|
colour: 0x2ECC71,
|
||||||
|
use_custom_emoji: false,
|
||||||
emote: '📩',
|
emote: '📩',
|
||||||
welcome_message: null,
|
welcome_message: null,
|
||||||
mentions: [],
|
mentions: [],
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<span slot="title">Edit Panel</span>
|
<span slot="title">Edit Panel</span>
|
||||||
|
|
||||||
<div slot="body" class="body-wrapper">
|
<div slot="body" class="body-wrapper">
|
||||||
<PanelCreationForm {guildId} {channels} {roles} {teams} {forms} bind:data={panel} seedDefault={false} />
|
<PanelCreationForm {guildId} {channels} {roles} {emojis} {teams} {forms} bind:data={panel} seedDefault={false} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
@ -34,6 +34,7 @@
|
|||||||
export let channels = [];
|
export let channels = [];
|
||||||
export let forms = [];
|
export let forms = [];
|
||||||
export let roles = [];
|
export let roles = [];
|
||||||
|
export let emojis = [];
|
||||||
export let teams = [];
|
export let teams = [];
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{#if editModal}
|
{#if editModal}
|
||||||
<PanelEditModal {guildId} {channels} {roles} {teams} {forms} bind:panel={editData}
|
<PanelEditModal {guildId} {channels} {roles} {emojis} {teams} {forms} bind:panel={editData}
|
||||||
on:close={() => editModal = false} on:confirm={submitEdit}/>
|
on:close={() => editModal = false} on:confirm={submitEdit}/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -16,8 +16,6 @@
|
|||||||
<div slot="body" class="card-body">
|
<div slot="body" class="card-body">
|
||||||
<p>Your panel quota: <b>{panels.length} / {isPremium ? '∞' : '3'}</b></p>
|
<p>Your panel quota: <b>{panels.length} / {isPremium ? '∞' : '3'}</b></p>
|
||||||
|
|
||||||
<img src="https://cdn.discordapp.com/emojis/986995010136318022.png" />
|
|
||||||
|
|
||||||
<table style="margin-top: 10px">
|
<table style="margin-top: 10px">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
2
go.mod
2
go.mod
@ -6,7 +6,7 @@ require (
|
|||||||
github.com/BurntSushi/toml v0.3.1
|
github.com/BurntSushi/toml v0.3.1
|
||||||
github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc
|
github.com/TicketsBot/archiverclient v0.0.0-20220326163414-558fd52746dc
|
||||||
github.com/TicketsBot/common v0.0.0-20220609182514-8d43f86e8253
|
github.com/TicketsBot/common v0.0.0-20220609182514-8d43f86e8253
|
||||||
github.com/TicketsBot/database v0.0.0-20220616145240-1b6207291ca6
|
github.com/TicketsBot/database v0.0.0-20220616215313-0f5a33c3a2a6
|
||||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c
|
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c
|
||||||
github.com/TicketsBot/worker v0.0.0-20220614162334-f81bf3f39aa5
|
github.com/TicketsBot/worker v0.0.0-20220614162334-f81bf3f39aa5
|
||||||
github.com/apex/log v1.1.2
|
github.com/apex/log v1.1.2
|
||||||
|
2
go.sum
2
go.sum
@ -7,6 +7,8 @@ github.com/TicketsBot/common v0.0.0-20220609182514-8d43f86e8253 h1:HbL0OBZHmU0Tb
|
|||||||
github.com/TicketsBot/common v0.0.0-20220609182514-8d43f86e8253/go.mod h1:ZAoYcDD7SQLTsZT7dbo/X0J256+pogVRAReunCGng+U=
|
github.com/TicketsBot/common v0.0.0-20220609182514-8d43f86e8253/go.mod h1:ZAoYcDD7SQLTsZT7dbo/X0J256+pogVRAReunCGng+U=
|
||||||
github.com/TicketsBot/database v0.0.0-20220616145240-1b6207291ca6 h1:lq5+CXNCQRUyd3ODq1Y6tUsEY7Y0e1YfLQr50C0Nuis=
|
github.com/TicketsBot/database v0.0.0-20220616145240-1b6207291ca6 h1:lq5+CXNCQRUyd3ODq1Y6tUsEY7Y0e1YfLQr50C0Nuis=
|
||||||
github.com/TicketsBot/database v0.0.0-20220616145240-1b6207291ca6/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
github.com/TicketsBot/database v0.0.0-20220616145240-1b6207291ca6/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||||
|
github.com/TicketsBot/database v0.0.0-20220616215313-0f5a33c3a2a6 h1:DC9CoT5uMuIh0pYX69euWLa/0MZLZA4sA+umIhOr0qo=
|
||||||
|
github.com/TicketsBot/database v0.0.0-20220616215313-0f5a33c3a2a6/go.mod h1:F57cywrZsnper1cy56Bx0c/HEsxQBLHz3Pl98WXblWw=
|
||||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c h1:OqGjFH6mbE6gd+NqI2ARJdtH3UUvhiAkD0r0fhGJK2s=
|
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c h1:OqGjFH6mbE6gd+NqI2ARJdtH3UUvhiAkD0r0fhGJK2s=
|
||||||
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c/go.mod h1:jgi2OXQKsd5nUnTIRkwvPmeuD/i7OhN68LKMssuQY1c=
|
github.com/TicketsBot/logarchiver v0.0.0-20220326162808-cdf0310f5e1c/go.mod h1:jgi2OXQKsd5nUnTIRkwvPmeuD/i7OhN68LKMssuQY1c=
|
||||||
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261 h1:NHD5GB6cjlkpZFjC76Yli2S63/J2nhr8MuE6KlYJpQM=
|
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261 h1:NHD5GB6cjlkpZFjC76Yli2S63/J2nhr8MuE6KlYJpQM=
|
||||||
|
@ -10,7 +10,8 @@ var emojisByName map[string]string
|
|||||||
var emojis []string
|
var emojis []string
|
||||||
|
|
||||||
func LoadEmoji() {
|
func LoadEmoji() {
|
||||||
bytes, err := ioutil.ReadFile("emojis.json"); if err != nil {
|
bytes, err := ioutil.ReadFile("emojis.json")
|
||||||
|
if err != nil {
|
||||||
log.Error("Couldn't load emoji: " + err.Error())
|
log.Error("Couldn't load emoji: " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -32,7 +33,7 @@ func GetEmoji(input string) (emoji string, ok bool) {
|
|||||||
// try by name first
|
// try by name first
|
||||||
emoji, ok = emojisByName[input]
|
emoji, ok = emojisByName[input]
|
||||||
if !ok { // else try by the actual unicode char
|
if !ok { // else try by the actual unicode char
|
||||||
for _, unicode := range emojis {
|
for _, unicode := range emojis { // TODO: Optimise
|
||||||
if unicode == input {
|
if unicode == input {
|
||||||
emoji = unicode
|
emoji = unicode
|
||||||
ok = true
|
ok = true
|
||||||
|
93
utils/types/emoji.go
Normal file
93
utils/types/emoji.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/rxdn/gdl/objects"
|
||||||
|
"github.com/rxdn/gdl/objects/guild/emoji"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Emoji struct {
|
||||||
|
IsCustomEmoji bool
|
||||||
|
Name string
|
||||||
|
Id *uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEmoji(emojiName *string, emojiId *uint64) Emoji {
|
||||||
|
if emojiName == nil || *emojiName == "" {
|
||||||
|
return Emoji{
|
||||||
|
IsCustomEmoji: false,
|
||||||
|
Name: "",
|
||||||
|
Id: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Emoji{
|
||||||
|
IsCustomEmoji: emojiId != nil,
|
||||||
|
Name: *emojiName,
|
||||||
|
Id: emojiId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Emoji) IntoGdl() *emoji.Emoji {
|
||||||
|
if e.IsCustomEmoji {
|
||||||
|
return &emoji.Emoji{
|
||||||
|
Id: objects.NewNullableSnowflake(*e.Id),
|
||||||
|
Name: e.Name,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if e.Name == "" {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return &emoji.Emoji{
|
||||||
|
Name: e.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type customEmoji struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Id *uint64 `json:"id,string"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Emoji) UnmarshalJSON(data []byte) error {
|
||||||
|
var raw interface{}
|
||||||
|
if err := json.Unmarshal(data, &raw); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if raw == nil {
|
||||||
|
return fmt.Errorf("emoji data was nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := raw.(type) {
|
||||||
|
case string:
|
||||||
|
e.IsCustomEmoji = false
|
||||||
|
e.Name = v
|
||||||
|
case map[string]interface{}:
|
||||||
|
var decoded customEmoji
|
||||||
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.IsCustomEmoji = true
|
||||||
|
e.Name = decoded.Name
|
||||||
|
e.Id = decoded.Id
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Emoji) MarshalJSON() ([]byte, error) {
|
||||||
|
if e.IsCustomEmoji {
|
||||||
|
return json.Marshal(customEmoji{
|
||||||
|
Name: e.Name,
|
||||||
|
Id: e.Id,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return json.Marshal(e.Name)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user