latest
This commit is contained in:
parent
4822ba54a3
commit
bc3fa195c1
@ -1,22 +0,0 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func IndexHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
package endpoints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func LoginHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
redirect := url.QueryEscape(fmt.Sprintf("%s/callback", config.Conf.Server.BaseUrl))
|
||||
ctx.Redirect(302, fmt.Sprintf("https://discordapp.com/oauth2/authorize?response_type=code&redirect_uri=%s&scope=identify+guilds&client_id=%d", redirect, config.Conf.Oauth.Id))
|
||||
}
|
67
app/http/endpoints/manage/logs.go
Normal file
67
app/http/endpoints/manage/logs.go
Normal file
@ -0,0 +1,67 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/app/http/template"
|
||||
"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 LogsHandler(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
|
||||
}
|
||||
|
||||
pageStr := ctx.Param("page")
|
||||
page := 1
|
||||
i, err := strconv.Atoi(pageStr); if err == nil {
|
||||
if i > 0 {
|
||||
page = i
|
||||
}
|
||||
}
|
||||
|
||||
// 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 !guild.Owner && !table.IsAdmin(guildId, userId) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
utils.Respond(ctx, template.TemplateSettings.Render(map[string]interface{}{
|
||||
"name": store.Get("name").(string),
|
||||
"guildId": guildIdStr,
|
||||
}))
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
}
|
169
app/http/endpoints/manage/settings.go
Normal file
169
app/http/endpoints/manage/settings.go
Normal file
@ -0,0 +1,169 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/app/http/template"
|
||||
"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"
|
||||
)
|
||||
|
||||
func SettingsHandler(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 !guild.Owner && !table.IsAdmin(guildId, userId) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get prefix
|
||||
prefix := ctx.Query("prefix")
|
||||
if prefix == "" {
|
||||
prefix = table.GetPrefix(guildId)
|
||||
} else {
|
||||
table.UpdatePrefix(guildId, prefix)
|
||||
}
|
||||
|
||||
// Get welcome message
|
||||
welcomeMessage := ctx.Query("welcomeMessage")
|
||||
if welcomeMessage == "" {
|
||||
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
|
||||
if limitStr == "" || !utils.IsInt(limitStr) {
|
||||
limit = table.GetTicketLimit(guildId)
|
||||
} else {
|
||||
table.UpdateTicketLimit(guildId, limit)
|
||||
}
|
||||
|
||||
// Get a list of actual category IDs
|
||||
categories := guild.GetCategories()
|
||||
|
||||
// /users/@me/guilds doesn't return channels, so we have to get them for the specific guild
|
||||
if len(categories) == 0 {
|
||||
var channels []objects.Channel
|
||||
endpoint := guildendpoint.GetGuildChannels(int(guildId))
|
||||
err = endpoint.Request(store, nil, nil, &channels)
|
||||
|
||||
if err != nil {
|
||||
// Not in guild
|
||||
} else {
|
||||
guild.Channels = channels
|
||||
categories = guild.GetCategories()
|
||||
|
||||
// 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 {
|
||||
table.UpdateGuilds(userIdStr, base64.StdEncoding.EncodeToString(marshalled))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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)),
|
||||
})
|
||||
}
|
||||
|
||||
utils.Respond(ctx, template.TemplateSettings.Render(map[string]interface{}{
|
||||
"name": store.Get("name").(string),
|
||||
"guildId": guildIdStr,
|
||||
"prefix": prefix,
|
||||
"welcomeMessage": welcomeMessage,
|
||||
"ticketLimit": limit,
|
||||
"categories": formattedCategories,
|
||||
}))
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
}
|
@ -1,9 +1,15 @@
|
||||
package endpoints
|
||||
package root
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/endpoints/user"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"github.com/apex/log"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
@ -35,6 +41,11 @@ func CallbackHandler(ctx *gin.Context) {
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl)
|
||||
return
|
||||
}
|
||||
|
||||
code := ctx.DefaultQuery("code", "")
|
||||
if code == "" {
|
||||
ctx.String(400, "Discord provided an invalid Oauth2 code")
|
||||
@ -58,10 +69,25 @@ func CallbackHandler(ctx *gin.Context) {
|
||||
|
||||
store.Set("userid", currentUser.Id)
|
||||
store.Set("name", currentUser.Username)
|
||||
|
||||
// Get Guilds
|
||||
var currentUserGuilds []objects.Guild
|
||||
err = user.CurrentUserGuilds.Request(store, nil, nil, ¤tUserGuilds); if err != nil {
|
||||
ctx.String(500, err.Error())
|
||||
if err = store.Save(); err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
|
||||
ctx.Redirect(302,config.Conf.Server.BaseUrl)
|
||||
|
||||
// Cache guilds because Discord takes like 2 whole seconds to return then
|
||||
go func() {
|
||||
var guilds []objects.Guild
|
||||
err = user.CurrentUserGuilds.Request(store, nil, nil, &guilds); if err != nil {
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
marshalled, err := json.Marshal(guilds); if err != nil {
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
table.UpdateGuilds(currentUser.Id, base64.StdEncoding.EncodeToString(marshalled))
|
||||
}()
|
||||
}
|
61
app/http/endpoints/root/index.go
Normal file
61
app/http/endpoints/root/index.go
Normal file
@ -0,0 +1,61 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/app/http/template"
|
||||
"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 IndexHandler(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
|
||||
}
|
||||
|
||||
adminGuilds := make([]objects.Guild, 0)
|
||||
adminGuildIds := table.GetAdminGuilds(userId)
|
||||
for _, guild := range table.GetGuilds(userIdStr) {
|
||||
guildId, err := strconv.ParseInt(guild.Id, 10, 64); if err != nil {
|
||||
ctx.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if guild.Owner || utils.Contains(adminGuildIds, guildId) {
|
||||
adminGuilds = append(adminGuilds, guild)
|
||||
}
|
||||
}
|
||||
|
||||
var servers []map[string]string
|
||||
for _, server := range adminGuilds {
|
||||
element := map[string]string{
|
||||
"serverid": server.Id,
|
||||
"servername": server.Name,
|
||||
}
|
||||
|
||||
servers = append(servers, element)
|
||||
}
|
||||
|
||||
utils.Respond(ctx, template.TemplateIndex.Render(map[string]interface{}{
|
||||
"name": store.Get("name").(string),
|
||||
"baseurl": config.Conf.Server.BaseUrl,
|
||||
"servers": servers,
|
||||
"empty": len(servers) == 0,
|
||||
}))
|
||||
} else {
|
||||
ctx.Redirect(302, "/login")
|
||||
}
|
||||
}
|
||||
|
25
app/http/endpoints/root/login.go
Normal file
25
app/http/endpoints/root/login.go
Normal file
@ -0,0 +1,25 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func LoginHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl)
|
||||
} else {
|
||||
redirect := url.QueryEscape(config.Conf.Oauth.RedirectUri)
|
||||
ctx.Redirect(302, fmt.Sprintf("https://discordapp.com/oauth2/authorize?response_type=code&redirect_uri=%s&scope=identify+guilds&client_id=%d", redirect, config.Conf.Oauth.Id))
|
||||
}
|
||||
}
|
17
app/http/endpoints/root/logout.go
Normal file
17
app/http/endpoints/root/logout.go
Normal file
@ -0,0 +1,17 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func LogoutHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
store.Clear()
|
||||
ctx.Redirect(302, "https://ticketsbot.net")
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/app/http/template"
|
||||
)
|
||||
|
||||
type Layout string
|
||||
|
||||
const(
|
||||
Main Layout = "main"
|
||||
)
|
||||
|
||||
var(
|
||||
layouts = map[string]template.Layout{
|
||||
Main.ToString(): template.LoadLayout(Main.ToString()),
|
||||
}
|
||||
)
|
||||
|
||||
func (l Layout) ToString() string {
|
||||
return string(l)
|
||||
}
|
||||
|
||||
func (l Layout) GetInstance() template.Layout {
|
||||
return layouts[l.ToString()]
|
||||
}
|
@ -2,7 +2,9 @@ package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/app/http/endpoints"
|
||||
"github.com/TicketsBot/GoPanel/app/http/endpoints/manage"
|
||||
"github.com/TicketsBot/GoPanel/app/http/endpoints/root"
|
||||
"github.com/TicketsBot/GoPanel/app/http/template"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/gin-contrib/static"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
@ -13,6 +15,10 @@ import (
|
||||
func StartServer() {
|
||||
log.Println("Starting HTTP server")
|
||||
|
||||
// Compile templates
|
||||
template.LoadLayouts()
|
||||
template.LoadTemplates()
|
||||
|
||||
router := gin.Default()
|
||||
|
||||
// Sessions
|
||||
@ -30,19 +36,22 @@ func StartServer() {
|
||||
router.Use(static.Serve("/assets/", static.LocalFile("./public/static", false)))
|
||||
|
||||
// Root
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
endpoints.IndexHandler(c)
|
||||
})
|
||||
router.GET("/", root.IndexHandler)
|
||||
|
||||
// /login
|
||||
router.GET("/login", func(c *gin.Context) {
|
||||
endpoints.LoginHandler(c)
|
||||
})
|
||||
router.GET("/login", root.LoginHandler)
|
||||
|
||||
// /callback
|
||||
router.GET("/callback", func(c *gin.Context) {
|
||||
endpoints.CallbackHandler(c)
|
||||
})
|
||||
router.GET("/callback", root.CallbackHandler)
|
||||
|
||||
// /logout
|
||||
router.GET("/logout", root.LogoutHandler)
|
||||
|
||||
// /manage/:id/settings
|
||||
router.GET("/manage/:id/settings", manage.SettingsHandler)
|
||||
|
||||
// /manage/:id/logs/page/:page
|
||||
router.GET("/manage/:id/logs/page/:page", manage.LogsHandler)
|
||||
|
||||
if err := router.Run(config.Conf.Server.Host); err != nil {
|
||||
panic(err)
|
||||
|
@ -1,22 +0,0 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
)
|
||||
|
||||
type Layout struct {
|
||||
Name string
|
||||
Content string
|
||||
}
|
||||
|
||||
func LoadLayout(name string) Layout {
|
||||
content, err := utils.ReadFile(fmt.Sprintf("./public/templates/layouts/%s.mustache", name)); if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return Layout{
|
||||
Name: name,
|
||||
Content: content,
|
||||
}
|
||||
}
|
@ -2,26 +2,63 @@ package template
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/hoisie/mustache"
|
||||
)
|
||||
|
||||
type Template struct {
|
||||
Layout Layout
|
||||
Content string
|
||||
type Layout struct {
|
||||
compiled *mustache.Template
|
||||
}
|
||||
|
||||
func LoadTemplate(layout Layout, name string) Template {
|
||||
content, err := utils.ReadFile(fmt.Sprintf("./public/templates/views/%s.mustache", name)); if err != nil {
|
||||
type Template struct {
|
||||
compiled *mustache.Template
|
||||
Layout Layout
|
||||
}
|
||||
|
||||
var(
|
||||
LayoutMain Layout
|
||||
|
||||
TemplateIndex Template
|
||||
TemplateLogs Template
|
||||
TemplateSettings Template
|
||||
)
|
||||
|
||||
func (t *Template) Render(context ...interface{}) string {
|
||||
return t.compiled.RenderInLayout(t.Layout.compiled, context[0])
|
||||
}
|
||||
|
||||
func LoadLayouts() {
|
||||
LayoutMain = Layout{
|
||||
compiled: loadLayout("main"),
|
||||
}
|
||||
}
|
||||
|
||||
func LoadTemplates() {
|
||||
TemplateIndex = Template{
|
||||
compiled: loadTemplate("index"),
|
||||
Layout: LayoutMain,
|
||||
}
|
||||
TemplateLogs = Template{
|
||||
compiled: loadTemplate("logs"),
|
||||
Layout: LayoutMain,
|
||||
}
|
||||
TemplateSettings = Template{
|
||||
compiled: loadTemplate("settings"),
|
||||
Layout: LayoutMain,
|
||||
}
|
||||
}
|
||||
|
||||
func loadLayout(name string) *mustache.Template {
|
||||
tmpl, err := mustache.ParseFile(fmt.Sprintf("./public/templates/layouts/%s.mustache", name)); if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return Template{
|
||||
Layout: layout,
|
||||
Content: content,
|
||||
}
|
||||
return tmpl
|
||||
}
|
||||
|
||||
func (t *Template) Render(context ...interface{}) string {
|
||||
return mustache.RenderInLayout(t.Content, t.Layout.Content, context)
|
||||
func loadTemplate(name string) *mustache.Template {
|
||||
tmpl, err := mustache.ParseFile(fmt.Sprintf("./public/templates/views/%s.mustache", name)); if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return tmpl
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
package http
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/app/http/template"
|
||||
|
||||
type Template string
|
||||
|
||||
const(
|
||||
Index Template = "index"
|
||||
)
|
||||
|
||||
var(
|
||||
templates = map[string]template.Template{
|
||||
Index.ToString(): template.LoadTemplate(Main.GetInstance(), Index.ToString()),
|
||||
}
|
||||
)
|
||||
|
||||
func (t Template) ToString() string {
|
||||
return string(t)
|
||||
}
|
||||
|
||||
func (t Template) GetInstance() template.Template {
|
||||
return templates[t.ToString()]
|
||||
}
|
||||
|
||||
func (t Template) Render(context ...interface{}) string {
|
||||
temp := t.GetInstance()
|
||||
return temp.Render(context)
|
||||
}
|
@ -21,6 +21,9 @@ password="ryan"
|
||||
database="tickets"
|
||||
threads=5
|
||||
|
||||
[bot]
|
||||
token=""
|
||||
|
||||
[redis]
|
||||
host="127.0.0.1"
|
||||
port=6379
|
||||
|
@ -18,6 +18,7 @@ type(
|
||||
Host string
|
||||
BaseUrl string
|
||||
MainSite string
|
||||
CsrfKey string
|
||||
Ratelimit Ratelimit
|
||||
Session Session
|
||||
}
|
||||
@ -47,8 +48,7 @@ type(
|
||||
}
|
||||
|
||||
Bot struct {
|
||||
Key string
|
||||
HttpServer []string
|
||||
Token string
|
||||
}
|
||||
|
||||
Redis struct {
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
var(
|
||||
database **gorm.DB
|
||||
Database gorm.DB
|
||||
)
|
||||
|
||||
func ConnectToDatabase() {
|
||||
@ -27,5 +27,5 @@ func ConnectToDatabase() {
|
||||
db.DB().SetMaxOpenConns(config.Conf.MariaDB.Threads)
|
||||
db.DB().SetMaxIdleConns(0)
|
||||
|
||||
database = &db
|
||||
Database = *db
|
||||
}
|
||||
|
25
database/table/channelcategory.go
Normal file
25
database/table/channelcategory.go
Normal file
@ -0,0 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type ChannelCategory struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Category int64 `gorm:"column:CATEGORYID"`
|
||||
}
|
||||
|
||||
func (ChannelCategory) TableName() string {
|
||||
return "channelcategory"
|
||||
}
|
||||
|
||||
func UpdateChannelCategory(guildId int64, categoryId int64) {
|
||||
database.Database.Where(&ChannelCategory{GuildId: guildId}).Assign(&ChannelCategory{Category: categoryId}).FirstOrCreate(&ChannelCategory{})
|
||||
}
|
||||
|
||||
func GetChannelCategory(guildId int64) int64 {
|
||||
var category ChannelCategory
|
||||
database.Database.Where(&ChannelCategory{GuildId: guildId}).First(&category)
|
||||
|
||||
return category.Category
|
||||
}
|
37
database/table/guilds.go
Normal file
37
database/table/guilds.go
Normal file
@ -0,0 +1,37 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
)
|
||||
|
||||
type GuildCache struct {
|
||||
UserId string `gorm:"column:USERID;type:varchar(20)"` // Apparently I made this a VARCHAR in the JS version
|
||||
Guilds string `gorm:"column:guilds;type:mediumtext"`
|
||||
}
|
||||
|
||||
func (GuildCache) TableName() string {
|
||||
return "guildscache"
|
||||
}
|
||||
|
||||
func UpdateGuilds(userId string, guilds string) {
|
||||
var cache GuildCache
|
||||
database.Database.Where(&GuildCache{UserId: userId}).Assign(&GuildCache{Guilds: guilds}).FirstOrCreate(&cache)
|
||||
}
|
||||
|
||||
func GetGuilds(userId string) []objects.Guild {
|
||||
var cache GuildCache
|
||||
database.Database.Where(&GuildCache{UserId: userId}).First(&cache)
|
||||
decoded, err := base64.StdEncoding.DecodeString(cache.Guilds); if err != nil {
|
||||
return make([]objects.Guild, 0)
|
||||
}
|
||||
|
||||
var guilds []objects.Guild
|
||||
if err := json.Unmarshal(decoded, &guilds); err != nil {
|
||||
return make([]objects.Guild, 0)
|
||||
}
|
||||
|
||||
return guilds
|
||||
}
|
32
database/table/permissions.go
Normal file
32
database/table/permissions.go
Normal file
@ -0,0 +1,32 @@
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type PermissionNode struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
UserId int64 `gorm:"column:USERID"`
|
||||
IsSupport bool `gorm:"column:ISSUPPORT"`
|
||||
IsAdmin bool `gorm:"column:ISADMIN"`
|
||||
}
|
||||
|
||||
func (PermissionNode) TableName() string {
|
||||
return "permissions"
|
||||
}
|
||||
|
||||
func GetAdminGuilds(userId int64) []int64 {
|
||||
var nodes []PermissionNode
|
||||
database.Database.Where(&PermissionNode{UserId: userId}).Find(&nodes)
|
||||
|
||||
ids := make([]int64, 0)
|
||||
for _, node := range nodes {
|
||||
ids = append(ids, node.GuildId)
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
func IsAdmin(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin
|
||||
}
|
25
database/table/prefix.go
Normal file
25
database/table/prefix.go
Normal file
@ -0,0 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type Prefix struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Prefix string `gorm:"column:PREFIX;type:varchar(8)"`
|
||||
}
|
||||
|
||||
func (Prefix) TableName() string {
|
||||
return "prefix"
|
||||
}
|
||||
|
||||
func UpdatePrefix(guildId int64, prefix string) {
|
||||
database.Database.Where(&Prefix{GuildId: guildId}).Assign(&Prefix{Prefix: prefix}).FirstOrCreate(&Prefix{})
|
||||
}
|
||||
|
||||
func GetPrefix(guildId int64) string {
|
||||
prefix := Prefix{Prefix:"t!"}
|
||||
database.Database.Where(&Prefix{GuildId: guildId}).First(&prefix)
|
||||
|
||||
return prefix.Prefix
|
||||
}
|
44
database/table/ticketarchive.go
Normal file
44
database/table/ticketarchive.go
Normal file
@ -0,0 +1,44 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type TicketArchive struct {
|
||||
Uuid string `gorm:"column:UUID;type:varchar(36)"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
User int64 `gorm:"column:USERID"`
|
||||
Username string `gorm:"column:USERNAME;type:varchar(32)"`
|
||||
TicketId int `gorm:"column:TICKETID"`
|
||||
CdnUrl string `gorm:"column:CDNURL;type:varchar(100)"`
|
||||
}
|
||||
|
||||
func (TicketArchive) TableName() string {
|
||||
return "ticketarchive"
|
||||
}
|
||||
|
||||
func GetTicketArchives(guildId int64) []TicketArchive {
|
||||
var archives []TicketArchive
|
||||
database.Database.Where(&TicketArchive{Guild: guildId}).Find(&archives)
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
func GetFilteredTicketArchives(guildId int64, userId int64, username string, ticketId int) []TicketArchive {
|
||||
var archives []TicketArchive
|
||||
|
||||
query := database.Database.Where(&TicketArchive{Guild: guildId})
|
||||
if userId != 0 {
|
||||
query = query.Where(&TicketArchive{User: userId})
|
||||
}
|
||||
if username != "" {
|
||||
query = query.Where(&TicketArchive{Username: username})
|
||||
}
|
||||
if ticketId != 0 {
|
||||
query = query.Where(&TicketArchive{TicketId: ticketId})
|
||||
}
|
||||
|
||||
query.Find(&archives)
|
||||
|
||||
return archives
|
||||
}
|
25
database/table/ticketlimit.go
Normal file
25
database/table/ticketlimit.go
Normal file
@ -0,0 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type TicketLimit struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Limit int `gorm:"column:TICKETLIMIT"`
|
||||
}
|
||||
|
||||
func (TicketLimit) TableName() string {
|
||||
return "ticketlimit"
|
||||
}
|
||||
|
||||
func UpdateTicketLimit(guildId int64, limit int) {
|
||||
database.Database.Where(&TicketLimit{GuildId: guildId}).Assign(&TicketLimit{Limit: limit}).FirstOrCreate(&TicketLimit{})
|
||||
}
|
||||
|
||||
func GetTicketLimit(guildId int64) int {
|
||||
limit := TicketLimit{Limit: 5}
|
||||
database.Database.Where(&TicketLimit{GuildId: guildId}).First(&limit)
|
||||
|
||||
return limit.Limit
|
||||
}
|
25
database/table/welcomemessage.go
Normal file
25
database/table/welcomemessage.go
Normal file
@ -0,0 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type WelcomeMessage struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Message string `gorm:"column:MESSAGE;type:text"`
|
||||
}
|
||||
|
||||
func (WelcomeMessage) TableName() string {
|
||||
return "welcomemessages"
|
||||
}
|
||||
|
||||
func UpdateWelcomeMessage(guildId int64, message string) {
|
||||
database.Database.Where(&WelcomeMessage{GuildId: guildId}).Assign(&WelcomeMessage{Message: message}).FirstOrCreate(&WelcomeMessage{})
|
||||
}
|
||||
|
||||
func GetWelcomeMessage(guildId int64) string {
|
||||
message := WelcomeMessage{Message:"No message specified"}
|
||||
database.Database.Where(&WelcomeMessage{GuildId: guildId}).First(&message)
|
||||
|
||||
return message.Message
|
||||
}
|
@ -37,6 +37,6 @@
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
{{{body}}}
|
||||
{{{content}}}
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,23 +1,24 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
{{#if isNotAdmin}}
|
||||
{{#empty}}
|
||||
<p class="center-align" style="padding-top: 50px; font-size: 16px">
|
||||
You are not the admin of any guilds that the bot is in. Click below to invite the bot:
|
||||
<br />
|
||||
<a href="https://invite.ticketsbot.net">Invite</a>
|
||||
</p>
|
||||
{{else}}
|
||||
{{/empty}}
|
||||
{{^empty}}
|
||||
<p class="center-align" style="padding-top: 50px; font-size: 16px">
|
||||
Select a server to manage below
|
||||
</p>
|
||||
|
||||
<ul class="collection">
|
||||
{{#each guilds}}
|
||||
<li class="collection-item"><a href="{{baseUrl}}/manage/{{id}}/settings">{{name}}</a></li>
|
||||
{{/each}}
|
||||
{{#servers}}
|
||||
<li class="collection-item"><a href="{{baseUrl}}/manage/{{serverid}}/settings">{{servername}}</a></li>
|
||||
{{/servers}}
|
||||
</ul>
|
||||
{{/if}}
|
||||
{{/empty}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -59,7 +59,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each logs}}
|
||||
{{#logs}}
|
||||
{{{baseUrl}}}
|
||||
<tr>
|
||||
<td>{{TICKETID}}</td>
|
||||
@ -67,7 +67,7 @@
|
||||
<td>{{USERID}}</td>
|
||||
<td><a href="{{baseUrl}}/logs/{{UUID}}">{{UUID}}</a></td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{/logs}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -77,11 +77,12 @@
|
||||
<div class="col s12 center-align">
|
||||
<p class="center-align">Pages</p>
|
||||
<ul class="pagination center-align">
|
||||
{{#if isPageOne}}
|
||||
{{#isPageOne}}
|
||||
<li class="disabled"><a href="#"><i class="material-icons">chevron_left</i></a></li>
|
||||
{{else}}
|
||||
{{/isPageOne}}
|
||||
{{^isPageOne}}
|
||||
<li class="waves-effect"><a href="/manage/{{guildId}}/logs/page/{{previousPage}}"><i class="material-icons">chevron_left</i></a></li>
|
||||
{{/if}}
|
||||
{{/isPageOne}}
|
||||
<li class="waves-effect"><a href="/manage/{{guildId}}/logs/page/{{nextPage}}"><i class="material-icons">chevron_right</i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -1,16 +1,15 @@
|
||||
<script>
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var elems = document.querySelectorAll('select');
|
||||
var instances = M.FormSelect.init(elems, {});
|
||||
});
|
||||
|
||||
{{#if invalidPrefix}}
|
||||
M.toast({html: 'Prefixes must be between 1 and 8 characters'})
|
||||
{{/if}}
|
||||
{{#if invalidMessage}}
|
||||
M.toast({html: 'Welcome messages must be between 1 and 1000 characters'})
|
||||
{{/if}}
|
||||
{{#invalidPrefix}}
|
||||
M.toast({html: 'Prefixes must be between 1 and 8 characters'});
|
||||
{{/invalidPrefix}}
|
||||
{{#invalidMessage}}
|
||||
M.toast({html: 'Welcome messages must be between 1 and 1000 characters'});
|
||||
{{/invalidMessage}}
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
@ -53,13 +52,14 @@
|
||||
<div class="input-field col s12">
|
||||
<p><b>Channel Category</b></p>
|
||||
<select name="category">
|
||||
{{#each categories}}
|
||||
{{#if active}}
|
||||
<option value="{{id}}" selected>{{name}}</option>
|
||||
{{else}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
{{#categories}}
|
||||
{{#active}}
|
||||
<option value="{{categoryid}}" selected>{{categoryname}}</option>
|
||||
{{/active}}
|
||||
{{^active}}
|
||||
<option value="{{categoryid}}">{{categoryname}}</option>
|
||||
{{/active}}
|
||||
{{/categories}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,6 +3,7 @@ package discord
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/pasztorpisti/qs"
|
||||
"github.com/pkg/errors"
|
||||
@ -13,12 +14,16 @@ import (
|
||||
|
||||
type RequestType string
|
||||
type ContentType string
|
||||
type AuthorizationType string
|
||||
|
||||
const(
|
||||
GET RequestType = "GET"
|
||||
POST RequestType = "POST"
|
||||
PATCH RequestType = "PATCH"
|
||||
|
||||
BEARER AuthorizationType = "Bearer"
|
||||
BOT AuthorizationType = "BOT"
|
||||
|
||||
ApplicationJson ContentType = "application/json"
|
||||
ApplicationFormUrlEncoded ContentType = "application/x-www-form-urlencoded"
|
||||
|
||||
@ -27,6 +32,7 @@ const(
|
||||
|
||||
type Endpoint struct {
|
||||
RequestType RequestType
|
||||
AuthorizationType AuthorizationType
|
||||
Endpoint string
|
||||
}
|
||||
|
||||
@ -65,7 +71,7 @@ func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, bod
|
||||
if contentType != nil {
|
||||
req.Header.Set("Content-Type", string(*contentType))
|
||||
}
|
||||
req.Header.Set("User-Agent", "DiscordBot (https://github.com/TicketsBot/GoPanel 1.0.0)")
|
||||
req.Header.Set("User-Agent", "DiscordBot (https://github.com/TicketsBot/GoPanel, 1.0.0)")
|
||||
|
||||
// Auth
|
||||
accessToken := store.Get("access_token").(string)
|
||||
@ -86,7 +92,11 @@ func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, bod
|
||||
|
||||
accessToken = res.AccessToken
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer " + accessToken)
|
||||
|
||||
switch e.AuthorizationType{
|
||||
case BEARER: req.Header.Set("Authorization", "Bearer " + accessToken)
|
||||
case BOT: req.Header.Set("Authorization", "Bot " + config.Conf.Bot.Token)
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
client.Timeout = 3 * time.Second
|
||||
|
@ -3,11 +3,13 @@ package guild
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetGuild(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
Endpoint: fmt.Sprintf("/guilds/%d", id),
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/guilds/%s", strconv.Itoa(id)),
|
||||
}
|
||||
}
|
||||
|
14
utils/discord/endpoints/guild/getGuildChannels.go
Normal file
14
utils/discord/endpoints/guild/getGuildChannels.go
Normal file
@ -0,0 +1,14 @@
|
||||
package guild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
)
|
||||
|
||||
func GetGuildChannels(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/guilds/%d/channels", id),
|
||||
}
|
||||
}
|
@ -4,5 +4,6 @@ import "github.com/TicketsBot/GoPanel/utils/discord"
|
||||
|
||||
var CurrentUser = discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BEARER,
|
||||
Endpoint: "/users/@me",
|
||||
}
|
||||
|
@ -4,5 +4,6 @@ import "github.com/TicketsBot/GoPanel/utils/discord"
|
||||
|
||||
var CurrentUserGuilds = discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BEARER,
|
||||
Endpoint: "/users/@me/guilds",
|
||||
}
|
||||
|
@ -38,3 +38,15 @@ type Guild struct {
|
||||
Description string
|
||||
Banner string
|
||||
}
|
||||
|
||||
func (g *Guild) GetCategories() []Channel {
|
||||
var categories []Channel
|
||||
|
||||
for _, channel := range g.Channels {
|
||||
if channel.Type == 4 {
|
||||
categories = append(categories, channel)
|
||||
}
|
||||
}
|
||||
|
||||
return categories
|
||||
}
|
||||
|
7
utils/httputils.go
Normal file
7
utils/httputils.go
Normal file
@ -0,0 +1,7 @@
|
||||
package utils
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
func Respond(ctx *gin.Context, s string) {
|
||||
ctx.Data(200, "text/html; charset=utf-8", []byte(s))
|
||||
}
|
@ -2,8 +2,13 @@ package utils
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func IsLoggedIn(store sessions.Session) bool {
|
||||
return store.Get("access_token") != nil && store.Get("expiry") != nil && store.Get("refresh_token") != nil && store.Get("userid") != nil && store.Get("name") != nil
|
||||
}
|
||||
|
||||
func GetUserId(store sessions.Session) (int64, error) {
|
||||
return strconv.ParseInt(store.Get("userid").(string), 10, 64)
|
||||
}
|
||||
|
34
utils/sliceutils.go
Normal file
34
utils/sliceutils.go
Normal file
@ -0,0 +1,34 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func Contains(s interface{}, elem interface{}) bool {
|
||||
arrV := reflect.ValueOf(s)
|
||||
|
||||
if arrV.Kind() == reflect.Slice {
|
||||
for i := 0; i < arrV.Len(); i++ {
|
||||
|
||||
// XXX - panics if slice element points to an unexported struct field
|
||||
// see https://golang.org/pkg/reflect/#Value.Interface
|
||||
if arrV.Index(i).Interface() == elem {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func Insert(slice []objects.Guild, index int , value objects.Guild) []objects.Guild {
|
||||
// Grow the slice by one element.
|
||||
slice = slice[0 : len(slice)+1]
|
||||
// Use copy to move the upper part of the slice out of the way and open a hole.
|
||||
copy(slice[index+1:], slice[index:])
|
||||
// Store the new value.
|
||||
slice[index] = value
|
||||
// Return the result.
|
||||
return slice
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
package utils
|
||||
|
||||
import "math/rand"
|
||||
import (
|
||||
"math/rand"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
|
||||
@ -11,3 +14,8 @@ func RandStringRunes(length int) string {
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func IsInt(str string) bool {
|
||||
_, err := strconv.ParseInt(str, 10, 64)
|
||||
return err == nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user