Forms
This commit is contained in:
parent
54cf2521e5
commit
116e5d6e05
45
app/http/endpoints/api/forms/createform.go
Normal file
45
app/http/endpoints/api/forms/createform.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/TicketsBot/database"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
type createFormBody struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateForm(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
var data createFormBody
|
||||||
|
if err := ctx.BindJSON(&data); err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.Title) > 255 {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Title is too long"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 26^50 chance of collision
|
||||||
|
customId := utils.RandString(50)
|
||||||
|
|
||||||
|
id, err := dbclient.Client.Forms.Create(guildId, data.Title, customId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
form := database.Form{
|
||||||
|
Id: id,
|
||||||
|
GuildId: guildId,
|
||||||
|
Title: data.Title,
|
||||||
|
CustomId: customId,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, form)
|
||||||
|
}
|
119
app/http/endpoints/api/forms/createinput.go
Normal file
119
app/http/endpoints/api/forms/createinput.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/TicketsBot/database"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/rxdn/gdl/objects/interaction/component"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type inputCreateBody struct {
|
||||||
|
Style component.TextStyleTypes `json:"style"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Placeholder *string `json:"placeholder"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateInput(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
var data inputCreateBody
|
||||||
|
if err := ctx.BindJSON(&data); err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate body
|
||||||
|
if !data.Validate(ctx) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse form ID from URL
|
||||||
|
formId, err := strconv.Atoi(ctx.Param("form_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get form and validate it belongs to the guild
|
||||||
|
form, ok, err := dbclient.Client.Forms.Get(formId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Form not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.GuildId != guildId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check there are not more than 25 inputs already
|
||||||
|
// TODO: This is vulnerable to a race condition
|
||||||
|
inputCount, err := getFormInputCount(formId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if inputCount >= 5 {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("A form cannot have more than 5 inputs"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2^30 chance of collision
|
||||||
|
customId := utils.RandString(30)
|
||||||
|
|
||||||
|
formInputId, err := dbclient.Client.FormInput.Create(formId, customId, uint8(data.Style), data.Label, data.Placeholder)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, database.FormInput{
|
||||||
|
Id: formInputId,
|
||||||
|
FormId: formId,
|
||||||
|
CustomId: customId,
|
||||||
|
Style: uint8(data.Style),
|
||||||
|
Label: data.Label,
|
||||||
|
Placeholder: data.Placeholder,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *inputCreateBody) Validate(ctx *gin.Context) bool {
|
||||||
|
if b.Style != component.TextStyleShort && b.Style != component.TextStyleParagraph {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid style"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(b.Label) == 0 || len(b.Label) > 255 {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("The input label must be between 1 and 255 characters"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Placeholder != nil && len(*b.Placeholder) == 0 {
|
||||||
|
b.Placeholder = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Placeholder != nil && len(*b.Placeholder) > 100 {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("The placeholder cannot be more than 100 characters"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use select count()
|
||||||
|
func getFormInputCount(formId int) (int, error) {
|
||||||
|
inputs, err := dbclient.Client.FormInput.GetInputs(formId)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(inputs), nil
|
||||||
|
}
|
41
app/http/endpoints/api/forms/deleteform.go
Normal file
41
app/http/endpoints/api/forms/deleteform.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteForm(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
formId, err := strconv.Atoi(ctx.Param("form_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
form, ok, err := dbclient.Client.Forms.Get(formId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Form not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.GuildId != guildId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dbclient.Client.Forms.Delete(formId); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, utils.SuccessResponse)
|
||||||
|
}
|
63
app/http/endpoints/api/forms/deleteinput.go
Normal file
63
app/http/endpoints/api/forms/deleteinput.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteInput(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
formId, err := strconv.Atoi(ctx.Param("form_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
inputId, err := strconv.Atoi(ctx.Param("input_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
form, ok, err := dbclient.Client.Forms.Get(formId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Form not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.GuildId != guildId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
input, ok, err := dbclient.Client.FormInput.Get(inputId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Input not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.FormId != formId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Input does not belong to this form"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dbclient.Client.FormInput.Delete(input.Id, input.FormId); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, utils.SuccessResponse)
|
||||||
|
}
|
28
app/http/endpoints/api/forms/getforms.go
Normal file
28
app/http/endpoints/api/forms/getforms.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetForms(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
forms, err := dbclient.Client.Forms.GetForms(guildId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs, err := dbclient.Client.FormInput.GetInputsForGuild(guildId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, gin.H{
|
||||||
|
"forms": forms,
|
||||||
|
"inputs": inputs,
|
||||||
|
})
|
||||||
|
}
|
52
app/http/endpoints/api/forms/updateform.go
Normal file
52
app/http/endpoints/api/forms/updateform.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateForm(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
var data createFormBody
|
||||||
|
if err := ctx.BindJSON(&data); err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data.Title) > 255 {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Title is too long"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
formId, err := strconv.Atoi(ctx.Param("form_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
form, ok, err := dbclient.Client.Forms.Get(formId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Form not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.GuildId != guildId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dbclient.Client.Forms.UpdateTitle(formId, data.Title); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, utils.SuccessResponse)
|
||||||
|
}
|
83
app/http/endpoints/api/forms/updateinput.go
Normal file
83
app/http/endpoints/api/forms/updateinput.go
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package forms
|
||||||
|
|
||||||
|
import (
|
||||||
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||||
|
"github.com/TicketsBot/GoPanel/utils"
|
||||||
|
"github.com/TicketsBot/database"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UpdateInput(ctx *gin.Context) {
|
||||||
|
guildId := ctx.Keys["guildid"].(uint64)
|
||||||
|
|
||||||
|
var data inputCreateBody
|
||||||
|
if err := ctx.BindJSON(&data); err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !data.Validate(ctx) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
formId, err := strconv.Atoi(ctx.Param("form_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
inputId, err := strconv.Atoi(ctx.Param("input_id"))
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(400, utils.ErrorStr("Invalid form ID"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
form, ok, err := dbclient.Client.Forms.Get(formId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Form not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.GuildId != guildId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Form does not belong to this guild"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
input, ok, err := dbclient.Client.FormInput.Get(inputId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.JSON(404, utils.ErrorStr("Input not found"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.FormId != formId {
|
||||||
|
ctx.JSON(403, utils.ErrorStr("Input does not belong to this form"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newInput := database.FormInput{
|
||||||
|
Id: inputId,
|
||||||
|
FormId: formId,
|
||||||
|
CustomId: input.CustomId,
|
||||||
|
Style: uint8(data.Style),
|
||||||
|
Label: data.Label,
|
||||||
|
Placeholder: data.Placeholder,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := dbclient.Client.FormInput.Update(newInput); err != nil {
|
||||||
|
ctx.JSON(500, utils.ErrorJson(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(200, newInput)
|
||||||
|
}
|
@ -38,6 +38,7 @@ type panelBody struct {
|
|||||||
ImageUrl *string `json:"image_url,omitempty"`
|
ImageUrl *string `json:"image_url,omitempty"`
|
||||||
ThumbnailUrl *string `json:"thumbnail_url,omitempty"`
|
ThumbnailUrl *string `json:"thumbnail_url,omitempty"`
|
||||||
ButtonStyle component.ButtonStyle `json:"button_style,string"`
|
ButtonStyle component.ButtonStyle `json:"button_style,string"`
|
||||||
|
FormId int `json:"form_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData {
|
func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData {
|
||||||
@ -138,6 +139,11 @@ func CreatePanel(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var formId *int
|
||||||
|
if data.FormId != 0 { // Already validated
|
||||||
|
formId = &data.FormId
|
||||||
|
}
|
||||||
|
|
||||||
// Store in DB
|
// Store in DB
|
||||||
panel := database.Panel{
|
panel := database.Panel{
|
||||||
MessageId: msgId,
|
MessageId: msgId,
|
||||||
@ -154,6 +160,7 @@ func CreatePanel(ctx *gin.Context) {
|
|||||||
ImageUrl: data.ImageUrl,
|
ImageUrl: data.ImageUrl,
|
||||||
ThumbnailUrl: data.ThumbnailUrl,
|
ThumbnailUrl: data.ThumbnailUrl,
|
||||||
ButtonStyle: int(data.ButtonStyle),
|
ButtonStyle: int(data.ButtonStyle),
|
||||||
|
FormId: formId,
|
||||||
}
|
}
|
||||||
|
|
||||||
panelId, err := dbclient.Client.Panel.Create(panel)
|
panelId, err := dbclient.Client.Panel.Create(panel)
|
||||||
@ -305,6 +312,19 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ok, err := p.verifyFormId(guildId)
|
||||||
|
if err != nil {
|
||||||
|
ctx.AbortWithStatusJSON(500, utils.ErrorJson(err))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
ctx.AbortWithStatusJSON(400, utils.ErrorStr("Guild ID for form does not match"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,3 +403,24 @@ func (p *panelBody) verifyThumbnailUrl() bool {
|
|||||||
func (p *panelBody) verifyButtonStyle() bool {
|
func (p *panelBody) verifyButtonStyle() bool {
|
||||||
return p.ButtonStyle >= component.ButtonStylePrimary && p.ButtonStyle <= component.ButtonStyleDanger
|
return p.ButtonStyle >= component.ButtonStylePrimary && p.ButtonStyle <= component.ButtonStyleDanger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *panelBody) verifyFormId(guildId uint64) (bool, error) {
|
||||||
|
if p.FormId == 0 { // TODO: Use nil
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
form, ok, err := dbclient.Client.Forms.Get(p.FormId)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.GuildId != guildId {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -84,12 +84,12 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
messageData := multiPanelMessageData{
|
messageData := multiPanelMessageData{
|
||||||
Title: multiPanel.Title,
|
Title: multiPanel.Title,
|
||||||
Content: multiPanel.Content,
|
Content: multiPanel.Content,
|
||||||
Colour: multiPanel.Colour,
|
Colour: multiPanel.Colour,
|
||||||
ChannelId: multiPanel.ChannelId,
|
ChannelId: multiPanel.ChannelId,
|
||||||
SelectMenu: multiPanel.SelectMenu,
|
SelectMenu: multiPanel.SelectMenu,
|
||||||
IsPremium: premiumTier > premium.None,
|
IsPremium: premiumTier > premium.None,
|
||||||
}
|
}
|
||||||
|
|
||||||
messageId, err := messageData.send(&botContext, panels)
|
messageId, err := messageData.send(&botContext, panels)
|
||||||
@ -142,6 +142,12 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Already validated
|
||||||
|
var formId *int
|
||||||
|
if data.FormId != 0 {
|
||||||
|
formId = &data.FormId
|
||||||
|
}
|
||||||
|
|
||||||
// Store in DB
|
// Store in DB
|
||||||
panel := database.Panel{
|
panel := database.Panel{
|
||||||
PanelId: panelId,
|
PanelId: panelId,
|
||||||
@ -159,6 +165,7 @@ func UpdatePanel(ctx *gin.Context) {
|
|||||||
ImageUrl: data.ImageUrl,
|
ImageUrl: data.ImageUrl,
|
||||||
ThumbnailUrl: data.ThumbnailUrl,
|
ThumbnailUrl: data.ThumbnailUrl,
|
||||||
ButtonStyle: int(data.ButtonStyle),
|
ButtonStyle: int(data.ButtonStyle),
|
||||||
|
FormId: formId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = dbclient.Client.Panel.Update(panel); err != nil {
|
if err = dbclient.Client.Panel.Update(panel); err != nil {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
api_autoclose "github.com/TicketsBot/GoPanel/app/http/endpoints/api/autoclose"
|
api_autoclose "github.com/TicketsBot/GoPanel/app/http/endpoints/api/autoclose"
|
||||||
api_blacklist "github.com/TicketsBot/GoPanel/app/http/endpoints/api/blacklist"
|
api_blacklist "github.com/TicketsBot/GoPanel/app/http/endpoints/api/blacklist"
|
||||||
api_customisation "github.com/TicketsBot/GoPanel/app/http/endpoints/api/customisation"
|
api_customisation "github.com/TicketsBot/GoPanel/app/http/endpoints/api/customisation"
|
||||||
|
api_forms "github.com/TicketsBot/GoPanel/app/http/endpoints/api/forms"
|
||||||
api_panels "github.com/TicketsBot/GoPanel/app/http/endpoints/api/panel"
|
api_panels "github.com/TicketsBot/GoPanel/app/http/endpoints/api/panel"
|
||||||
api_settings "github.com/TicketsBot/GoPanel/app/http/endpoints/api/settings"
|
api_settings "github.com/TicketsBot/GoPanel/app/http/endpoints/api/settings"
|
||||||
api_tags "github.com/TicketsBot/GoPanel/app/http/endpoints/api/tags"
|
api_tags "github.com/TicketsBot/GoPanel/app/http/endpoints/api/tags"
|
||||||
@ -102,6 +103,14 @@ func StartServer() {
|
|||||||
guildAuthApiAdmin.PATCH("/multipanels/:panelid", api_panels.MultiPanelUpdate)
|
guildAuthApiAdmin.PATCH("/multipanels/:panelid", api_panels.MultiPanelUpdate)
|
||||||
guildAuthApiAdmin.DELETE("/multipanels/:panelid", api_panels.MultiPanelDelete)
|
guildAuthApiAdmin.DELETE("/multipanels/:panelid", api_panels.MultiPanelDelete)
|
||||||
|
|
||||||
|
guildAuthApiSupport.GET("/forms", api_forms.GetForms)
|
||||||
|
guildAuthApiAdmin.POST("/forms", rl(middleware.RateLimitTypeGuild, 30, time.Hour), api_forms.CreateForm)
|
||||||
|
guildAuthApiAdmin.PATCH("/forms/:form_id", rl(middleware.RateLimitTypeGuild, 30, time.Hour), api_forms.UpdateForm)
|
||||||
|
guildAuthApiAdmin.DELETE("/forms/:form_id", api_forms.DeleteForm)
|
||||||
|
guildAuthApiAdmin.POST("/forms/:form_id", api_forms.CreateInput)
|
||||||
|
guildAuthApiAdmin.PATCH("/forms/:form_id/:input_id", api_forms.UpdateInput)
|
||||||
|
guildAuthApiAdmin.DELETE("/forms/:form_id/:input_id", api_forms.DeleteInput)
|
||||||
|
|
||||||
// Should be a GET, but easier to take a body for development purposes
|
// Should be a GET, but easier to take a body for development purposes
|
||||||
guildAuthApiSupport.POST("/transcripts",
|
guildAuthApiSupport.POST("/transcripts",
|
||||||
rl(middleware.RateLimitTypeUser, 5, 5*time.Second),
|
rl(middleware.RateLimitTypeUser, 5, 5*time.Second),
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
||||||
<label for="input" class="form-label">{label}</label>
|
{#if label !== undefined}
|
||||||
|
<label for="input" class="form-label">{label}</label>
|
||||||
|
{/if}
|
||||||
<select id="input" class="form-input" on:change bind:value={value}>
|
<select id="input" class="form-input" on:change bind:value={value}>
|
||||||
<slot />
|
<slot />
|
||||||
</select>
|
</select>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4}>
|
<div class:col-1={col1} class:col-2={col2} class:col-3={col3} class:col-4={col4} class:col-3-4={col3_4}>
|
||||||
<label for="input" class="form-label">{label}</label>
|
<label for="input" class="form-label">{label}</label>
|
||||||
<textarea id="input" class="form-input" placeholder="{placeholder}" bind:value on:change on:input></textarea>
|
<textarea id="input" class="form-input" placeholder="{placeholder}" bind:value on:change on:input></textarea>
|
||||||
</div>
|
</div>
|
||||||
@ -12,6 +12,8 @@
|
|||||||
export let col2 = false;
|
export let col2 = false;
|
||||||
export let col3 = false;
|
export let col3 = false;
|
||||||
export let col4 = false;
|
export let col4 = false;
|
||||||
|
|
||||||
|
export let col3_4 = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
126
frontend/src/components/manage/FormInputRow.svelte
Normal file
126
frontend/src/components/manage/FormInputRow.svelte
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<form on:submit|preventDefault={forwardCreate} class="input-form">
|
||||||
|
<div class="row">
|
||||||
|
<div class="sub-row" style="flex: 1">
|
||||||
|
<Input col4={true} label="Label" bind:value={data.label} placeholder="Name of the field" />
|
||||||
|
</div>
|
||||||
|
<div class="sub-row buttons-row">
|
||||||
|
{#if windowWidth > 950}
|
||||||
|
{#if withSaveButton}
|
||||||
|
<form on:submit|preventDefault={forwardSave} class="button-form">
|
||||||
|
<Button icon="fas fa-save">Save</Button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
{#if withDeleteButton}
|
||||||
|
<form on:submit|preventDefault={forwardDelete} class="button-form">
|
||||||
|
<Button icon="fas fa-trash" danger={true}>Delete</Button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row settings-row">
|
||||||
|
<Textarea col3_4={true} label="Placeholder" bind:value={data.placeholder}
|
||||||
|
placeholder="Placeholder text for the field, just like this text" />
|
||||||
|
<Dropdown col4={true} label="Style" bind:value={data.style}>
|
||||||
|
<option value=1 selected>Short</option>
|
||||||
|
<option value=2>Paragraph</option>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if windowWidth <= 950}
|
||||||
|
<div class="row">
|
||||||
|
{#if withSaveButton}
|
||||||
|
<form on:submit|preventDefault={forwardSave} class="button-form">
|
||||||
|
<Button icon="fas fa-save">Save</Button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
{#if withDeleteButton}
|
||||||
|
<form on:submit|preventDefault={forwardDelete} class="button-form">
|
||||||
|
<Button icon="fas fa-trash" danger={true}>Delete</Button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if withCreateButton}
|
||||||
|
<div class="row" style="justify-content: center; margin-top: 10px">
|
||||||
|
<Button type="submit" icon="fas fa-plus">Add Input</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<svelte:window bind:innerWidth={windowWidth} />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
import Input from "../form/Input.svelte";
|
||||||
|
import Dropdown from "../form/Dropdown.svelte";
|
||||||
|
import Button from "../Button.svelte";
|
||||||
|
import Textarea from "../form/Textarea.svelte";
|
||||||
|
|
||||||
|
export let withCreateButton = false;
|
||||||
|
export let withSaveButton = false;
|
||||||
|
export let withDeleteButton = false;
|
||||||
|
|
||||||
|
export let data = {};
|
||||||
|
|
||||||
|
$: windowWidth = 0;
|
||||||
|
|
||||||
|
function forwardCreate() {
|
||||||
|
dispatch('create', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function forwardSave() {
|
||||||
|
dispatch('save', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function forwardDelete() {
|
||||||
|
dispatch('delete', {});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.input-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, .25);
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons-row > form:first-of-type {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 950px) {
|
||||||
|
.row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.settings-row {
|
||||||
|
flex-direction: column-reverse !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -21,6 +21,13 @@
|
|||||||
<option value="3">Green</option>
|
<option value="3">Green</option>
|
||||||
<option value="4">Red</option>
|
<option value="4">Red</option>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
|
<Dropdown col4=true label="Form" bind:value={data.form_id}>
|
||||||
|
<option value=0>Disabled</option>
|
||||||
|
{#each forms as form}
|
||||||
|
<option value={form.form_id}>{form.title}</option>
|
||||||
|
{/each}
|
||||||
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="justify-content: center">
|
<div class="row" style="justify-content: center">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
@ -94,12 +101,14 @@
|
|||||||
default_team: true,
|
default_team: true,
|
||||||
teams: [],
|
teams: [],
|
||||||
button_style: "1",
|
button_style: "1",
|
||||||
|
form_id: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export let channels = [];
|
export let channels = [];
|
||||||
export let roles = [];
|
export let roles = [];
|
||||||
export let teams = [];
|
export let teams = [];
|
||||||
|
export let forms = [];
|
||||||
|
|
||||||
let advancedSettings = false;
|
let advancedSettings = false;
|
||||||
let overflowShow = false;
|
let overflowShow = false;
|
||||||
|
@ -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} bind:data={panel} seedDefault={false} />
|
<PanelCreationForm {guildId} {channels} {roles} {teams} {forms} bind:data={panel} seedDefault={false} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div slot="footer">
|
<div slot="footer">
|
||||||
@ -30,6 +30,7 @@
|
|||||||
export let guildId;
|
export let guildId;
|
||||||
export let panel = {};
|
export let panel = {};
|
||||||
export let channels = [];
|
export let channels = [];
|
||||||
|
export let forms = [];
|
||||||
export let roles = [];
|
export let roles = [];
|
||||||
export let teams = [];
|
export let teams = [];
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.col-4, .col-3, .col-2) {
|
:global(.col-4, .col-3, .col-2, .col-3-4) {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<NavElement icon="fas fa-cogs" link="/manage/{guildId}/settings" on:click={closeDropdown}>Settings</NavElement>
|
<NavElement icon="fas fa-cogs" link="/manage/{guildId}/settings" on:click={closeDropdown}>Settings</NavElement>
|
||||||
<NavElement icon="fas fa-copy" link="/manage/{guildId}/transcripts" on:click={closeDropdown}>Transcripts</NavElement>
|
<NavElement icon="fas fa-copy" link="/manage/{guildId}/transcripts" on:click={closeDropdown}>Transcripts</NavElement>
|
||||||
<NavElement icon="fas fa-mouse-pointer" link="/manage/{guildId}/panels" on:click={closeDropdown}>Reaction Panels</NavElement>
|
<NavElement icon="fas fa-mouse-pointer" link="/manage/{guildId}/panels" on:click={closeDropdown}>Reaction Panels</NavElement>
|
||||||
|
<NavElement icon="fas fa-poll-h" link="/manage/{guildId}/forms" on:click={closeDropdown}>Forms</NavElement>
|
||||||
<NavElement icon="fas fa-users" link="/manage/{guildId}/teams" on:click={closeDropdown}>Teams</NavElement>
|
<NavElement icon="fas fa-users" link="/manage/{guildId}/teams" on:click={closeDropdown}>Teams</NavElement>
|
||||||
<NavElement icon="fas fa-ticket-alt" link="/manage/{guildId}/tickets" on:click={closeDropdown}>Tickets</NavElement>
|
<NavElement icon="fas fa-ticket-alt" link="/manage/{guildId}/tickets" on:click={closeDropdown}>Tickets</NavElement>
|
||||||
<NavElement icon="fas fa-ban" link="/manage/{guildId}/blacklist" on:click={closeDropdown}>Blacklist</NavElement>
|
<NavElement icon="fas fa-ban" link="/manage/{guildId}/blacklist" on:click={closeDropdown}>Blacklist</NavElement>
|
||||||
|
@ -20,6 +20,7 @@ import Teams from './views/Teams.svelte'
|
|||||||
import Tickets from './views/Tickets.svelte'
|
import Tickets from './views/Tickets.svelte'
|
||||||
import TicketView from './views/TicketView.svelte'
|
import TicketView from './views/TicketView.svelte'
|
||||||
import Appearance from './views/Appearance.svelte';
|
import Appearance from './views/Appearance.svelte';
|
||||||
|
import Forms from './views/Forms.svelte';
|
||||||
|
|
||||||
export const routes = [
|
export const routes = [
|
||||||
{name: '/', component: Index, layout: IndexLayout},
|
{name: '/', component: Index, layout: IndexLayout},
|
||||||
@ -65,6 +66,7 @@ export const routes = [
|
|||||||
{name: 'blacklist', component: Blacklist, layout: ManageLayout},
|
{name: 'blacklist', component: Blacklist, layout: ManageLayout},
|
||||||
{name: 'tags', component: Tags, layout: ManageLayout},
|
{name: 'tags', component: Tags, layout: ManageLayout},
|
||||||
{name: 'teams', component: Teams, layout: ManageLayout},
|
{name: 'teams', component: Teams, layout: ManageLayout},
|
||||||
|
{name: 'forms', component: Forms, layout: ManageLayout},
|
||||||
{
|
{
|
||||||
name: 'tickets',
|
name: 'tickets',
|
||||||
nestedRoutes: [
|
nestedRoutes: [
|
||||||
|
279
frontend/src/views/Forms.svelte
Normal file
279
frontend/src/views/Forms.svelte
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
<div class="parent">
|
||||||
|
<div class="content">
|
||||||
|
<Card footer={false}>
|
||||||
|
<span slot="title">Forms</span>
|
||||||
|
<div slot="body" class="body-wrapper">
|
||||||
|
<div class="section">
|
||||||
|
<h2 class="section-title">Create New Form</h2>
|
||||||
|
|
||||||
|
<form on:submit|preventDefault={createForm}>
|
||||||
|
<div class="row" id="creation-row">
|
||||||
|
<Input placeholder="Form Title" col3={true} bind:value={newTitle}/>
|
||||||
|
<div id="create-button-wrapper">
|
||||||
|
<Button icon="fas fa-paper-plane" fullWidth={windowWidth <= 950}>Create</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="section">
|
||||||
|
<h2 class="section-title">Manage Forms</h2>
|
||||||
|
|
||||||
|
<div class="col-1" style="flex-direction: row">
|
||||||
|
<div class="col-4" style="margin-right: 12px">
|
||||||
|
<div class="multiselect-super">
|
||||||
|
<Dropdown col1={true} bind:value={activeFormId}>
|
||||||
|
<option value={null}>Select a form...</option>
|
||||||
|
{#each forms as form}
|
||||||
|
<option value="{form.form_id}">{form.title}</option>
|
||||||
|
{/each}
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if activeFormId !== null}
|
||||||
|
<div class="col-4">
|
||||||
|
<Button danger={true} type="button"
|
||||||
|
on:click={() => deleteForm(activeFormId)}>Delete {getActiveFormTitle()}</Button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="manage">
|
||||||
|
{#if activeFormId !== null && inputs[activeFormId.toString()]}
|
||||||
|
{#each inputs[activeFormId.toString()] as input}
|
||||||
|
<FormInputRow data={input} formId={activeFormId} withSaveButton={true} withDeleteButton={true}
|
||||||
|
on:save={(e) => editInput(activeFormId, input.id, e.detail)}
|
||||||
|
on:delete={() => deleteInput(activeFormId, input.id)}/>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if activeFormId !== null}
|
||||||
|
<FormInputRow bind:data={inputCreationData} withCreateButton={true}
|
||||||
|
on:create={(e) => createInput(e.detail)}/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<svelte:window bind:innerWidth={windowWidth} />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Card from "../components/Card.svelte";
|
||||||
|
import {notifyError, notifySuccess, withLoadingScreen} from '../js/util'
|
||||||
|
import Button from "../components/Button.svelte";
|
||||||
|
import axios from "axios";
|
||||||
|
import {API_URL} from "../js/constants";
|
||||||
|
import {setDefaultHeaders} from '../includes/Auth.svelte'
|
||||||
|
import Input from "../components/form/Input.svelte";
|
||||||
|
import Dropdown from "../components/form/Dropdown.svelte";
|
||||||
|
import FormInputRow from "../components/manage/FormInputRow.svelte";
|
||||||
|
|
||||||
|
export let currentRoute;
|
||||||
|
let guildId = currentRoute.namedParams.id;
|
||||||
|
|
||||||
|
let defaultTeam = {id: 'default', name: 'Default'};
|
||||||
|
|
||||||
|
let newTitle;
|
||||||
|
let forms = [];
|
||||||
|
let inputs = {};
|
||||||
|
let activeFormId = null;
|
||||||
|
let inputCreationData = {};
|
||||||
|
|
||||||
|
$: windowWidth = 0;
|
||||||
|
|
||||||
|
async function createForm() {
|
||||||
|
let data = {
|
||||||
|
title: newTitle,
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await axios.post(`${API_URL}/api/${guildId}/forms`, data);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifySuccess(`Form ${newTitle} has been created`);
|
||||||
|
newTitle = '';
|
||||||
|
inputs[res.data.form_id] = {};
|
||||||
|
forms = [...forms, res.data];
|
||||||
|
activeFormId = res.data.form_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteForm(id) {
|
||||||
|
const res = await axios.delete(`${API_URL}/api/${guildId}/forms/${id}`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifySuccess(`Form deleted successfully`);
|
||||||
|
|
||||||
|
forms = forms.filter(form => form.form_id !== id);
|
||||||
|
delete inputs[id.toString()];
|
||||||
|
if (forms.length > 0) {
|
||||||
|
activeFormId = forms[0].form_id;
|
||||||
|
} else {
|
||||||
|
activeFormId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createInput(data) {
|
||||||
|
let mapped = {...data, style: parseInt(data.style)};
|
||||||
|
|
||||||
|
const res = await axios.post(`${API_URL}/api/${guildId}/forms/${activeFormId}`, mapped);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs[res.data.form_id] = [...inputs[res.data.form_id], res.data];
|
||||||
|
inputCreationData = {};
|
||||||
|
notifySuccess('Form input created successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function editInput(formId, inputId, data) {
|
||||||
|
let mapped = {...data, style: parseInt(data.style)};
|
||||||
|
|
||||||
|
const res = await axios.patch(`${API_URL}/api/${guildId}/forms/${formId}/${inputId}`, mapped);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs[res.data.form_id] = inputs[res.data.form_id].filter(input => input.id !== inputId);
|
||||||
|
inputs[res.data.form_id] = [...inputs[res.data.form_id], res.data];
|
||||||
|
notifySuccess('Form input updated successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteInput(formId, inputId) {
|
||||||
|
const res = await axios.delete(`${API_URL}/api/${guildId}/forms/${formId}/${inputId}`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs[formId] = inputs[formId].filter(input => input.id !== inputId);
|
||||||
|
notifySuccess('Form input deleted successfully');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadForms() {
|
||||||
|
const res = await axios.get(`${API_URL}/api/${guildId}/forms`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
forms = res.data.forms || [];
|
||||||
|
for (const form of forms) {
|
||||||
|
inputs[form.form_id] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(res.data.inputs)) {
|
||||||
|
inputs[key] = value.map(input => ({...input, style: input.style.toString()}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forms.length > 0) {
|
||||||
|
activeFormId = forms[0].form_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActiveFormTitle() {
|
||||||
|
console.log(forms);
|
||||||
|
return activeFormId !== null ? forms.find(f => f.form_id === activeFormId).title : 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
withLoadingScreen(async () => {
|
||||||
|
setDefaultHeaders();
|
||||||
|
await loadForms();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.parent {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 96%;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section:not(:first-child) {
|
||||||
|
margin-top: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: bolder !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 28px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manage {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#creation-row {
|
||||||
|
justify-content: flex-start !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#create-button-wrapper {
|
||||||
|
margin-left: 15px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 950px) {
|
||||||
|
.manage {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#create-button-wrapper {
|
||||||
|
margin-left: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,5 +1,5 @@
|
|||||||
{#if editModal}
|
{#if editModal}
|
||||||
<PanelEditModal {guildId} {channels} {roles} {teams} bind:panel={editData}
|
<PanelEditModal {guildId} {channels} {roles} {teams} {forms} bind:panel={editData}
|
||||||
on:close={() => editModal = false} on:confirm={submitEdit}/>
|
on:close={() => editModal = false} on:confirm={submitEdit}/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
<div slot="body" class="body-wrapper">
|
<div slot="body" class="body-wrapper">
|
||||||
{#if !$loadingScreen}
|
{#if !$loadingScreen}
|
||||||
<PanelCreationForm {guildId} {channels} {roles} {teams} bind:data={panelCreateData}/>
|
<PanelCreationForm {guildId} {channels} {roles} {teams} {forms} bind:data={panelCreateData}/>
|
||||||
<div style="display: flex; justify-content: center">
|
<div style="display: flex; justify-content: center">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<Button icon="fas fa-paper-plane" fullWidth={true} on:click={createPanel}>Submit</Button>
|
<Button icon="fas fa-paper-plane" fullWidth={true} on:click={createPanel}>Submit</Button>
|
||||||
@ -143,6 +143,7 @@
|
|||||||
let channels = [];
|
let channels = [];
|
||||||
let roles = [];
|
let roles = [];
|
||||||
let teams = [];
|
let teams = [];
|
||||||
|
let forms = [];
|
||||||
let panels = [];
|
let panels = [];
|
||||||
let multiPanels = [];
|
let multiPanels = [];
|
||||||
let isPremium = false;
|
let isPremium = false;
|
||||||
@ -320,10 +321,21 @@
|
|||||||
roles = res.data.roles;
|
roles = res.data.roles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadForms() {
|
||||||
|
const res = await axios.get(`${API_URL}/api/${guildId}/forms`);
|
||||||
|
if (res.status !== 200) {
|
||||||
|
notifyError(res.data.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
forms = res.data.forms || [];
|
||||||
|
}
|
||||||
|
|
||||||
withLoadingScreen(async () => {
|
withLoadingScreen(async () => {
|
||||||
await loadPremium();
|
await loadPremium();
|
||||||
await loadChannels();
|
await loadChannels();
|
||||||
await loadTeams();
|
await loadTeams();
|
||||||
|
await loadForms();
|
||||||
await loadRoles();
|
await loadRoles();
|
||||||
await loadPanels();
|
await loadPanels();
|
||||||
await loadMultiPanels();
|
await loadMultiPanels();
|
||||||
|
4
go.mod
4
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-20210220155137-a562b2f1bbbb
|
github.com/TicketsBot/archiverclient v0.0.0-20210220155137-a562b2f1bbbb
|
||||||
github.com/TicketsBot/common v0.0.0-20210910205523-7ce93fba6fa5
|
github.com/TicketsBot/common v0.0.0-20210910205523-7ce93fba6fa5
|
||||||
github.com/TicketsBot/database v0.0.0-20211109153802-24100e383d78
|
github.com/TicketsBot/database v0.0.0-20211202174040-bd189305f898
|
||||||
github.com/TicketsBot/worker v0.0.0-20211108224403-97ac8e44b789
|
github.com/TicketsBot/worker v0.0.0-20211108224403-97ac8e44b789
|
||||||
github.com/apex/log v1.1.2
|
github.com/apex/log v1.1.2
|
||||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
|
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
|
||||||
@ -23,7 +23,7 @@ require (
|
|||||||
github.com/jackc/pgx/v4 v4.7.1
|
github.com/jackc/pgx/v4 v4.7.1
|
||||||
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c
|
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rxdn/gdl v0.0.0-20211030160619-a8772c268ca4
|
github.com/rxdn/gdl v0.0.0-20220209151849-19fd8c86af50
|
||||||
github.com/sirupsen/logrus v1.5.0
|
github.com/sirupsen/logrus v1.5.0
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
|
||||||
)
|
)
|
||||||
|
19
go.sum
19
go.sum
@ -14,8 +14,8 @@ github.com/TicketsBot/common v0.0.0-20210910205523-7ce93fba6fa5/go.mod h1:SVwX6g
|
|||||||
github.com/TicketsBot/database v0.0.0-20200516170158-fd8a949aec2c/go.mod h1:eky4tBL+IZ0svPgTT0N/9i6j7ygHDQH3784DW+HgfcA=
|
github.com/TicketsBot/database v0.0.0-20200516170158-fd8a949aec2c/go.mod h1:eky4tBL+IZ0svPgTT0N/9i6j7ygHDQH3784DW+HgfcA=
|
||||||
github.com/TicketsBot/database v0.0.0-20210902172951-4e1f8ced84b7/go.mod h1:A4T2uQFIWC/ttCYpfgv7AkPjR09mMRgzG13lgoV/+aI=
|
github.com/TicketsBot/database v0.0.0-20210902172951-4e1f8ced84b7/go.mod h1:A4T2uQFIWC/ttCYpfgv7AkPjR09mMRgzG13lgoV/+aI=
|
||||||
github.com/TicketsBot/database v0.0.0-20211108142700-c406ab0fc1bb/go.mod h1:72oWvH/Gq1iKeXCZhVRZn1JFbNVC5iAgERZWTrEarEo=
|
github.com/TicketsBot/database v0.0.0-20211108142700-c406ab0fc1bb/go.mod h1:72oWvH/Gq1iKeXCZhVRZn1JFbNVC5iAgERZWTrEarEo=
|
||||||
github.com/TicketsBot/database v0.0.0-20211109153802-24100e383d78 h1:zzjOyxCdXN1fGDL2Na6Q82EDU96Cfd1vnlafeY1utUQ=
|
github.com/TicketsBot/database v0.0.0-20211202174040-bd189305f898 h1:bbDirB6NmLjJ+9Zbw+Zy3073I7vRGxlKOb+jTRXm3vE=
|
||||||
github.com/TicketsBot/database v0.0.0-20211109153802-24100e383d78/go.mod h1:72oWvH/Gq1iKeXCZhVRZn1JFbNVC5iAgERZWTrEarEo=
|
github.com/TicketsBot/database v0.0.0-20211202174040-bd189305f898/go.mod h1:72oWvH/Gq1iKeXCZhVRZn1JFbNVC5iAgERZWTrEarEo=
|
||||||
github.com/TicketsBot/logarchiver v0.0.0-20200423221245-a3f92edf8c14/go.mod h1:whts8TRxrAF4WuDuEAMllkWA/inKem0NhDEFeyuoOvE=
|
github.com/TicketsBot/logarchiver v0.0.0-20200423221245-a3f92edf8c14/go.mod h1:whts8TRxrAF4WuDuEAMllkWA/inKem0NhDEFeyuoOvE=
|
||||||
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=
|
||||||
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261/go.mod h1:2zPxDAN2TAPpxUPjxszjs3QFKreKrQh5al/R3cMXmYk=
|
github.com/TicketsBot/ttlcache v1.6.1-0.20200405150101-acc18e37b261/go.mod h1:2zPxDAN2TAPpxUPjxszjs3QFKreKrQh5al/R3cMXmYk=
|
||||||
@ -106,7 +106,6 @@ github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GO
|
|||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
|
github.com/go-playground/validator/v10 v10.6.1 h1:W6TRDXt4WcWp4c4nf/G+6BkGdhiIo0k417gfr+V6u4I=
|
||||||
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
github.com/go-playground/validator/v10 v10.6.1/go.mod h1:xm76BBt941f7yWdGnI2DVPFFg1UK3YY04qifoXU3lOk=
|
||||||
github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
|
||||||
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
|
||||||
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||||
@ -115,7 +114,6 @@ github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCx
|
|||||||
github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc=
|
github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc=
|
||||||
github.com/go-redis/redis_rate/v9 v9.1.1 h1:7SIrbnhQ7zsTNEgIvprFhJf7/+l3wSpZc2iRVwUmaq8=
|
github.com/go-redis/redis_rate/v9 v9.1.1 h1:7SIrbnhQ7zsTNEgIvprFhJf7/+l3wSpZc2iRVwUmaq8=
|
||||||
github.com/go-redis/redis_rate/v9 v9.1.1/go.mod h1:jjU9YxOSZ3cz0yj1QJVAJiy5ueKmL9o4AySJHcKyTSE=
|
github.com/go-redis/redis_rate/v9 v9.1.1/go.mod h1:jjU9YxOSZ3cz0yj1QJVAJiy5ueKmL9o4AySJHcKyTSE=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||||
@ -237,7 +235,6 @@ github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
|
|||||||
github.com/jackc/puddle v1.1.1 h1:PJAw7H/9hoWC4Kf3J8iNmL1SwA6E8vfsLqBiL+F6CtI=
|
github.com/jackc/puddle v1.1.1 h1:PJAw7H/9hoWC4Kf3J8iNmL1SwA6E8vfsLqBiL+F6CtI=
|
||||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
|
||||||
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
@ -294,7 +291,6 @@ github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1y
|
|||||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||||
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
@ -323,14 +319,12 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
|||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
|
||||||
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
|
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
|
||||||
@ -353,10 +347,8 @@ github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
|||||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/rxdn/gdl v0.0.0-20200522202912-4ae241eb98c1/go.mod h1:2gPBB++1s9Zh11AGM/y84KpmqTyLCnjGwEnt6xRRKL4=
|
github.com/rxdn/gdl v0.0.0-20220209151849-19fd8c86af50 h1:xkWpJfblzNEzt/wQ0OB/vqJdLBnSCYIcuVE6z396MWY=
|
||||||
github.com/rxdn/gdl v0.0.0-20210527173953-25dde613ff0a/go.mod h1:jvcb1N6AdaGx3/e8MoLedO6qSo/+UdA5GGHOA8cnAeU=
|
github.com/rxdn/gdl v0.0.0-20220209151849-19fd8c86af50/go.mod h1:rENs8TxMsoYSJRssegNS/+fy18NCI9EUdCJX8R83PlY=
|
||||||
github.com/rxdn/gdl v0.0.0-20211030160619-a8772c268ca4 h1:vHSTqcCCZZwlj6trBUj3tqys5hnKbBf9J6mtuG7DvgM=
|
|
||||||
github.com/rxdn/gdl v0.0.0-20211030160619-a8772c268ca4/go.mod h1:rENs8TxMsoYSJRssegNS/+fy18NCI9EUdCJX8R83PlY=
|
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||||
@ -445,7 +437,6 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI=
|
||||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
@ -461,7 +452,6 @@ golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
@ -532,7 +522,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
Loading…
x
Reference in New Issue
Block a user