diff --git a/app/http/endpoints/api/tags/tagcreate.go b/app/http/endpoints/api/tags/tagcreate.go index 22e458c..24ce765 100644 --- a/app/http/endpoints/api/tags/tagcreate.go +++ b/app/http/endpoints/api/tags/tagcreate.go @@ -1,21 +1,35 @@ package api import ( - "github.com/TicketsBot/GoPanel/database" + "fmt" + dbclient "github.com/TicketsBot/GoPanel/database" "github.com/TicketsBot/GoPanel/utils" + "github.com/TicketsBot/GoPanel/utils/types" + "github.com/TicketsBot/database" "github.com/gin-gonic/gin" + "github.com/go-playground/validator/v10" + "regexp" + "strings" ) type tag struct { - Id string `json:"id"` - Content string `json:"content"` + Id string `json:"id" validate:"required,min=1,max=16"` + UseGuildCommand bool `json:"use_guild_command"` // Not yet implemented + Content *string `json:"content" validate:"omitempty,min=1,max=4096"` + UseEmbed bool `json:"use_embed"` + Embed *types.CustomEmbed `json:"embed" validate:"omitempty,dive"` } +var ( + validate = validator.New() + slashCommandRegex = regexp.MustCompile(`^[-_a-zA-Z0-9]{1,32}$`) +) + func CreateTag(ctx *gin.Context) { guildId := ctx.Keys["guildid"].(uint64) // Max of 200 tags - count, err := database.Client.Tag.GetTagCount(guildId) + count, err := dbclient.Client.Tag.GetTagCount(guildId) if err != nil { ctx.JSON(500, utils.ErrorJson(err)) return @@ -32,27 +46,80 @@ func CreateTag(ctx *gin.Context) { return } - if !data.verifyIdLength() { - ctx.JSON(400, utils.ErrorStr("Tag ID must be 1 - 16 characters in length")) + if !data.UseEmbed { + data.Embed = nil + } + + // TODO: Limit command amount + if err := validate.Struct(data); err != nil { + validationErrors, ok := err.(validator.ValidationErrors) + if !ok { + ctx.JSON(500, utils.ErrorStr("An error occurred while validating the integration")) + return + } + + formatted := "Your input contained the following errors:" + for _, validationError := range validationErrors { + formatted += fmt.Sprintf("\n%s", validationError.Error()) + } + + formatted = strings.TrimSuffix(formatted, "\n") + ctx.JSON(400, utils.ErrorStr(formatted)) return } - if !data.verifyContentLength() { - ctx.JSON(400, utils.ErrorStr("Tag content must be 1 - 2000 characters in length")) + if !data.verifyContent() { + ctx.JSON(400, utils.ErrorStr("You have not provided any content for the tag")) return } - if err := database.Client.Tag.Set(guildId, data.Id, data.Content); err != nil { + var embed *database.CustomEmbedWithFields + if data.Embed != nil { + customEmbed, fields := data.Embed.IntoDatabaseStruct() + embed = &database.CustomEmbedWithFields{ + CustomEmbed: customEmbed, + Fields: fields, + } + } + + wrapped := database.Tag{ + Id: data.Id, + GuildId: guildId, + UseGuildCommand: data.UseGuildCommand, + Content: data.Content, + Embed: embed, + } + + if err := dbclient.Client.Tag.Set(wrapped); err != nil { ctx.JSON(500, utils.ErrorJson(err)) + return + } + + ctx.Status(204) +} + +func (t *tag) verifyId() bool { + if len(t.Id) == 0 || len(t.Id) > 16 || strings.Contains(t.Id, " ") { + return false + } + + if t.UseGuildCommand { + return slashCommandRegex.MatchString(t.Id) } else { - ctx.JSON(200, utils.SuccessResponse) + return true } } -func (t *tag) verifyIdLength() bool { - return len(t.Id) > 0 && len(t.Id) <= 16 -} +func (t *tag) verifyContent() bool { + if t.Content != nil { // validator ensures that if this is not nil, > 0 length + return true + } -func (t *tag) verifyContentLength() bool { - return len(t.Content) > 0 && len(t.Content) <= 2000 + if t.Embed != nil { + if t.Embed.Description != nil || len(t.Embed.Fields) > 0 || t.Embed.ImageUrl != nil || t.Embed.ThumbnailUrl != nil { + return true + } + } + + return false } diff --git a/app/http/endpoints/api/tags/tagdelete.go b/app/http/endpoints/api/tags/tagdelete.go index 5b0ee21..6a4a550 100644 --- a/app/http/endpoints/api/tags/tagdelete.go +++ b/app/http/endpoints/api/tags/tagdelete.go @@ -6,14 +6,14 @@ import ( "github.com/gin-gonic/gin" ) +type deleteBody struct { + TagId string `json:"tag_id"` +} + func DeleteTag(ctx *gin.Context) { guildId := ctx.Keys["guildid"].(uint64) - type Body struct { - TagId string `json:"tag_id"` - } - - var body Body + var body deleteBody if err := ctx.BindJSON(&body); err != nil { ctx.JSON(400, utils.ErrorJson(err)) return @@ -26,7 +26,8 @@ func DeleteTag(ctx *gin.Context) { if err := database.Client.Tag.Delete(guildId, body.TagId); err != nil { ctx.JSON(500, utils.ErrorJson(err)) - } else { - ctx.JSON(200, utils.SuccessResponse) + return } + + ctx.Status(204) } diff --git a/app/http/endpoints/api/tags/tagslist.go b/app/http/endpoints/api/tags/tagslist.go index fd13e41..45554d5 100644 --- a/app/http/endpoints/api/tags/tagslist.go +++ b/app/http/endpoints/api/tags/tagslist.go @@ -2,21 +2,35 @@ package api import ( "github.com/TicketsBot/GoPanel/database" + "github.com/TicketsBot/GoPanel/utils" + "github.com/TicketsBot/GoPanel/utils/types" "github.com/gin-gonic/gin" ) -// TODO: Make client take new structure func TagsListHandler(ctx *gin.Context) { guildId := ctx.Keys["guildid"].(uint64) tags, err := database.Client.Tag.GetByGuild(guildId) if err != nil { - ctx.AbortWithStatusJSON(500, gin.H{ - "success": false, - "error": err.Error(), - }) + ctx.JSON(500, utils.ErrorJson(err)) return } - ctx.JSON(200, tags) + wrapped := make(map[string]tag) + for id, data := range tags { + var embed *types.CustomEmbed + if data.Embed != nil { + embed = types.NewCustomEmbed(data.Embed.CustomEmbed, data.Embed.Fields) + } + + wrapped[id] = tag{ + Id: data.Id, + UseGuildCommand: data.UseGuildCommand, + Content: data.Content, + UseEmbed: data.Embed != nil, + Embed: embed, + } + } + + ctx.JSON(200, wrapped) } diff --git a/botcontext/botcontext.go b/botcontext/botcontext.go index 1e1b1ae..01fe32f 100644 --- a/botcontext/botcontext.go +++ b/botcontext/botcontext.go @@ -10,6 +10,7 @@ import ( "github.com/rxdn/gdl/objects/channel" "github.com/rxdn/gdl/objects/guild" "github.com/rxdn/gdl/objects/guild/emoji" + "github.com/rxdn/gdl/objects/interaction" "github.com/rxdn/gdl/objects/member" "github.com/rxdn/gdl/objects/user" "github.com/rxdn/gdl/rest" @@ -168,3 +169,11 @@ func (ctx BotContext) ListMembers(guildId uint64) (members []member.Member, err return } + +func (ctx BotContext) CreateGuildCommand(guildId uint64, data rest.CreateCommandData) (interaction.ApplicationCommand, error) { + return rest.CreateGuildCommand(ctx.Token, ctx.RateLimiter, ctx.BotId, guildId, data) +} + +func (ctx BotContext) DeleteGuildCommand(guildId, commandId uint64) error { + return rest.DeleteGuildCommand(ctx.Token, ctx.RateLimiter, ctx.BotId, guildId, commandId) +} diff --git a/frontend/src/components/ConfirmationModal.svelte b/frontend/src/components/ConfirmationModal.svelte index 7fcccda..8dab052 100644 --- a/frontend/src/components/ConfirmationModal.svelte +++ b/frontend/src/components/ConfirmationModal.svelte @@ -1,7 +1,9 @@