diff --git a/app/http/endpoints/manage/settings.go b/app/http/endpoints/manage/settings.go index 8135242..9e75abe 100644 --- a/app/http/endpoints/manage/settings.go +++ b/app/http/endpoints/manage/settings.go @@ -1,14 +1,10 @@ package manage import ( - "encoding/base64" - "encoding/json" "github.com/TicketsBot/GoPanel/config" "github.com/TicketsBot/GoPanel/database/table" "github.com/TicketsBot/GoPanel/utils" - guildendpoint "github.com/TicketsBot/GoPanel/utils/discord/endpoints/guild" "github.com/TicketsBot/GoPanel/utils/discord/objects" - "github.com/apex/log" "github.com/gin-gonic/contrib/sessions" "github.com/gin-gonic/gin" "strconv" @@ -52,128 +48,23 @@ func SettingsHandler(ctx *gin.Context) { return } - // Get CSRF token - csrfCorrect := ctx.Query("csrf") == store.Get("csrf").(string) - - // Get prefix - prefix := ctx.Query("prefix") - if prefix == "" || len(prefix) > 8 || !csrfCorrect { - prefix = table.GetPrefix(guildId) - } else { - table.UpdatePrefix(guildId, prefix) - } - - // Get welcome message - welcomeMessage := ctx.Query("welcomeMessage") - if welcomeMessage == "" || len(welcomeMessage) > 1000 || !csrfCorrect { - welcomeMessage = table.GetWelcomeMessage(guildId) - } else { - table.UpdateWelcomeMessage(guildId, welcomeMessage) - } - - // Get ticket limit - limitStr := ctx.Query("ticketlimit") - limit := 5 - - // Verify input is an int and overwrite default limit - if utils.IsInt(limitStr) { - limit, _ = strconv.Atoi(limitStr) - } - - // Update limit, or get current limit if user input is invalid - invalidTicketLimit := false - if limitStr == "" || !utils.IsInt(limitStr) || limit > 10 || limit < 1 || !csrfCorrect { - limit = table.GetTicketLimit(guildId) - - if limitStr != "" { // User wasn't setting anything - invalidTicketLimit = true - } - } else { - table.UpdateTicketLimit(guildId, limit) - } - - // Ping everyone + // Get settings from database + prefix := table.GetPrefix(guildId) + welcomeMessage := table.GetWelcomeMessage(guildId) + limit := table.GetTicketLimit(guildId) pingEveryone := table.GetPingEveryone(guildId) - pingEveryoneStr := ctx.Query("pingeveryone") - if csrfCorrect { - pingEveryone = pingEveryoneStr == "on" - table.UpdatePingEveryone(guildId, pingEveryone) - } + archiveChannel := table.GetArchiveChannel(guildId) + categoryId := table.GetChannelCategory(guildId) // /users/@me/guilds doesn't return channels, so we have to get them for the specific guild - if len(guild.Channels) == 0 { - var channels []objects.Channel - endpoint := guildendpoint.GetGuildChannels(int(guildId)) - err = endpoint.Request(store, nil, nil, &channels, nil) - - if err != nil { - // Not in guild - } else { - guild.Channels = channels - - // Update cache of categories now that we have them - guilds := table.GetGuilds(userIdStr) - - // Get index of guild - index := -1 - for i, g := range guilds { - if g.Id == guild.Id { - index = i - break - } - } - - if index != -1 { - // Delete - guilds = append(guilds[:index], guilds[index+1:]...) - - // Insert updated guild - guilds = utils.Insert(guilds, index, guild) - - marshalled, err := json.Marshal(guilds) - if err != nil { - log.Error(err.Error()) - } else { - if csrfCorrect { - table.UpdateGuilds(userIdStr, base64.StdEncoding.EncodeToString(marshalled)) - } - } - } - } - } + channelsChan := make(chan []table.Channel) + go table.GetCachedChannelsByGuild(guildId, channelsChan) + channels := <-channelsChan // Get a list of actual category IDs - categories := guild.GetCategories() - - // Convert to category IDs - var categoryIds []string - for _, c := range categories { - categoryIds = append(categoryIds, c.Id) - } - - categoryStr := ctx.Query("category") - var category int64 - - // Verify category ID is an int and set default category ID - if utils.IsInt(categoryStr) { - category, _ = strconv.ParseInt(categoryStr, 10, 64) - } - - // Update category, or get current category if user input is invalid - if categoryStr == "" || !utils.IsInt(categoryStr) || !utils.Contains(categoryIds, categoryStr) || !csrfCorrect { - category = table.GetChannelCategory(guildId) - } else { - table.UpdateChannelCategory(guildId, category) - } - - var formattedCategories []map[string]interface{} - for _, c := range categories { - formattedCategories = append(formattedCategories, map[string]interface{}{ - "categoryid": c.Id, - "categoryname": c.Name, - "active": c.Id == strconv.Itoa(int(category)), - }) - } + categoriesChan := make(chan []table.Channel) + go table.GetCategories(guildId, categoriesChan) + categories := <-categoriesChan // Archive channel // Create a list of IDs @@ -182,76 +73,16 @@ func SettingsHandler(ctx *gin.Context) { channelIds = append(channelIds, c.Id) } - // Update or get current archive channel if blank or invalid - var archiveChannel int64 - archiveChannelStr := ctx.Query("archivechannel") - - // Verify category ID is an int and set default category ID - if utils.IsInt(archiveChannelStr) { - archiveChannel, _ = strconv.ParseInt(archiveChannelStr, 10, 64) - } - - if archiveChannelStr == "" || !utils.IsInt(archiveChannelStr) || !utils.Contains(channelIds, archiveChannelStr) || !csrfCorrect { - archiveChannel = table.GetArchiveChannel(guildId) - } else { - table.UpdateArchiveChannel(guildId, archiveChannel) - } - - // Format channels for templating - var formattedChannels []map[string]interface{} - for _, c := range guild.Channels { - if c.Type == 0 { - formattedChannels = append(formattedChannels, map[string]interface{}{ - "channelid": c.Id, - "channelname": c.Name, - "active": c.Id == strconv.Itoa(int(archiveChannel)), - }) - } - } - panelSettings := table.GetPanelSettings(guildId) - panelUpdated := false - - // Get panel title - panelTitle := ctx.Query("paneltitle") - if panelTitle == "" || len(panelTitle) > 255 || !csrfCorrect { - panelTitle = panelSettings.Title - } else { - panelUpdated = true - } - - // Get panel content - panelContent := ctx.Query("panelcontent") - if panelContent == "" || len(panelContent) > 2048 || !csrfCorrect { - panelContent = panelSettings.Content - } else { - panelUpdated = true - } - - // Get panel colour - var panelColour uint64 - panelColourHex := ctx.Query("panelcolour") - if panelColourHex == "" || !csrfCorrect { - panelColour = uint64(panelSettings.Colour) - } else { - panelUpdated = true - panelColour, err = strconv.ParseUint(panelColourHex, 16, 32) - } - - if panelUpdated { - go table.UpdatePanelSettings(guildId, panelTitle, panelContent, int(panelColour)) - } // Users can close usersCanCloseChan := make(chan bool) go table.IsUserCanClose(guildId, usersCanCloseChan) usersCanClose := <-usersCanCloseChan - usersCanCloseStr := ctx.Query("userscanclose") - if csrfCorrect { - usersCanClose = usersCanCloseStr == "on" - table.SetUserCanClose(guildId, usersCanClose) - } + invalidPrefix := ctx.Query("validPrefix") == "false" + invalidWelcomeMessage := ctx.Query("validWelcomeMessage") == "false" + invalidTicketLimit := ctx.Query("validTicketLimit") == "false" ctx.HTML(200, "manage/settings", gin.H{ "name": store.Get("name").(string), @@ -260,16 +91,18 @@ func SettingsHandler(ctx *gin.Context) { "prefix": prefix, "welcomeMessage": welcomeMessage, "ticketLimit": limit, - "categories": formattedCategories, - "channels": formattedChannels, - "invalidPrefix": len(ctx.Query("prefix")) > 8, - "invalidWelcomeMessage": len(ctx.Query("welcomeMessage")) > 1000, + "categories": categories, + "activecategory": categoryId, + "channels": channels, + "archivechannel": archiveChannel, + "invalidPrefix": invalidPrefix, + "invalidWelcomeMessage": invalidWelcomeMessage, "invalidTicketLimit": invalidTicketLimit, "csrf": store.Get("csrf").(string), "pingEveryone": pingEveryone, - "paneltitle": panelTitle, - "panelcontent": panelContent, - "panelcolour": strconv.FormatInt(int64(panelColour), 16), + "paneltitle": panelSettings.Title, + "panelcontent": panelSettings.Content, + "panelcolour": strconv.FormatInt(int64(panelSettings.Colour), 16), "usersCanClose": usersCanClose, }) } else { diff --git a/app/http/endpoints/manage/updatesettings.go b/app/http/endpoints/manage/updatesettings.go new file mode 100644 index 0000000..b359983 --- /dev/null +++ b/app/http/endpoints/manage/updatesettings.go @@ -0,0 +1,157 @@ +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 UpdateSettingsHandler(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 prefix + prefix := ctx.PostForm("prefix") + prefixValid := false + if prefix != "" && len(prefix) < 8 { + table.UpdatePrefix(guildId, prefix) + prefixValid = true + } + + // Get welcome message + welcomeMessageValid := false + welcomeMessage := ctx.PostForm("welcomeMessage") + if welcomeMessage != "" && len(welcomeMessage) > 1000 { + table.UpdateWelcomeMessage(guildId, welcomeMessage) + welcomeMessageValid = true + } + + // Get ticket limit + var limit int + limitStr := ctx.PostForm("ticketlimit") + + // Verify input is an int and overwrite default limit + if utils.IsInt(limitStr) { + limit, _ = strconv.Atoi(limitStr) + } + + // Update limit, or get current limit if user input is invalid + ticketLimitValid := false + if limitStr != "" && utils.IsInt(limitStr) && limit >= 1 && limit <= 10 { + table.UpdateTicketLimit(guildId, limit) + ticketLimitValid = true + } + + // Ping everyone + pingEveryone := ctx.PostForm("pingeveryone") == "on" + table.UpdatePingEveryone(guildId, pingEveryone) + + // Get a list of actual category IDs + categories := make(chan []table.Channel) + go table.GetCategories(guildId, categories) + + // Convert to category IDs + var categoryIds []string + for _, category := range <-categories { + categoryIds = append(categoryIds, strconv.Itoa(int(category.ChannelId))) + } + + // Update category + categoryStr := ctx.PostForm("category") + if utils.Contains(categoryIds, categoryStr) { + // Error is impossible, as we check it's a valid channel already + category, _ := strconv.ParseInt(categoryStr, 10, 64) + table.UpdateChannelCategory(guildId, category) + } + + // Archive channel + // Create a list of IDs + var channelIds []string + for _, c := range guild.Channels { + channelIds = append(channelIds, c.Id) + } + + // Update or archive channel + archiveChannelStr := ctx.PostForm("archivechannel") + if utils.Contains(channelIds, archiveChannelStr) { + // Error is impossible, as we check it's a valid channel already + parsed, _ := strconv.ParseInt(archiveChannelStr, 10, 64) + table.UpdateArchiveChannel(guildId, parsed) + } + + // Get panel title + panelTitle := ctx.PostForm("paneltitle") + if panelTitle != "" && len(panelTitle) <= 255 { + table.UpdatePanelTitle(guildId, panelTitle) + } + + // Get panel content + panelContent := ctx.PostForm("panelcontent") + if panelContent != "" || len(panelContent) <= 2048 { + table.UpdatePanelContent(guildId, panelContent) + } + + // Get panel colour + panelColourHex := ctx.PostForm("panelcolour") + if panelColourHex == "" { + panelColour, err := strconv.ParseUint(panelColourHex, 16, 32) + if err == nil { + table.UpdatePanelColour(guildId, int(panelColour)) + } + } + + // Users can close + 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)) + } else { + ctx.Redirect(302, "/login") + } +} diff --git a/app/http/server.go b/app/http/server.go index ce1fd36..78a07b8 100644 --- a/app/http/server.go +++ b/app/http/server.go @@ -41,6 +41,7 @@ func StartServer() { router.GET("/logout", root.LogoutHandler) router.GET("/manage/:id/settings", manage.SettingsHandler) + router.POST("/manage/:id/settings", manage.UpdateSettingsHandler) router.GET("/manage/:id/logs/page/:page", manage.LogsHandler) router.GET("/manage/:id/logs/view/:uuid", manage.LogViewHandler) diff --git a/database/table/channels.go b/database/table/channels.go new file mode 100644 index 0000000..32a0b71 --- /dev/null +++ b/database/table/channels.go @@ -0,0 +1,56 @@ +package table + +import ( + "github.com/TicketsBot/GoPanel/database" +) + +type Channel struct { + ChannelId int64 `gorm:"column:CHANNELID"` + GuildId int64 `gorm:"column:GUILDID"` + Name string `gorm:"column:NAME;type:VARCHAR(32)"` + Type int `gorm:"column:CHANNELTYPE;type:TINYINT(1)"` +} + +func (Channel) TableName() string { + return "Channel" +} + +func StoreChannel(channelId, guildId int64, name string, channelType int) { + channel := Channel{ + ChannelId: channelId, + GuildId: guildId, + Name: name, + Type: channelType, + } + + database.Database.Where(&Channel{ChannelId:channelId}).Assign(&channel).FirstOrCreate(&Channel{}) +} + +func DeleteChannel(channelId int64) { + var node Channel + database.Database.Where(Channel{ChannelId: channelId}).Take(&node) + database.Database.Delete(&node) +} + +func GetCachedChannelsByGuild(guildId int64, res chan []Channel) { + var nodes []Channel + database.Database.Where(Channel{GuildId: guildId}).Find(&nodes) + res <- nodes +} + +// Util function ig +func GetCategories(guildId int64, res chan []Channel) { + channelsChan := make(chan []Channel) + go GetCachedChannelsByGuild(guildId, channelsChan) + channels := <-channelsChan + + var categories []Channel + + for _, channel := range channels { + if channel.Type == 4 { + categories = append(categories, channel) + } + } + + res <- categories +} diff --git a/database/table/panelsettings.go b/database/table/panelsettings.go index a094c4b..5713d8e 100644 --- a/database/table/panelsettings.go +++ b/database/table/panelsettings.go @@ -25,6 +25,30 @@ func UpdatePanelSettings(guildId int64, title string, content string, colour int database.Database.Where(&PanelSettings{GuildId: guildId}).Assign(&settings).FirstOrCreate(&PanelSettings{}) } +func UpdatePanelTitle(guildId int64, title string) { + settings := PanelSettings{ + Title: title, + } + + database.Database.Where(&PanelSettings{GuildId: guildId}).Assign(&settings).FirstOrCreate(&PanelSettings{}) +} + +func UpdatePanelContent(guildId int64, content string) { + settings := PanelSettings{ + Content: content, + } + + database.Database.Where(&PanelSettings{GuildId: guildId}).Assign(&settings).FirstOrCreate(&PanelSettings{}) +} + +func UpdatePanelColour(guildId int64, colour int) { + settings := PanelSettings{ + Colour: colour, + } + + database.Database.Where(&PanelSettings{GuildId: guildId}).Assign(&settings).FirstOrCreate(&PanelSettings{}) +} + func GetPanelSettings(guildId int64) PanelSettings { settings := PanelSettings{ Title: "Open A Ticket", diff --git a/public/templates/views/settings.tmpl b/public/templates/views/settings.tmpl index 70ba26c..15ea5f4 100644 --- a/public/templates/views/settings.tmpl +++ b/public/templates/views/settings.tmpl @@ -11,7 +11,7 @@ {{end}}