This commit is contained in:
Dot-Rar 2019-05-25 23:25:00 +01:00
parent 4822ba54a3
commit bc3fa195c1
37 changed files with 785 additions and 179 deletions

View File

@ -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")
}
}

View File

@ -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))
}

View 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")
}
}

View 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")
}
}

View File

@ -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)
if err = store.Save(); err != nil {
log.Error(err.Error())
}
// Get Guilds
var currentUserGuilds []objects.Guild
err = user.CurrentUserGuilds.Request(store, nil, nil, &currentUserGuilds); if err != nil {
ctx.String(500, 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))
}()
}

View 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")
}
}

View 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))
}
}

View 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")
}

View File

@ -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()]
}

View File

@ -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)

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -21,6 +21,9 @@ password="ryan"
database="tickets"
threads=5
[bot]
token=""
[redis]
host="127.0.0.1"
port=6379

View File

@ -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 {

View File

@ -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
}

View 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
View 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
}

View 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
View 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
}

View 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
}

View 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
}

View 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
}

View File

@ -37,6 +37,6 @@
</ul>
</div>
</nav>
{{{body}}}
{{{content}}}
</body>
</html>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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)),
}
}

View 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),
}
}

View File

@ -4,5 +4,6 @@ import "github.com/TicketsBot/GoPanel/utils/discord"
var CurrentUser = discord.Endpoint{
RequestType: discord.GET,
AuthorizationType: discord.BEARER,
Endpoint: "/users/@me",
}

View File

@ -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",
}

View File

@ -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
View 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))
}

View File

@ -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
View 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
}

View File

@ -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
}