panel update
This commit is contained in:
parent
19ac84ad16
commit
8ae95009b7
192
app/http/endpoints/manage/panelcreate.go
Normal file
192
app/http/endpoints/manage/panelcreate.go
Normal file
@ -0,0 +1,192 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/cache"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func PanelCreateHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
userIdStr := store.Get("userid").(string)
|
||||
userId, err := utils.GetUserId(store)
|
||||
if err != nil {
|
||||
ctx.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the guild exists
|
||||
guildIdStr := ctx.Param("id")
|
||||
guildId, err := strconv.ParseInt(guildIdStr, 10, 64)
|
||||
if err != nil {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get object for selected guild
|
||||
var guild objects.Guild
|
||||
for _, g := range table.GetGuilds(userIdStr) {
|
||||
if g.Id == guildIdStr {
|
||||
guild = g
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the user has permissions to be here
|
||||
if !utils.Contains(config.Conf.Admins, userIdStr) && !guild.Owner && !table.IsAdmin(guildId, userId) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get CSRF token
|
||||
csrfCorrect := ctx.PostForm("csrf") == store.Get("csrf").(string)
|
||||
if !csrfCorrect {
|
||||
ctx.Redirect(302, "/")
|
||||
return
|
||||
}
|
||||
|
||||
// Get if the guild is premium
|
||||
premiumChan := make(chan bool)
|
||||
go utils.IsPremiumGuild(store, guildIdStr, premiumChan)
|
||||
premium := <-premiumChan
|
||||
|
||||
// Check the user hasn't met their panel quota
|
||||
if !premium {
|
||||
panels := make(chan []table.Panel)
|
||||
go table.GetPanelsByGuild(guildId, panels)
|
||||
if len(<-panels) > 1 {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?metQuota=true", guildId))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Validate title
|
||||
title := ctx.PostForm("title")
|
||||
if len(title) == 0 || len(title) > 255 {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validTitle=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
// Validate content
|
||||
content := ctx.PostForm("content")
|
||||
if len(content) == 0 || len(content) > 1024 {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validContent=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
// Validate colour
|
||||
panelColourHex := ctx.PostForm("colour")
|
||||
panelColour, err := strconv.ParseUint(panelColourHex, 16, 32)
|
||||
if err != nil {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validColour=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
// Validate channel
|
||||
channelIdStr := ctx.PostForm("channel")
|
||||
channelId, err := strconv.ParseInt(channelIdStr, 10, 64); if err != nil {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validChannel=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
validChannel := make(chan bool)
|
||||
go validateChannel(guildId, channelId, validChannel)
|
||||
if !<-validChannel {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validChannel=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
// Validate category
|
||||
categoryStr := ctx.PostForm("category")
|
||||
categoryId, err := strconv.ParseInt(categoryStr, 10, 64); if err != nil {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validCategory=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
validCategory := make(chan bool)
|
||||
go validateCategory(guildId, categoryId, validChannel)
|
||||
if !<-validCategory {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validCategory=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
// Validate reaction emote
|
||||
reaction := strings.ToLower(ctx.PostForm("reaction"))
|
||||
if len(title) == 0 || len(title) > 32 {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validReaction=false", guildId))
|
||||
return
|
||||
}
|
||||
reaction = strings.Replace(reaction, ":", "", -1)
|
||||
|
||||
emoji := utils.GetEmojiByName(reaction)
|
||||
if emoji == "" {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?validReaction=false", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
settings := table.Panel{
|
||||
ChannelId: channelId,
|
||||
GuildId: guildId,
|
||||
Title: title,
|
||||
Content: content,
|
||||
Colour: int(panelColour),
|
||||
TargetCategory: categoryId,
|
||||
ReactionEmote: emoji,
|
||||
}
|
||||
|
||||
go cache.Client.PublishPanelCreate(settings)
|
||||
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels?created=true", guildId))
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
}
|
||||
|
||||
func validateChannel(guildId, channelId int64, res chan bool) {
|
||||
// Get channels from DB
|
||||
channelsChan := make(chan []table.Channel)
|
||||
go table.GetCachedChannelsByGuild(guildId, channelsChan)
|
||||
channels := <-channelsChan
|
||||
|
||||
// Compare channel IDs
|
||||
validChannel := false
|
||||
for _, guildChannel := range channels {
|
||||
if guildChannel.ChannelId == channelId {
|
||||
validChannel = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
res <- validChannel
|
||||
}
|
||||
|
||||
func validateCategory(guildId, categoryId int64, res chan bool) {
|
||||
// Get channels from DB
|
||||
categoriesChan := make(chan []table.Channel)
|
||||
go table.GetCategories(guildId, categoriesChan)
|
||||
categories := <-categoriesChan
|
||||
|
||||
// Compare channel IDs
|
||||
validCategory := false
|
||||
for _, category := range categories {
|
||||
if category.ChannelId == categoryId {
|
||||
validCategory = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
res <- validCategory
|
||||
}
|
71
app/http/endpoints/manage/paneldelete.go
Normal file
71
app/http/endpoints/manage/paneldelete.go
Normal file
@ -0,0 +1,71 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func PanelDeleteHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
userIdStr := store.Get("userid").(string)
|
||||
userId, err := utils.GetUserId(store)
|
||||
if err != nil {
|
||||
ctx.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the guild exists
|
||||
guildIdStr := ctx.Param("id")
|
||||
guildId, err := strconv.ParseInt(guildIdStr, 10, 64)
|
||||
if err != nil {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
|
||||
return
|
||||
}
|
||||
|
||||
messageIdStr := ctx.Param("msg")
|
||||
messageId, err := strconv.ParseInt(messageIdStr, 10, 64); if err != nil {
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels", guildId))
|
||||
return
|
||||
}
|
||||
|
||||
// Get object for selected guild
|
||||
var guild objects.Guild
|
||||
for _, g := range table.GetGuilds(userIdStr) {
|
||||
if g.Id == guildIdStr {
|
||||
guild = g
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the user has permissions to be here
|
||||
if !utils.Contains(config.Conf.Admins, userIdStr) && !guild.Owner && !table.IsAdmin(guildId, userId) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get CSRF token
|
||||
csrfCorrect := ctx.Query("csrf") == store.Get("csrf").(string)
|
||||
if !csrfCorrect {
|
||||
ctx.Redirect(302, "/")
|
||||
return
|
||||
}
|
||||
|
||||
go table.DeletePanel(messageId)
|
||||
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/panels", guildId))
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
}
|
144
app/http/endpoints/manage/panels.go
Normal file
144
app/http/endpoints/manage/panels.go
Normal file
@ -0,0 +1,144 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type wrappedPanel struct {
|
||||
MessageId int64
|
||||
ChannelName string
|
||||
Title string
|
||||
Content string
|
||||
CategoryName string
|
||||
}
|
||||
|
||||
func PanelHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
userIdStr := store.Get("userid").(string)
|
||||
userId, err := utils.GetUserId(store)
|
||||
if err != nil {
|
||||
ctx.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the guild exists
|
||||
guildIdStr := ctx.Param("id")
|
||||
guildId, err := strconv.ParseInt(guildIdStr, 10, 64)
|
||||
if err != nil {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get object for selected guild
|
||||
var guild objects.Guild
|
||||
for _, g := range table.GetGuilds(userIdStr) {
|
||||
if g.Id == guildIdStr {
|
||||
guild = g
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the user has permissions to be here
|
||||
if !utils.Contains(config.Conf.Admins, userIdStr) && !guild.Owner && !table.IsAdmin(guildId, userId) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get active panels
|
||||
panelChan := make(chan []table.Panel)
|
||||
go table.GetPanelsByGuild(guildId, panelChan)
|
||||
panels := <-panelChan
|
||||
|
||||
// Get channels
|
||||
channelsChan := make(chan []table.Channel)
|
||||
go table.GetCachedChannelsByGuild(guildId, channelsChan)
|
||||
channels := <-channelsChan
|
||||
|
||||
// Get default panel settings
|
||||
settings := table.GetPanelSettings(guildId)
|
||||
|
||||
// Convert to wrapped panels
|
||||
wrappedPanels := make([]wrappedPanel, 0)
|
||||
for _, panel := range panels {
|
||||
wrapper := wrappedPanel{
|
||||
MessageId: panel.MessageId,
|
||||
Title: panel.Title,
|
||||
Content: panel.Content,
|
||||
CategoryName: "",
|
||||
}
|
||||
|
||||
if panel.Title == "" {
|
||||
wrapper.Title = settings.Title
|
||||
}
|
||||
if panel.Content == "" {
|
||||
wrapper.Content = settings.Content
|
||||
}
|
||||
|
||||
// Get channel name & category name
|
||||
for _, guildChannel := range channels {
|
||||
if guildChannel.ChannelId == panel.ChannelId {
|
||||
wrapper.ChannelName = guildChannel.Name
|
||||
} else if guildChannel.ChannelId == panel.TargetCategory {
|
||||
wrapper.CategoryName = guildChannel.Name
|
||||
}
|
||||
}
|
||||
|
||||
wrappedPanels = append(wrappedPanels, wrapper)
|
||||
}
|
||||
|
||||
// Format channels to be text channels only
|
||||
channelMap := make(map[int64]string)
|
||||
for _, channel := range channels {
|
||||
if channel.Type == 0 {
|
||||
channelMap[channel.ChannelId] = channel.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Get categories & format
|
||||
categories := make(map[int64]string)
|
||||
for _, channel := range channels {
|
||||
if channel.Type == 4 {
|
||||
categories[channel.ChannelId] = channel.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Get is premium
|
||||
isPremiumChan := make(chan bool)
|
||||
go utils.IsPremiumGuild(store, guildIdStr, isPremiumChan)
|
||||
isPremium := <-isPremiumChan
|
||||
|
||||
ctx.HTML(200, "manage/panels", gin.H{
|
||||
"name": store.Get("name").(string),
|
||||
"guildId": guildIdStr,
|
||||
"csrf": store.Get("csrf").(string),
|
||||
"avatar": store.Get("avatar").(string),
|
||||
"baseUrl": config.Conf.Server.BaseUrl,
|
||||
"panelcount": len(panels),
|
||||
"premium": isPremium,
|
||||
"panels": wrappedPanels,
|
||||
"channels": channelMap,
|
||||
"categories": categories,
|
||||
|
||||
"validTitle": ctx.Query("validTitle") != "true",
|
||||
"validContent": ctx.Query("validContent") != "false",
|
||||
"validColour": ctx.Query("validColour") != "false",
|
||||
"validChannel": ctx.Query("validChannel") != "false",
|
||||
"validCategory": ctx.Query("validCategory") != "false",
|
||||
"validReaction": ctx.Query("validReaction") != "false",
|
||||
"created": ctx.Query("created") == "true",
|
||||
"metQuota": ctx.Query("metQuota") == "true",
|
||||
})
|
||||
}
|
||||
}
|
@ -69,8 +69,8 @@ func SettingsHandler(ctx *gin.Context) {
|
||||
// Archive channel
|
||||
// Create a list of IDs
|
||||
var channelIds []string
|
||||
for _, c := range guild.Channels {
|
||||
channelIds = append(channelIds, c.Id)
|
||||
for _, c := range channels {
|
||||
channelIds = append(channelIds, strconv.Itoa(int(c.ChannelId)))
|
||||
}
|
||||
|
||||
panelSettings := table.GetPanelSettings(guildId)
|
||||
|
@ -67,7 +67,7 @@ func UpdateSettingsHandler(ctx *gin.Context) {
|
||||
// Get welcome message
|
||||
welcomeMessageValid := false
|
||||
welcomeMessage := ctx.PostForm("welcomeMessage")
|
||||
if welcomeMessage != "" && len(welcomeMessage) > 1000 {
|
||||
if welcomeMessage != "" && len(welcomeMessage) < 1000 {
|
||||
table.UpdateWelcomeMessage(guildId, welcomeMessage)
|
||||
welcomeMessageValid = true
|
||||
}
|
||||
@ -139,7 +139,7 @@ func UpdateSettingsHandler(ctx *gin.Context) {
|
||||
|
||||
// Get panel colour
|
||||
panelColourHex := ctx.PostForm("panelcolour")
|
||||
if panelColourHex == "" {
|
||||
if panelColourHex != "" {
|
||||
panelColour, err := strconv.ParseUint(panelColourHex, 16, 32)
|
||||
if err == nil {
|
||||
table.UpdatePanelColour(guildId, int(panelColour))
|
||||
@ -150,7 +150,7 @@ func UpdateSettingsHandler(ctx *gin.Context) {
|
||||
usersCanClose := ctx.PostForm("userscanclose") == "on"
|
||||
table.SetUserCanClose(guildId, usersCanClose)
|
||||
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/settings?validPrefix=%t&validWelcomeMessage=%t&ticketLimitValid=%t", guildId, prefixValid, welcomeMessageValid, ticketLimitValid))
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%d/settings?validPrefix=%t&validWelcomeMessage=%t&validTicketLimit=%t", guildId, prefixValid, welcomeMessageValid, ticketLimitValid))
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
|
@ -49,6 +49,10 @@ func StartServer() {
|
||||
router.GET("/manage/:id/blacklist", manage.BlacklistHandler)
|
||||
router.GET("/manage/:id/blacklist/remove/:user", manage.BlacklistRemoveHandler)
|
||||
|
||||
router.GET("/manage/:id/panels", manage.PanelHandler)
|
||||
router.POST("/manage/:id/panels/create", manage.PanelCreateHandler)
|
||||
router.GET("/manage/:id/panels/delete/:msg", manage.PanelDeleteHandler)
|
||||
|
||||
router.GET("/manage/:id/tickets", manage.TicketListHandler)
|
||||
router.GET("/manage/:id/tickets/view/:uuid", manage.TicketViewHandler)
|
||||
router.POST("/manage/:id/tickets/view/:uuid", manage.SendMessage)
|
||||
@ -69,6 +73,7 @@ func createRenderer() multitemplate.Renderer {
|
||||
r = addManageTemplate(r, "settings")
|
||||
r = addManageTemplate(r, "ticketlist")
|
||||
r = addManageTemplate(r, "ticketview")
|
||||
r = addManageTemplate(r, "panels")
|
||||
|
||||
return r
|
||||
}
|
||||
|
17
cache/panelcreate.go
vendored
Normal file
17
cache/panelcreate.go
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
"github.com/apex/log"
|
||||
)
|
||||
|
||||
func (c *RedisClient) PublishPanelCreate(settings table.Panel) {
|
||||
encoded, err := json.Marshal(settings); if err != nil {
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Publish("tickets:panel:create", string(encoded))
|
||||
}
|
||||
|
@ -1,22 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
crypto_rand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/app/http"
|
||||
"github.com/TicketsBot/GoPanel/app/http/endpoints/manage"
|
||||
"github.com/TicketsBot/GoPanel/cache"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/TicketsGo/sentry"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano() % 3497)
|
||||
var b [8]byte
|
||||
_, err := crypto_rand.Read(b[:])
|
||||
if err == nil {
|
||||
rand.Seed(int64(binary.LittleEndian.Uint64(b[:])))
|
||||
} else {
|
||||
sentry.Error(err)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
config.LoadConfig()
|
||||
database.ConnectToDatabase()
|
||||
|
||||
utils.LoadEmoji()
|
||||
|
||||
cache.Client = cache.NewRedisClient()
|
||||
go Listen(cache.Client)
|
||||
|
||||
|
51
database/table/panels.go
Normal file
51
database/table/panels.go
Normal file
@ -0,0 +1,51 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type Panel struct {
|
||||
MessageId int64 `gorm:"column:MESSAGEID"`
|
||||
ChannelId int64 `gorm:"column:CHANNELID"`
|
||||
GuildId int64 `gorm:"column:GUILDID"` // Might be useful in the future so we store it
|
||||
|
||||
Title string `gorm:"column:TITLE;type:VARCHAR(255)"`
|
||||
Content string `gorm:"column:CONTENT;type:TEXT"`
|
||||
Colour int `gorm:"column:COLOUR`
|
||||
TargetCategory int64 `gorm:"column:TARGETCATEGORY"`
|
||||
ReactionEmote string `gorm:"column:REACTIONEMOTE;type:VARCHAR(32)"`
|
||||
}
|
||||
|
||||
func (Panel) TableName() string {
|
||||
return "panels"
|
||||
}
|
||||
|
||||
func AddPanel(messageId, channelId, guildId int64, title, content string, colour int, targetCategory int64, reactionEmote string) {
|
||||
database.Database.Create(&Panel{
|
||||
MessageId: messageId,
|
||||
ChannelId: channelId,
|
||||
GuildId: guildId,
|
||||
|
||||
Title: title,
|
||||
Content: content,
|
||||
Colour: colour,
|
||||
TargetCategory: targetCategory,
|
||||
ReactionEmote: reactionEmote,
|
||||
})
|
||||
}
|
||||
|
||||
func IsPanel(messageId int64, ch chan bool) {
|
||||
var count int
|
||||
database.Database.Table(Panel{}.TableName()).Where(Panel{MessageId: messageId}).Count(&count)
|
||||
ch <- count > 0
|
||||
}
|
||||
|
||||
func GetPanelsByGuild(guildId int64, ch chan []Panel) {
|
||||
var panels []Panel
|
||||
database.Database.Where(Panel{GuildId: guildId}).Find(&panels)
|
||||
ch <- panels
|
||||
}
|
||||
|
||||
func DeletePanel(msgId int64) {
|
||||
database.Database.Where(Panel{MessageId: msgId}).Delete(Panel{})
|
||||
}
|
1939
emojis.json
Normal file
1939
emojis.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -4,10 +4,6 @@
|
||||
@font-face{font-family:WhitneyMedium;font-style:medium;font-weight:600;src:url('https://discordapp.com/assets/be0060dafb7a0e31d2a1ca17c0708636.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:bold;font-weight:700;src:url('https://discordapp.com/assets/8e12fb4f14d9c4592eb8ec9f22337b04.woff') format('woff')}
|
||||
|
||||
html {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.discord-container {
|
||||
background-color: #2e3136;
|
||||
border-radius: 4px;
|
||||
|
@ -14,6 +14,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/tickets">Ticket List</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/panels">Panels</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
237
public/templates/views/panels.tmpl
Normal file
237
public/templates/views/panels.tmpl
Normal file
@ -0,0 +1,237 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Panels</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Your panel quota: <b>{{.panelcount}} / {{if .premium}}∞{{else}}1{{end}}</b></p>
|
||||
|
||||
{{if not .premium}}
|
||||
<p>Note: You can expand your panel quote by purchasing premium</p>
|
||||
{{end}}
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Channel</th>
|
||||
<th>Panel Title</th>
|
||||
<th>Panel Content</th>
|
||||
<th>Ticket Channel Category</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .panels}}
|
||||
<tr>
|
||||
<td>{{.ChannelName}}</td>
|
||||
<td>{{.Title}}</td>
|
||||
<td>{{.Content}}</td>
|
||||
<td>{{.CategoryName}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/panels/delete/{{.MessageId}}?csrf={{$.csrf}}">Delete</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Create A Panel</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="/manage/{{.guildId}}/panels/create">
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Panel Title</label>
|
||||
<input name="title" type="text" class="form-control" placeholder="Open a ticket!">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Panel Content</label>
|
||||
<textarea name="content" type="text" class="form-control"
|
||||
placeholder="By reacting to this ticket, a ticket will be opened for you."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 pr-1">
|
||||
<label>Panel Colour (Hex)</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<input name="colour" type="text" class="form-control" placeholder="23A31A">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label>Panel Channel</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="channel">
|
||||
{{range $id, $name := .channels}}
|
||||
<option value="{{$id}}">{{$name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label>Ticket Channel Category</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="categories">
|
||||
{{range $id, $name := .categories}}
|
||||
<option value="{{$id}}">{{$name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Reaction Emote</label>
|
||||
<input name="reaction" type="text" class="form-control" placeholder="envelope_with_arrow">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="col-md-2 pr-1 offset-md-5">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if not .validTitle}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Panel titles must be between 1 and 255 characters long
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validContent}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Panel content must be between 1 and 1024 characters long
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validColour}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid panel colour. You must use the hex value of the colour, which you can find <a href="https://www.google.co.uk/search?client=opera&q=html+colour+picker">here</a>.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validChannel}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid channel - please try again
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validCategory}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid category - please try again
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validReaction}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid reaction emote
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .created}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Success</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Your panel has been created. You may need to refresh this page to see it displayed.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .metQuota}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
You've hit your panel quota. Premium users can create <b>unlimited panels</b>. Click <a href="https://ticketsbot.net/premium">here</a> to learn more about premium.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{end}}
|
@ -79,6 +79,11 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<h4>Default Panel Settings</h4>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label>Panel Title</label>
|
||||
<input name="paneltitle" type="text" class="form-control" placeholder="Open A Ticket" value="{{.paneltitle}}">
|
||||
|
30
utils/emojiutil.go
Normal file
30
utils/emojiutil.go
Normal file
@ -0,0 +1,30 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/apex/log"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var emojis map[string]interface{}
|
||||
|
||||
func LoadEmoji() {
|
||||
bytes, err := ioutil.ReadFile("emojis.json"); if err != nil {
|
||||
log.Error("Couldn't load emoji: " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(bytes, &emojis); err != nil {
|
||||
log.Error("Couldn't load emoji: " + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func GetEmojiByName(name string) string {
|
||||
emoji, ok := emojis[name]; if !ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
str, _ := emoji.(string)
|
||||
return str
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user