Refactoring

This commit is contained in:
rxdn 2024-11-16 20:29:56 +00:00
parent 41efc46236
commit c42808f38d
20 changed files with 376 additions and 309 deletions

View File

@ -1,40 +1,42 @@
package forms
import (
"github.com/TicketsBot/GoPanel/app"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/database"
"github.com/gin-gonic/gin"
"net/http"
)
type createFormBody struct {
Title string `json:"title"`
}
func CreateForm(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func CreateForm(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
var data createFormBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, utils.ErrorJson(err))
if err := c.BindJSON(&data); err != nil {
c.JSON(400, utils.ErrorStr("Invalid request body"))
return
}
if len(data.Title) > 45 {
ctx.JSON(400, utils.ErrorStr("Title is too long"))
c.JSON(400, utils.ErrorStr("Title is too long"))
return
}
// 26^50 chance of collision
customId, err := utils.RandString(30)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
id, err := dbclient.Client.Forms.Create(ctx, guildId, data.Title, customId)
id, err := dbclient.Client.Forms.Create(c, guildId, data.Title, customId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -45,5 +47,5 @@ func CreateForm(ctx *gin.Context) {
CustomId: customId,
}
ctx.JSON(200, form)
c.JSON(200, form)
}

View File

@ -1,41 +1,43 @@
package forms
import (
"github.com/TicketsBot/GoPanel/app"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
func DeleteForm(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func DeleteForm(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
formId, err := strconv.Atoi(ctx.Param("form_id"))
formId, err := strconv.Atoi(c.Param("form_id"))
if err != nil {
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
c.JSON(400, utils.ErrorStr("Invalid form ID"))
return
}
form, ok, err := dbclient.Client.Forms.Get(ctx, formId)
form, ok, err := dbclient.Client.Forms.Get(c, formId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if !ok {
ctx.JSON(404, utils.ErrorStr("Form not found"))
c.JSON(404, utils.ErrorStr("Form not found"))
return
}
if form.GuildId != guildId {
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
c.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
return
}
if err := dbclient.Client.Forms.Delete(ctx, formId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.Forms.Delete(c, formId); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}

View File

@ -1,10 +1,11 @@
package forms
import (
"github.com/TicketsBot/GoPanel/app"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/database"
"github.com/gin-gonic/gin"
"net/http"
)
type embeddedForm struct {
@ -12,18 +13,18 @@ type embeddedForm struct {
Inputs []database.FormInput `json:"inputs"`
}
func GetForms(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func GetForms(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
forms, err := dbclient.Client.Forms.GetForms(ctx, guildId)
forms, err := dbclient.Client.Forms.GetForms(c, guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
inputs, err := dbclient.Client.FormInput.GetInputsForGuild(ctx, guildId)
inputs, err := dbclient.Client.FormInput.GetInputsForGuild(c, guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -40,5 +41,5 @@ func GetForms(ctx *gin.Context) {
}
}
ctx.JSON(200, data)
c.JSON(200, data)
}

View File

@ -1,52 +1,54 @@
package forms
import (
"github.com/TicketsBot/GoPanel/app"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"net/http"
"strconv"
)
func UpdateForm(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func UpdateForm(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
var data createFormBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, utils.ErrorJson(err))
if err := c.BindJSON(&data); err != nil {
c.JSON(400, utils.ErrorJson(err))
return
}
if len(data.Title) > 45 {
ctx.JSON(400, utils.ErrorStr("Title is too long"))
c.JSON(400, utils.ErrorStr("Title is too long"))
return
}
formId, err := strconv.Atoi(ctx.Param("form_id"))
formId, err := strconv.Atoi(c.Param("form_id"))
if err != nil {
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
c.JSON(400, utils.ErrorStr("Invalid form ID"))
return
}
form, ok, err := dbclient.Client.Forms.Get(ctx, formId)
form, ok, err := dbclient.Client.Forms.Get(c, formId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if !ok {
ctx.JSON(404, utils.ErrorStr("Form not found"))
c.JSON(404, utils.ErrorStr("Form not found"))
return
}
if form.GuildId != guildId {
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
c.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
return
}
if err := dbclient.Client.Forms.UpdateTitle(ctx, formId, data.Title); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.Forms.UpdateTitle(c, formId, data.Title); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}

View File

@ -2,13 +2,16 @@ package forms
import (
"context"
"errors"
"fmt"
"github.com/TicketsBot/GoPanel/app"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/database"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/rxdn/gdl/objects/interaction/component"
"net/http"
"sort"
"strconv"
)
@ -38,66 +41,66 @@ type (
var validate = validator.New()
func UpdateInputs(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func UpdateInputs(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
formId, err := strconv.Atoi(ctx.Param("form_id"))
formId, err := strconv.Atoi(c.Param("form_id"))
if err != nil {
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
c.JSON(400, utils.ErrorStr("Invalid form ID"))
return
}
var data updateInputsBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, utils.ErrorJson(err))
if err := c.BindJSON(&data); err != nil {
c.JSON(400, utils.ErrorJson(err))
return
}
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"))
var validationErrors validator.ValidationErrors
if !errors.As(err, &validationErrors) {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "An error occurred while validating the integration"))
return
}
formatted := "Your input contained the following errors:\n" + utils.FormatValidationErrors(validationErrors)
ctx.JSON(400, utils.ErrorStr(formatted))
c.JSON(400, utils.ErrorStr(formatted))
return
}
fieldCount := len(data.Create) + len(data.Update)
if fieldCount <= 0 || fieldCount > 5 {
ctx.JSON(400, utils.ErrorStr("Forms must have between 1 and 5 inputs"))
c.JSON(400, utils.ErrorStr("Forms must have between 1 and 5 inputs"))
return
}
// Verify form exists and is from the right guild
form, ok, err := dbclient.Client.Forms.Get(ctx, formId)
form, ok, err := dbclient.Client.Forms.Get(c, formId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if !ok {
ctx.JSON(404, utils.ErrorStr("Form not found"))
c.JSON(404, utils.ErrorStr("Form not found"))
return
}
if form.GuildId != guildId {
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
c.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
return
}
existingInputs, err := dbclient.Client.FormInput.GetInputs(ctx, formId)
existingInputs, err := dbclient.Client.FormInput.GetInputs(c, formId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Verify that the UPDATE inputs exist
for _, input := range data.Update {
if !utils.ExistsMap(existingInputs, input.Id, idMapper) {
ctx.JSON(400, utils.ErrorStr("Input (to be updated) not found"))
c.JSON(400, utils.ErrorStr("Input (to be updated) not found"))
return
}
}
@ -105,7 +108,7 @@ func UpdateInputs(ctx *gin.Context) {
// Verify that the DELETE inputs exist
for _, id := range data.Delete {
if !utils.ExistsMap(existingInputs, id, idMapper) {
ctx.JSON(400, utils.ErrorStr("Input (to be deleted) not found"))
c.JSON(400, utils.ErrorStr("Input (to be deleted) not found"))
return
}
}
@ -113,7 +116,7 @@ func UpdateInputs(ctx *gin.Context) {
// Ensure no overlap between DELETE and UPDATE
for _, id := range data.Delete {
if utils.ExistsMap(data.Update, id, idMapperBody) {
ctx.JSON(400, utils.ErrorStr("Delete and update overlap"))
c.JSON(400, utils.ErrorStr("Delete and update overlap"))
return
}
}
@ -128,29 +131,29 @@ func UpdateInputs(ctx *gin.Context) {
// Now verify that the contents match exactly
if len(remainingExisting) != len(data.Update) {
ctx.JSON(400, utils.ErrorStr("All inputs must be included in the update array"))
c.JSON(400, utils.ErrorStr("All inputs must be included in the update array"))
return
}
for _, input := range data.Update {
if !utils.Exists(remainingExisting, input.Id) {
ctx.JSON(400, utils.ErrorStr("All inputs must be included in the update array"))
c.JSON(400, utils.ErrorStr("All inputs must be included in the update array"))
return
}
}
// Verify that the positions are unique, and are in ascending order
if !arePositionsCorrect(data) {
ctx.JSON(400, utils.ErrorStr("Positions must be unique and in ascending order"))
c.JSON(400, utils.ErrorStr("Positions must be unique and in ascending order"))
return
}
if err := saveInputs(ctx, formId, data, existingInputs); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := saveInputs(c, formId, data, existingInputs); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.Status(204)
c.Status(204)
}
func idMapper(input database.FormInput) int {

View File

@ -3,6 +3,7 @@ package api
import (
"context"
"errors"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/botcontext"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/rpc"
@ -16,6 +17,7 @@ import (
"github.com/rxdn/gdl/objects/channel"
"github.com/rxdn/gdl/rest/request"
"golang.org/x/sync/errgroup"
"net/http"
)
type multiPanelCreateData struct {
@ -36,48 +38,45 @@ func (d *multiPanelCreateData) IntoMessageData(isPremium bool) multiPanelMessage
}
}
func MultiPanelCreate(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func MultiPanelCreate(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
var data multiPanelCreateData
if err := ctx.ShouldBindJSON(&data); err != nil {
ctx.JSON(400, utils.ErrorJson(err))
if err := c.ShouldBindJSON(&data); err != nil {
c.JSON(400, utils.ErrorJson(err))
return
}
if err := validate.Struct(data); err != nil {
var validationErrors validator.ValidationErrors
if ok := errors.As(err, &validationErrors); !ok {
ctx.JSON(500, utils.ErrorStr("An error occurred while validating the panel"))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "An error occurred while validating the panel"))
return
}
formatted := "Your input contained the following errors:\n" + utils.FormatValidationErrors(validationErrors)
ctx.JSON(400, utils.ErrorStr(formatted))
c.JSON(400, utils.ErrorStr(formatted))
return
}
// validate body & get sub-panels
panels, err := data.doValidations(guildId)
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
c.JSON(400, utils.ErrorJson(err))
return
}
// get bot context
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, gin.H{
"success": false,
"error": err.Error(),
})
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// get premium status
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(ctx, guildId, true, botContext.Token, botContext.RateLimiter)
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(c, guildId, true, botContext.Token, botContext.RateLimiter)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -86,9 +85,9 @@ func MultiPanelCreate(ctx *gin.Context) {
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped); unwrapped.StatusCode == 403 {
ctx.JSON(500, utils.ErrorJson(errors.New("I do not have permission to send messages in the provided channel")))
c.JSON(http.StatusBadRequest, utils.ErrorJson(errors.New("I do not have permission to send messages in the provided channel")))
} else {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
@ -107,9 +106,9 @@ func MultiPanelCreate(ctx *gin.Context) {
},
}
multiPanel.Id, err = dbclient.Client.MultiPanels.Create(ctx, multiPanel)
multiPanel.Id, err = dbclient.Client.MultiPanels.Create(c, multiPanel)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -118,16 +117,16 @@ func MultiPanelCreate(ctx *gin.Context) {
panel := panel
group.Go(func() error {
return dbclient.Client.MultiPanelTargets.Insert(ctx, multiPanel.Id, panel.PanelId)
return dbclient.Client.MultiPanelTargets.Insert(c, multiPanel.Id, panel.PanelId)
})
}
if err := group.Wait(); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.JSON(200, gin.H{
c.JSON(200, gin.H{
"success": true,
"data": multiPanel,
})

View File

@ -1,61 +1,70 @@
package api
import (
"context"
"errors"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/botcontext"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/rest"
"github.com/rxdn/gdl/rest/request"
"net/http"
"strconv"
)
func MultiPanelDelete(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func MultiPanelDelete(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
multiPanelId, err := strconv.Atoi(ctx.Param("panelid"))
multiPanelId, err := strconv.Atoi(c.Param("panelid"))
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// get bot context
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
panel, ok, err := dbclient.Client.MultiPanels.Get(ctx, multiPanelId)
panel, ok, err := dbclient.Client.MultiPanels.Get(c, multiPanelId)
if !ok {
ctx.JSON(404, utils.ErrorStr("No panel with matching ID found"))
c.JSON(404, utils.ErrorStr("No panel with matching ID found"))
return
}
if panel.GuildId != guildId {
ctx.JSON(403, utils.ErrorStr("Guild ID doesn't match"))
c.JSON(403, utils.ErrorStr("Guild ID doesn't match"))
return
}
var unwrapped request.RestError
// TODO: Use proper context
if err := rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil && !(errors.As(err, &unwrapped) && unwrapped.IsClientError()) {
ctx.JSON(500, utils.ErrorJson(err))
return
if err := rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
// Swallow 403 / 404
if unwrapped.StatusCode != http.StatusForbidden && unwrapped.StatusCode != http.StatusNotFound {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
success, err := dbclient.Client.MultiPanels.Delete(ctx, guildId, multiPanelId)
success, err := dbclient.Client.MultiPanels.Delete(c, guildId, multiPanelId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if !success {
ctx.JSON(404, utils.ErrorJson(errors.New("No panel with matching ID found")))
c.JSON(404, utils.ErrorJson(errors.New("No panel with matching ID found")))
return
}
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}

View File

@ -15,6 +15,7 @@ import (
"github.com/rxdn/gdl/rest"
"github.com/rxdn/gdl/rest/request"
"golang.org/x/sync/errgroup"
"net/http"
"strconv"
)
@ -24,21 +25,21 @@ func MultiPanelUpdate(c *gin.Context) {
// parse body
var data multiPanelCreateData
if err := c.ShouldBindJSON(&data); err != nil {
c.JSON(400, utils.ErrorJson(err))
c.JSON(400, utils.ErrorStr("Invalid request body"))
return
}
// parse panel ID
panelId, err := strconv.Atoi(c.Param("panelid"))
if err != nil {
c.JSON(400, utils.ErrorJson(err))
c.JSON(400, utils.ErrorStr("Missing panel ID"))
return
}
// retrieve panel from DB
multiPanel, ok, err := dbclient.Client.MultiPanels.Get(c, panelId)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -57,7 +58,7 @@ func MultiPanelUpdate(c *gin.Context) {
if err := validate.Struct(data); err != nil {
var validationErrors validator.ValidationErrors
if ok := errors.As(err, &validationErrors); !ok {
c.JSON(500, utils.ErrorStr("An error occurred while validating the panel"))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewError(err, "An error occurred while validating the panel"))
return
}
@ -77,12 +78,12 @@ func MultiPanelUpdate(c *gin.Context) {
if panel.CustomId == "" {
panel.CustomId, err = utils.RandString(30)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if err := dbclient.Client.Panel.Update(c, panel); err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
@ -91,7 +92,7 @@ func MultiPanelUpdate(c *gin.Context) {
// get bot context
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -99,17 +100,19 @@ func MultiPanelUpdate(c *gin.Context) {
ctx, cancel := app.DefaultContext()
defer cancel()
var unwrapped request.RestError
if err := rest.DeleteMessage(ctx, botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId); err != nil && !(errors.As(err, &unwrapped) && unwrapped.IsClientError()) {
c.JSON(500, utils.ErrorJson(err))
return
if err := rest.DeleteMessage(ctx, botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId); err != nil {
var unwrapped request.RestError
if !errors.As(err, &unwrapped) || !unwrapped.IsClientError() {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
cancel()
// get premium status
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(c, guildId, true, botContext.Token, botContext.RateLimiter)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -119,9 +122,9 @@ func MultiPanelUpdate(c *gin.Context) {
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) && unwrapped.StatusCode == 403 {
c.JSON(500, utils.ErrorJson(errors.New("I do not have permission to send messages in the provided channel")))
c.JSON(http.StatusBadRequest, utils.ErrorJson(errors.New("I do not have permission to send messages in the provided channel")))
} else {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
@ -143,14 +146,14 @@ func MultiPanelUpdate(c *gin.Context) {
}
if err = dbclient.Client.MultiPanels.Update(c, multiPanel.Id, updated); err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// TODO: one query for ACID purposes
// delete old targets
if err := dbclient.Client.MultiPanelTargets.DeleteAll(c, multiPanel.Id); err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -165,7 +168,7 @@ func MultiPanelUpdate(c *gin.Context) {
}
if err := group.Wait(); err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}

View File

@ -18,6 +18,7 @@ import (
"github.com/rxdn/gdl/objects/guild/emoji"
"github.com/rxdn/gdl/objects/interaction/component"
"github.com/rxdn/gdl/rest/request"
"net/http"
"strconv"
)
@ -70,14 +71,14 @@ func CreatePanel(c *gin.Context) {
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
var data panelBody
if err := c.BindJSON(&data); err != nil {
c.JSON(400, utils.ErrorJson(err))
c.JSON(400, utils.ErrorStr("Invalid request body"))
return
}
@ -86,14 +87,14 @@ func CreatePanel(c *gin.Context) {
// Check panel quota
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(c, guildId, false, botContext.Token, botContext.RateLimiter)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if premiumTier == premium.None {
panels, err := dbclient.Client.Panel.GetByGuild(c, guildId)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -111,13 +112,13 @@ func CreatePanel(c *gin.Context) {
channels, err := botContext.GetGuildChannels(ctx, guildId)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
roles, err := botContext.GetGuildRoles(ctx, guildId)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -136,7 +137,7 @@ func CreatePanel(c *gin.Context) {
if errors.As(err, &validationError) {
c.JSON(400, utils.ErrorStr(validationError.Error()))
} else {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
@ -157,7 +158,7 @@ func CreatePanel(c *gin.Context) {
customId, err := utils.RandString(30)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -165,11 +166,14 @@ func CreatePanel(c *gin.Context) {
msgId, err := messageData.send(botContext)
if err != nil {
var unwrapped request.RestError
if errors.As(err, &unwrapped) && unwrapped.StatusCode == 403 {
c.JSON(500, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == http.StatusForbidden {
c.JSON(400, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
} else {
c.JSON(400, utils.ErrorStr("Error sending panel message: "+unwrapped.ApiError.Message))
}
} else {
// TODO: Most appropriate error?
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
@ -196,7 +200,7 @@ func CreatePanel(c *gin.Context) {
id, err := dbclient.Client.Embeds.CreateWithFields(c, embed, fields)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -256,7 +260,7 @@ func CreatePanel(c *gin.Context) {
panelId, err := storePanel(c, panel, createOptions)
if err != nil {
c.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}

View File

@ -1,8 +1,8 @@
package api
import (
"context"
"errors"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/botcontext"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/rpc"
@ -11,74 +11,75 @@ import (
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/rest"
"github.com/rxdn/gdl/rest/request"
"net/http"
"strconv"
)
func DeletePanel(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func DeletePanel(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
panelId, err := strconv.Atoi(ctx.Param("panelid"))
panelId, err := strconv.Atoi(c.Param("panelid"))
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
c.JSON(400, utils.ErrorStr("Missing panel ID"))
return
}
panel, err := database.Client.Panel.GetById(ctx, panelId)
panel, err := database.Client.Panel.GetById(c, panelId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if panel.PanelId == 0 {
ctx.JSON(404, utils.ErrorStr("Panel not found"))
c.JSON(404, utils.ErrorStr("Panel not found"))
return
}
// verify panel belongs to guild
if panel.GuildId != guildId {
ctx.JSON(403, utils.ErrorStr("Guild ID doesn't match"))
c.JSON(403, utils.ErrorStr("Guild ID doesn't match"))
return
}
// Get any multi panels this panel is part of to use later
multiPanels, err := database.Client.MultiPanelTargets.GetMultiPanels(ctx, panelId)
multiPanels, err := database.Client.MultiPanelTargets.GetMultiPanels(c, panelId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Delete welcome message embed
if panel.WelcomeMessageEmbed != nil {
if err := database.Client.Embeds.Delete(ctx, *panel.WelcomeMessageEmbed); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := database.Client.Embeds.Delete(c, *panel.WelcomeMessageEmbed); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
if err := database.Client.Panel.Delete(ctx, panelId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := database.Client.Panel.Delete(c, panelId); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// TODO: Use proper context
if err := rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil {
// TODO: Set timeout on context
if err := rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, panel.ChannelId, panel.MessageId); err != nil {
var unwrapped request.RestError
if !errors.As(err, &unwrapped) || unwrapped.StatusCode != 404 {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
// Get premium tier
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(ctx, guildId, true, botContext.Token, botContext.RateLimiter)
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(c, guildId, true, botContext.Token, botContext.RateLimiter)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -89,9 +90,9 @@ func DeletePanel(ctx *gin.Context) {
break
}
panels, err := database.Client.MultiPanelTargets.GetPanels(ctx, multiPanel.Id)
panels, err := database.Client.MultiPanelTargets.GetPanels(c, multiPanel.Id)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -99,19 +100,19 @@ func DeletePanel(ctx *gin.Context) {
messageId, err := messageData.send(botContext, panels)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if err := database.Client.MultiPanels.UpdateMessageId(ctx, multiPanel.Id, messageId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := database.Client.MultiPanels.UpdateMessageId(c, multiPanel.Id, messageId); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Delete old panel
// TODO: Use proper context
_ = rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId)
_ = rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId)
}
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}

View File

@ -3,6 +3,7 @@ package api
import (
"context"
"errors"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/app/http/validation"
"github.com/TicketsBot/GoPanel/botcontext"
dbclient "github.com/TicketsBot/GoPanel/database"
@ -16,68 +17,69 @@ import (
"github.com/rxdn/gdl/objects/interaction/component"
"github.com/rxdn/gdl/rest"
"github.com/rxdn/gdl/rest/request"
"net/http"
"strconv"
)
func UpdatePanel(ctx *gin.Context) {
guildId := ctx.Keys["guildid"].(uint64)
func UpdatePanel(c *gin.Context) {
guildId := c.Keys["guildid"].(uint64)
botContext, err := botcontext.ContextForGuild(guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
var data panelBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, utils.ErrorJson(err))
if err := c.BindJSON(&data); err != nil {
c.JSON(400, utils.ErrorStr("Invalid request body"))
return
}
panelId, err := strconv.Atoi(ctx.Param("panelid"))
panelId, err := strconv.Atoi(c.Param("panelid"))
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
c.JSON(400, utils.ErrorStr("Missing panel ID"))
return
}
// get existing
existing, err := dbclient.Client.Panel.GetById(ctx, panelId)
existing, err := dbclient.Client.Panel.GetById(c, panelId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// check guild ID matches
if existing.GuildId != guildId {
ctx.JSON(400, utils.ErrorStr("Guild ID does not match"))
c.JSON(400, utils.ErrorStr("Guild ID does not match"))
return
}
if existing.ForceDisabled {
ctx.JSON(400, utils.ErrorStr("This panel is disabled and cannot be modified: please reactivate premium to re-enable it"))
c.JSON(400, utils.ErrorStr("This panel is disabled and cannot be modified: please reactivate premium to re-enable it"))
return
}
// Apply defaults
ApplyPanelDefaults(&data)
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(ctx, guildId, true, botContext.Token, botContext.RateLimiter)
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(c, guildId, true, botContext.Token, botContext.RateLimiter)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// TODO: Use proper context
channels, err := botContext.GetGuildChannels(context.Background(), guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// TODO: Use proper context
roles, err := botContext.GetGuildRoles(context.Background(), guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
c.JSON(500, utils.ErrorJson(err))
return
}
@ -94,9 +96,9 @@ func UpdatePanel(ctx *gin.Context) {
if err := ValidatePanelBody(validationContext); err != nil {
var validationError *validation.InvalidInputError
if errors.As(err, &validationError) {
ctx.JSON(400, utils.ErrorStr(validationError.Error()))
c.JSON(400, utils.ErrorStr(validationError.Error()))
} else {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
@ -104,14 +106,14 @@ func UpdatePanel(ctx *gin.Context) {
// Do tag validation
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 panel"))
var validationErrors validator.ValidationErrors
if !errors.As(err, &validationErrors) {
c.JSON(500, utils.ErrorStr("An error occurred while validating the panel"))
return
}
formatted := "Your input contained the following errors:\n" + utils.FormatValidationErrors(validationErrors)
ctx.JSON(400, utils.ErrorStr(formatted))
c.JSON(400, utils.ErrorStr(formatted))
return
}
@ -146,7 +148,7 @@ func UpdatePanel(ctx *gin.Context) {
if shouldUpdateMessage {
// delete old message, ignoring error
// TODO: Use proper context
_ = rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, existing.ChannelId, existing.MessageId)
_ = rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, existing.ChannelId, existing.MessageId)
messageData := data.IntoPanelMessageData(existing.CustomId, premiumTier > premium.None)
newMessageId, err = messageData.send(botContext)
@ -154,16 +156,17 @@ func UpdatePanel(ctx *gin.Context) {
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == 403 {
ctx.JSON(403, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
c.JSON(403, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
return
} else if unwrapped.StatusCode == 404 {
// Swallow error
// TODO: Make channel_id column nullable, and set to null
} else {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
} else {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
@ -173,8 +176,8 @@ func UpdatePanel(ctx *gin.Context) {
var welcomeMessageEmbed *int
if data.WelcomeMessage == nil {
if existing.WelcomeMessageEmbed != nil { // If welcome message wasn't null, but now is, delete the embed
if err := dbclient.Client.Embeds.Delete(ctx, *existing.WelcomeMessageEmbed); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.Embeds.Delete(c, *existing.WelcomeMessageEmbed); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
} // else, welcomeMessageEmbed will be nil
@ -184,9 +187,9 @@ func UpdatePanel(ctx *gin.Context) {
embed, fields := data.WelcomeMessage.IntoDatabaseStruct()
embed.GuildId = guildId
id, err := dbclient.Client.Embeds.CreateWithFields(ctx, embed, fields)
id, err := dbclient.Client.Embeds.CreateWithFields(c, embed, fields)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -198,8 +201,8 @@ func UpdatePanel(ctx *gin.Context) {
embed.Id = *existing.WelcomeMessageEmbed
embed.GuildId = guildId
if err := dbclient.Client.Embeds.UpdateWithFields(ctx, embed, fields); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.Embeds.UpdateWithFields(c, embed, fields); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
@ -243,7 +246,7 @@ func UpdatePanel(ctx *gin.Context) {
} else {
roleId, err := strconv.ParseUint(mention, 10, 64)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -253,25 +256,25 @@ func UpdatePanel(ctx *gin.Context) {
}
}
err = dbclient.Client.Panel.BeginFunc(ctx, func(tx pgx.Tx) error {
if err := dbclient.Client.Panel.UpdateWithTx(ctx, tx, panel); err != nil {
err = dbclient.Client.Panel.BeginFunc(c, func(tx pgx.Tx) error {
if err := dbclient.Client.Panel.UpdateWithTx(c, tx, panel); err != nil {
return err
}
if err := dbclient.Client.PanelUserMention.SetWithTx(ctx, tx, panel.PanelId, shouldMentionUser); err != nil {
if err := dbclient.Client.PanelUserMention.SetWithTx(c, tx, panel.PanelId, shouldMentionUser); err != nil {
return err
}
if err := dbclient.Client.PanelRoleMentions.ReplaceWithTx(ctx, tx, panel.PanelId, roleMentions); err != nil {
if err := dbclient.Client.PanelRoleMentions.ReplaceWithTx(c, tx, panel.PanelId, roleMentions); err != nil {
return err
}
// We are safe to insert, team IDs already validated
if err := dbclient.Client.PanelTeams.ReplaceWithTx(ctx, tx, panel.PanelId, data.Teams); err != nil {
if err := dbclient.Client.PanelTeams.ReplaceWithTx(c, tx, panel.PanelId, data.Teams); err != nil {
return err
}
if err := dbclient.Client.PanelAccessControlRules.ReplaceWithTx(ctx, tx, panel.PanelId, data.AccessControlList); err != nil {
if err := dbclient.Client.PanelAccessControlRules.ReplaceWithTx(c, tx, panel.PanelId, data.AccessControlList); err != nil {
return err
}
@ -279,7 +282,7 @@ func UpdatePanel(ctx *gin.Context) {
})
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -288,9 +291,9 @@ func UpdatePanel(ctx *gin.Context) {
// check if this will break a multi-panel;
// first, get any multipanels this panel belongs to
multiPanels, err := dbclient.Client.MultiPanelTargets.GetMultiPanels(ctx, existing.PanelId)
multiPanels, err := dbclient.Client.MultiPanelTargets.GetMultiPanels(c, existing.PanelId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -300,9 +303,9 @@ func UpdatePanel(ctx *gin.Context) {
break
}
panels, err := dbclient.Client.MultiPanelTargets.GetPanels(ctx, multiPanel.Id)
panels, err := dbclient.Client.MultiPanelTargets.GetPanels(c, multiPanel.Id)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -310,19 +313,29 @@ func UpdatePanel(ctx *gin.Context) {
messageId, err := messageData.send(botContext, panels)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
var unwrapped request.RestError
if errors.As(err, &unwrapped) {
if unwrapped.StatusCode == http.StatusForbidden {
c.JSON(400, utils.ErrorStr("I do not have permission to send messages in the specified channel"))
} else {
c.JSON(400, utils.ErrorStr("Error sending panel message: "+unwrapped.ApiError.Message))
}
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
}
if err := dbclient.Client.MultiPanels.UpdateMessageId(ctx, multiPanel.Id, messageId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.MultiPanels.UpdateMessageId(c, multiPanel.Id, messageId); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Delete old panel
// TODO: Use proper context
_ = rest.DeleteMessage(context.Background(), botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId)
_ = rest.DeleteMessage(c, botContext.Token, botContext.RateLimiter, multiPanel.ChannelId, multiPanel.MessageId)
}
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}

View File

@ -1,20 +1,29 @@
package api
import (
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/GoPanel/redis"
"github.com/TicketsBot/common/whitelabeldelete"
"github.com/gin-gonic/gin"
"net/http"
)
func WhitelabelDelete(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
func WhitelabelDelete(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
// Check if this is a different token
if err := database.Client.Whitelabel.Delete(ctx, userId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
botId, err := database.Client.Whitelabel.Delete(c, userId)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.Status(http.StatusNoContent)
if botId != nil {
// TODO: Kafka
go whitelabeldelete.Publish(redis.Client.Client, *botId)
}
c.Status(http.StatusNoContent)
}

View File

@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/botcontext"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/redis"
@ -11,6 +12,7 @@ import (
"github.com/TicketsBot/worker/bot/command/manager"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/rest"
"net/http"
"time"
)
@ -19,33 +21,33 @@ func GetWhitelabelCreateInteractions() func(*gin.Context) {
cm := new(manager.CommandManager)
cm.RegisterCommands()
return func(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
return func(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
// Get bot
bot, err := database.Client.Whitelabel.GetByUserId(ctx, userId)
bot, err := database.Client.Whitelabel.GetByUserId(c, userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Ensure bot exists
if bot.BotId == 0 {
ctx.JSON(404, utils.ErrorStr("No bot found"))
c.JSON(404, utils.ErrorStr("No bot found"))
return
}
if err := createInteractions(cm, bot.BotId, bot.Token); err != nil {
if errors.Is(err, ErrInteractionCreateCooldown) {
ctx.JSON(400, utils.ErrorJson(err))
c.JSON(http.StatusTooManyRequests, utils.ErrorJson(err))
} else {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
}
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}
}

View File

@ -2,55 +2,48 @@ package api
import (
"context"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/objects/user"
"github.com/rxdn/gdl/rest"
"net/http"
)
type whitelabelResponse struct {
Id uint64 `json:"id,string"`
PublicKey string `json:"public_key"`
Username string `json:"username"`
Id uint64 `json:"id,string"`
Username string `json:"username"`
statusUpdateBody
}
func WhitelabelGet(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
func WhitelabelGet(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
// Check if this is a different token
bot, err := database.Client.Whitelabel.GetByUserId(ctx, userId)
bot, err := database.Client.Whitelabel.GetByUserId(c, userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if bot.BotId == 0 {
ctx.JSON(404, utils.ErrorStr("No bot found"))
return
}
// Get public key
publicKey, err := database.Client.WhitelabelKeys.Get(ctx, bot.BotId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
c.JSON(404, utils.ErrorStr("No bot found"))
return
}
// Get status
status, statusType, _, err := database.Client.WhitelabelStatuses.Get(ctx, bot.BotId)
status, statusType, _, err := database.Client.WhitelabelStatuses.Get(c, bot.BotId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
username := getBotUsername(context.Background(), bot.Token)
username := getBotUsername(c, bot.Token)
ctx.JSON(200, whitelabelResponse{
Id: bot.BotId,
PublicKey: publicKey,
Username: username,
c.JSON(200, whitelabelResponse{
Id: bot.BotId,
Username: username,
statusUpdateBody: statusUpdateBody{ // Zero values if no status is fine
Status: status,
StatusType: user.ActivityType(statusType),

View File

@ -1,21 +1,22 @@
package api
import (
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
"net/http"
)
func WhitelabelGetErrors(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
func WhitelabelGetErrors(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
errors, err := database.Client.WhitelabelErrors.GetRecent(ctx, userId, 10)
errors, err := database.Client.WhitelabelErrors.GetRecent(c, userId, 10)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.JSON(200, gin.H{
c.JSON(200, gin.H{
"success": true,
"errors": errors,
})

View File

@ -3,40 +3,45 @@ package api
import (
"context"
"errors"
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/rpc/cache"
"github.com/TicketsBot/GoPanel/utils"
"github.com/gin-gonic/gin"
cache2 "github.com/rxdn/gdl/cache"
"net/http"
"strconv"
)
func WhitelabelGetGuilds(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
func WhitelabelGetGuilds(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
bot, err := database.Client.Whitelabel.GetByUserId(ctx, userId)
bot, err := database.Client.Whitelabel.GetByUserId(c, userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// id -> name
guilds := make(map[string]string)
if bot.BotId == 0 {
ctx.JSON(404, gin.H{
"success": false,
"guilds": guilds,
})
c.JSON(400, utils.ErrorStr("Whitelabel bot not found"))
return
}
ids, err := database.Client.WhitelabelGuilds.GetGuilds(ctx, bot.BotId)
ids, err := database.Client.WhitelabelGuilds.GetGuilds(c, bot.BotId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
for _, id := range ids {
guilds := make(map[string]string)
for i, id := range ids {
if i >= 10 {
idStr := strconv.FormatUint(id, 10)
guilds[idStr] = idStr
continue
}
// get guild name
// TODO: Use proper context
guild, err := cache.Instance.GetGuild(context.Background(), id)
@ -44,7 +49,7 @@ func WhitelabelGetGuilds(ctx *gin.Context) {
if errors.Is(err, cache2.ErrNotFound) {
continue
} else {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
}
@ -52,7 +57,7 @@ func WhitelabelGetGuilds(ctx *gin.Context) {
guilds[strconv.FormatUint(id, 10)] = guild.Name
}
ctx.JSON(200, gin.H{
c.JSON(200, gin.H{
"success": true,
"guilds": guilds,
})

View File

@ -3,7 +3,9 @@ package api
import (
"context"
"encoding/base64"
"errors"
"fmt"
"github.com/TicketsBot/GoPanel/app"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/redis"
"github.com/TicketsBot/GoPanel/utils"
@ -14,6 +16,8 @@ import (
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/objects/application"
"github.com/rxdn/gdl/rest"
"github.com/rxdn/gdl/rest/request"
"net/http"
"strconv"
"strings"
)
@ -22,8 +26,8 @@ func WhitelabelPost() func(*gin.Context) {
cm := new(manager.CommandManager)
cm.RegisterCommands()
return func(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
return func(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
type whitelabelPostBody struct {
Token string `json:"token"`
@ -31,24 +35,29 @@ func WhitelabelPost() func(*gin.Context) {
// Get token
var data whitelabelPostBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, gin.H{
"success": false,
"error": "Missing token",
})
if err := c.BindJSON(&data); err != nil {
c.JSON(http.StatusBadRequest, utils.ErrorStr("Invalid request body"))
return
}
bot, err := fetchApplication(data.Token)
bot, err := fetchApplication(c, data.Token)
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
var restError request.RestError
if errors.Is(err, errInvalidToken) {
c.JSON(http.StatusBadRequest, utils.ErrorStr("Invalid token"))
} else if errors.As(err, &restError) && restError.StatusCode == http.StatusUnauthorized {
c.JSON(http.StatusBadRequest, utils.ErrorStr("Invalid token"))
} else {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
}
return
}
// Check if this is a different token
existing, err := dbclient.Client.Whitelabel.GetByUserId(ctx, userId)
existing, err := dbclient.Client.Whitelabel.GetByUserId(c, userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -59,17 +68,18 @@ func WhitelabelPost() func(*gin.Context) {
// Set token in DB so that http-gateway can use it when Discord validates the interactions endpoint
// TODO: Use a transaction
if err := dbclient.Client.Whitelabel.Set(ctx, database.WhitelabelBot{
UserId: userId,
BotId: bot.Id,
Token: data.Token,
if err := dbclient.Client.Whitelabel.Set(c, database.WhitelabelBot{
UserId: userId,
BotId: bot.Id,
PublicKey: bot.VerifyKey,
Token: data.Token,
}); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if err := dbclient.Client.WhitelabelKeys.Set(ctx, bot.Id, bot.VerifyKey); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.WhitelabelKeys.Set(c, bot.Id, bot.VerifyKey); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -91,12 +101,12 @@ func WhitelabelPost() func(*gin.Context) {
if _, err := rest.EditCurrentApplication(context.Background(), data.Token, nil, editData); err != nil {
// TODO: Use a transaction
if err := dbclient.Client.Whitelabel.Delete(ctx, bot.Id); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := dbclient.Client.Whitelabel.Delete(c, bot.Id); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
@ -107,16 +117,16 @@ func WhitelabelPost() func(*gin.Context) {
}
if err := tokenchange.PublishTokenChange(redis.Client.Client, tokenChangeData); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
if err := createInteractions(cm, bot.Id, data.Token); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
ctx.JSON(200, gin.H{
c.JSON(200, gin.H{
"success": true,
"bot": bot,
"username": bot.Bot.Username,
@ -124,6 +134,8 @@ func WhitelabelPost() func(*gin.Context) {
}
}
var errInvalidToken = fmt.Errorf("invalid token")
func validateToken(token string) bool {
split := strings.Split(token, ".")
@ -151,20 +163,20 @@ func validateToken(token string) bool {
return true
}
func fetchApplication(token string) (*application.Application, error) {
func fetchApplication(ctx context.Context, token string) (*application.Application, error) {
if !validateToken(token) {
return nil, fmt.Errorf("Invalid token")
return nil, errInvalidToken
}
// Validate token + get bot ID
// TODO: Use proper context
app, err := rest.GetCurrentApplication(context.Background(), token, nil)
app, err := rest.GetCurrentApplication(ctx, token, nil)
if err != nil {
return nil, err
}
if app.Id == 0 {
return nil, fmt.Errorf("Invalid token")
return nil, errInvalidToken
}
return &app, nil

View File

@ -1,12 +1,14 @@
package api
import (
"github.com/TicketsBot/GoPanel/app"
"github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/redis"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/common/statusupdates"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/objects/user"
"net/http"
)
type statusUpdateBody struct {
@ -14,32 +16,32 @@ type statusUpdateBody struct {
StatusType user.ActivityType `json:"status_type,string"`
}
func WhitelabelStatusPost(ctx *gin.Context) {
userId := ctx.Keys["userid"].(uint64)
func WhitelabelStatusPost(c *gin.Context) {
userId := c.Keys["userid"].(uint64)
// Get bot
bot, err := database.Client.Whitelabel.GetByUserId(ctx, userId)
bot, err := database.Client.Whitelabel.GetByUserId(c, userId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Ensure bot exists
if bot.BotId == 0 {
ctx.JSON(404, utils.ErrorStr("No bot found"))
c.JSON(404, utils.ErrorStr("No bot found"))
return
}
// Parse status
var data statusUpdateBody
if err := ctx.BindJSON(&data); err != nil {
ctx.JSON(400, utils.ErrorStr("Invalid request body"))
if err := c.BindJSON(&data); err != nil {
c.JSON(400, utils.ErrorStr("Invalid request body"))
return
}
// Validate status length
if len(data.Status) == 0 || len(data.Status) > 255 {
ctx.JSON(400, utils.ErrorStr("Status must be between 1-255 characters in length"))
c.JSON(400, utils.ErrorStr("Status must be between 1-255 characters in length"))
return
}
@ -51,18 +53,18 @@ func WhitelabelStatusPost(ctx *gin.Context) {
}
if !utils.Contains(validActivities, data.StatusType) {
ctx.JSON(400, utils.ErrorStr("Invalid status type"))
c.JSON(400, utils.ErrorStr("Invalid status type"))
return
}
// Update in database
if err := database.Client.WhitelabelStatuses.Set(ctx, bot.BotId, data.Status, int16(data.StatusType)); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
if err := database.Client.WhitelabelStatuses.Set(c, bot.BotId, data.Status, int16(data.StatusType)); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, app.NewServerError(err))
return
}
// Send status update to sharder
go statusupdates.Publish(redis.Client.Client, bot.BotId)
ctx.JSON(200, utils.SuccessResponse)
c.JSON(200, utils.SuccessResponse)
}

2
go.mod
View File

@ -8,7 +8,7 @@ require (
github.com/BurntSushi/toml v1.2.1
github.com/TicketsBot/archiverclient v0.0.0-20241012221057-16a920bfb454
github.com/TicketsBot/common v0.0.0-20241104184641-e39c64bdcf3e
github.com/TicketsBot/database v0.0.0-20241113215509-c84281e50a7e
github.com/TicketsBot/database v0.0.0-20241116202646-1741ded5d50f
github.com/TicketsBot/logarchiver v0.0.0-20241012220745-5f3ba17a5138
github.com/TicketsBot/worker v0.0.0-20241110222533-ba74e19de868
github.com/apex/log v1.1.2

4
go.sum
View File

@ -51,6 +51,10 @@ github.com/TicketsBot/database v0.0.0-20241110235041-04a08e1a42a4 h1:9YMD+x2nBQN
github.com/TicketsBot/database v0.0.0-20241110235041-04a08e1a42a4/go.mod h1:mpVkDO8tnnWn1pMGEphVg6YSeGIhDwLAN43lBTkpGmU=
github.com/TicketsBot/database v0.0.0-20241113215509-c84281e50a7e h1:8nvgWvmFAJfjuAUhaGdOO9y7puPAOHRjgGWn+/DI/HA=
github.com/TicketsBot/database v0.0.0-20241113215509-c84281e50a7e/go.mod h1:mpVkDO8tnnWn1pMGEphVg6YSeGIhDwLAN43lBTkpGmU=
github.com/TicketsBot/database v0.0.0-20241116201101-f77e9f58a6e0 h1:zVh8CnjkMh3qS+n/H5rOWL9E1RGOJYNi8kktMw21YZE=
github.com/TicketsBot/database v0.0.0-20241116201101-f77e9f58a6e0/go.mod h1:mpVkDO8tnnWn1pMGEphVg6YSeGIhDwLAN43lBTkpGmU=
github.com/TicketsBot/database v0.0.0-20241116202646-1741ded5d50f h1:CdYauI7Vkg0O9a/j8eZTFue2payodBblXkS6jqjrss4=
github.com/TicketsBot/database v0.0.0-20241116202646-1741ded5d50f/go.mod h1:mpVkDO8tnnWn1pMGEphVg6YSeGIhDwLAN43lBTkpGmU=
github.com/TicketsBot/logarchiver v0.0.0-20241012220745-5f3ba17a5138 h1:wsR5ESeaQKo122qsmzPcblxlJdE0GIQbp2B/7/uX+TA=
github.com/TicketsBot/logarchiver v0.0.0-20241012220745-5f3ba17a5138/go.mod h1:4Rq0CgSCgXVW6uEyEUvWzxOmFp+L57rFfCjPDFPHFiw=
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261 h1:NHD5GB6cjlkpZFjC76Yli2S63/J2nhr8MuE6KlYJpQM=