Finish porting panel

This commit is contained in:
2019-05-26 02:47:51 +01:00
parent bc3fa195c1
commit 208bdc03f3
43 changed files with 511 additions and 265 deletions

View File

@ -1 +0,0 @@
package database

View File

@ -20,21 +20,24 @@ func LogsHandler(ctx *gin.Context) {
if utils.IsLoggedIn(store) { if utils.IsLoggedIn(store) {
userIdStr := store.Get("userid").(string) userIdStr := store.Get("userid").(string)
userId, err := utils.GetUserId(store); if err != nil { userId, err := utils.GetUserId(store)
if err != nil {
ctx.String(500, err.Error()) ctx.String(500, err.Error())
return return
} }
// Verify the guild exists // Verify the guild exists
guildIdStr := ctx.Param("id") guildIdStr := ctx.Param("id")
guildId, err := strconv.ParseInt(guildIdStr, 10, 64); if err != nil { guildId, err := strconv.ParseInt(guildIdStr, 10, 64)
if err != nil {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
return return
} }
pageStr := ctx.Param("page") pageStr := ctx.Param("page")
page := 1 page := 1
i, err := strconv.Atoi(pageStr); if err == nil { i, err := strconv.Atoi(pageStr)
if err == nil {
if i > 0 { if i > 0 {
page = i page = i
} }
@ -55,11 +58,51 @@ func LogsHandler(ctx *gin.Context) {
return return
} }
pageLimit := 30
// Get logs
// Get user ID from URL
var filteredUserId int64
if utils.IsInt(ctx.Query("userid")) {
filteredUserId, _ = strconv.ParseInt(ctx.Query("userid"), 10, 64)
}
utils.Respond(ctx, template.TemplateSettings.Render(map[string]interface{}{ // Get ticket ID from URL
"name": store.Get("name").(string), var ticketId int
if utils.IsInt(ctx.Query("ticketid")) {
ticketId, _ = strconv.Atoi(ctx.Query("ticketid"))
}
// Get username from URL
username := ctx.Query("username")
// Get logs from DB
logs := table.GetFilteredTicketArchives(guildId, filteredUserId, username, ticketId)
// Select 30 logs + format them
var formattedLogs []map[string]interface{}
for i := (page - 1) * pageLimit; i < (page - 1) * pageLimit + pageLimit; i++ {
if i >= len(logs) {
break
}
log := logs[i]
formattedLogs = append(formattedLogs, map[string]interface{}{
"ticketid": log.TicketId,
"userid": log.User,
"username": log.Username,
"uuid": log.Uuid,
})
}
utils.Respond(ctx, template.TemplateLogs.Render(map[string]interface{}{
"name": store.Get("name").(string),
"guildId": guildIdStr, "guildId": guildIdStr,
"baseUrl": config.Conf.Server.BaseUrl,
"isPageOne": page == 1,
"previousPage": page - 1,
"nextPage": page + 1,
"logs": formattedLogs,
})) }))
} else { } else {
ctx.Redirect(302, "/login") ctx.Redirect(302, "/login")

View File

@ -3,6 +3,7 @@ package manage
import ( import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt"
"github.com/TicketsBot/GoPanel/app/http/template" "github.com/TicketsBot/GoPanel/app/http/template"
"github.com/TicketsBot/GoPanel/config" "github.com/TicketsBot/GoPanel/config"
"github.com/TicketsBot/GoPanel/database/table" "github.com/TicketsBot/GoPanel/database/table"
@ -24,14 +25,16 @@ func SettingsHandler(ctx *gin.Context) {
if utils.IsLoggedIn(store) { if utils.IsLoggedIn(store) {
userIdStr := store.Get("userid").(string) userIdStr := store.Get("userid").(string)
userId, err := utils.GetUserId(store); if err != nil { userId, err := utils.GetUserId(store)
if err != nil {
ctx.String(500, err.Error()) ctx.String(500, err.Error())
return return
} }
// Verify the guild exists // Verify the guild exists
guildIdStr := ctx.Param("id") guildIdStr := ctx.Param("id")
guildId, err := strconv.ParseInt(guildIdStr, 10, 64); if err != nil { guildId, err := strconv.ParseInt(guildIdStr, 10, 64)
if err != nil {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
return return
} }
@ -83,11 +86,8 @@ func SettingsHandler(ctx *gin.Context) {
table.UpdateTicketLimit(guildId, limit) 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 // /users/@me/guilds doesn't return channels, so we have to get them for the specific guild
if len(categories) == 0 { if len(guild.Channels) == 0 {
var channels []objects.Channel var channels []objects.Channel
endpoint := guildendpoint.GetGuildChannels(int(guildId)) endpoint := guildendpoint.GetGuildChannels(int(guildId))
err = endpoint.Request(store, nil, nil, &channels) err = endpoint.Request(store, nil, nil, &channels)
@ -96,7 +96,6 @@ func SettingsHandler(ctx *gin.Context) {
// Not in guild // Not in guild
} else { } else {
guild.Channels = channels guild.Channels = channels
categories = guild.GetCategories()
// Update cache of categories now that we have them // Update cache of categories now that we have them
guilds := table.GetGuilds(userIdStr) guilds := table.GetGuilds(userIdStr)
@ -117,7 +116,8 @@ func SettingsHandler(ctx *gin.Context) {
// Insert updated guild // Insert updated guild
guilds = utils.Insert(guilds, index, guild) guilds = utils.Insert(guilds, index, guild)
marshalled, err := json.Marshal(guilds); if err != nil { marshalled, err := json.Marshal(guilds)
if err != nil {
log.Error(err.Error()) log.Error(err.Error())
} else { } else {
table.UpdateGuilds(userIdStr, base64.StdEncoding.EncodeToString(marshalled)) table.UpdateGuilds(userIdStr, base64.StdEncoding.EncodeToString(marshalled))
@ -126,6 +126,10 @@ func SettingsHandler(ctx *gin.Context) {
} }
} }
// Get a list of actual category IDs
categories := guild.GetCategories()
// Convert to category IDs
var categoryIds []string var categoryIds []string
for _, c := range categories { for _, c := range categories {
categoryIds = append(categoryIds, c.Id) categoryIds = append(categoryIds, c.Id)
@ -149,19 +153,57 @@ func SettingsHandler(ctx *gin.Context) {
var formattedCategories []map[string]interface{} var formattedCategories []map[string]interface{}
for _, c := range categories { for _, c := range categories {
formattedCategories = append(formattedCategories, map[string]interface{}{ formattedCategories = append(formattedCategories, map[string]interface{}{
"categoryid": c.Id, "categoryid": c.Id,
"categoryname": c.Name, "categoryname": c.Name,
"active": c.Id == strconv.Itoa(int(category)), "active": c.Id == strconv.Itoa(int(category)),
}) })
} }
// Archive channel
// Create a list of IDs
var channelIds []string
for _, c := range guild.Channels {
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) {
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.Id == strconv.Itoa(int(archiveChannel)) {
fmt.Println(c.Name)
}
if c.Type == 0 {
formattedChannels = append(formattedChannels, map[string]interface{}{
"channelid": c.Id,
"channelname": c.Name,
"active": c.Id == strconv.Itoa(int(archiveChannel)),
})
}
}
utils.Respond(ctx, template.TemplateSettings.Render(map[string]interface{}{ utils.Respond(ctx, template.TemplateSettings.Render(map[string]interface{}{
"name": store.Get("name").(string), "name": store.Get("name").(string),
"guildId": guildIdStr, "guildId": guildIdStr,
"prefix": prefix, "prefix": prefix,
"welcomeMessage": welcomeMessage, "welcomeMessage": welcomeMessage,
"ticketLimit": limit, "ticketLimit": limit,
"categories": formattedCategories, "categories": formattedCategories,
"channels": formattedChannels,
})) }))
} else { } else {
ctx.Redirect(302, "/login") ctx.Redirect(302, "/login")

View File

@ -0,0 +1,84 @@
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"
"io/ioutil"
"net/http"
"strconv"
"time"
)
func LogViewHandler(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
}
uuid := ctx.Param("uuid")
cdnUrl := table.GetCdnUrl(guildId, uuid)
if cdnUrl == "" {
ctx.Redirect(302, fmt.Sprintf("/manage/%s/logs/page/1", guild.Id))
return
} else {
req, err := http.NewRequest("GET", cdnUrl, nil); if err != nil {
ctx.String(500, fmt.Sprintf("Failed to read log: %s", err.Error()))
return
}
client := &http.Client{}
client.Timeout = 3 * time.Second
res, err := client.Do(req); if err != nil {
ctx.String(500, fmt.Sprintf("Failed to read log: %s", err.Error()))
return
}
defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body); if err != nil {
ctx.String(500, fmt.Sprintf("Failed to read log: %s", err.Error()))
return
}
ctx.String(200, string(content))
}
}
}

View File

@ -15,22 +15,22 @@ import (
"time" "time"
) )
type( type (
TokenData struct { TokenData struct {
ClientId string `qs:"client_id"` ClientId string `qs:"client_id"`
ClientSecret string `qs:"client_secret"` ClientSecret string `qs:"client_secret"`
GrantType string `qs:"grant_type"` GrantType string `qs:"grant_type"`
Code string `qs:"code"` Code string `qs:"code"`
RedirectUri string `qs:"redirect_uri"` RedirectUri string `qs:"redirect_uri"`
Scope string `qs:"scope"` Scope string `qs:"scope"`
} }
TokenResponse struct { TokenResponse struct {
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
TokenType string `json:"token_type"` TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"` ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"` Scope string `json:"scope"`
} }
) )
@ -52,17 +52,19 @@ func CallbackHandler(ctx *gin.Context) {
return return
} }
res, err := discord.AccessToken(code); if err != nil { res, err := discord.AccessToken(code)
if err != nil {
ctx.String(500, err.Error()) ctx.String(500, err.Error())
} }
store.Set("access_token", res.AccessToken) store.Set("access_token", res.AccessToken)
store.Set("refresh_token", res.RefreshToken) store.Set("refresh_token", res.RefreshToken)
store.Set("expiry", (time.Now().UnixNano() / int64(time.Second)) + int64(res.ExpiresIn)) store.Set("expiry", (time.Now().UnixNano()/int64(time.Second))+int64(res.ExpiresIn))
// Get ID + name // Get ID + name
var currentUser objects.User var currentUser objects.User
err = user.CurrentUser.Request(store, nil, nil, &currentUser); if err != nil { err = user.CurrentUser.Request(store, nil, nil, &currentUser)
if err != nil {
ctx.String(500, err.Error()) ctx.String(500, err.Error())
return return
} }
@ -73,17 +75,19 @@ func CallbackHandler(ctx *gin.Context) {
log.Error(err.Error()) log.Error(err.Error())
} }
ctx.Redirect(302,config.Conf.Server.BaseUrl) ctx.Redirect(302, config.Conf.Server.BaseUrl)
// Cache guilds because Discord takes like 2 whole seconds to return then // Cache guilds because Discord takes like 2 whole seconds to return then
go func() { go func() {
var guilds []objects.Guild var guilds []objects.Guild
err = user.CurrentUserGuilds.Request(store, nil, nil, &guilds); if err != nil { err = user.CurrentUserGuilds.Request(store, nil, nil, &guilds)
if err != nil {
log.Error(err.Error()) log.Error(err.Error())
return return
} }
marshalled, err := json.Marshal(guilds); if err != nil { marshalled, err := json.Marshal(guilds)
if err != nil {
log.Error(err.Error()) log.Error(err.Error())
return return
} }

View File

@ -20,7 +20,8 @@ func IndexHandler(ctx *gin.Context) {
if utils.IsLoggedIn(store) { if utils.IsLoggedIn(store) {
userIdStr := store.Get("userid").(string) userIdStr := store.Get("userid").(string)
userId, err := utils.GetUserId(store); if err != nil { userId, err := utils.GetUserId(store)
if err != nil {
ctx.String(500, err.Error()) ctx.String(500, err.Error())
return return
} }
@ -28,7 +29,8 @@ func IndexHandler(ctx *gin.Context) {
adminGuilds := make([]objects.Guild, 0) adminGuilds := make([]objects.Guild, 0)
adminGuildIds := table.GetAdminGuilds(userId) adminGuildIds := table.GetAdminGuilds(userId)
for _, guild := range table.GetGuilds(userIdStr) { for _, guild := range table.GetGuilds(userIdStr) {
guildId, err := strconv.ParseInt(guild.Id, 10, 64); if err != nil { guildId, err := strconv.ParseInt(guild.Id, 10, 64)
if err != nil {
ctx.String(500, err.Error()) ctx.String(500, err.Error())
return return
} }
@ -41,7 +43,7 @@ func IndexHandler(ctx *gin.Context) {
var servers []map[string]string var servers []map[string]string
for _, server := range adminGuilds { for _, server := range adminGuilds {
element := map[string]string{ element := map[string]string{
"serverid": server.Id, "serverid": server.Id,
"servername": server.Name, "servername": server.Name,
} }
@ -49,13 +51,12 @@ func IndexHandler(ctx *gin.Context) {
} }
utils.Respond(ctx, template.TemplateIndex.Render(map[string]interface{}{ utils.Respond(ctx, template.TemplateIndex.Render(map[string]interface{}{
"name": store.Get("name").(string), "name": store.Get("name").(string),
"baseurl": config.Conf.Server.BaseUrl, "baseurl": config.Conf.Server.BaseUrl,
"servers": servers, "servers": servers,
"empty": len(servers) == 0, "empty": len(servers) == 0,
})) }))
} else { } else {
ctx.Redirect(302, "/login") ctx.Redirect(302, "/login")
} }
} }

View File

@ -53,6 +53,9 @@ func StartServer() {
// /manage/:id/logs/page/:page // /manage/:id/logs/page/:page
router.GET("/manage/:id/logs/page/:page", manage.LogsHandler) router.GET("/manage/:id/logs/page/:page", manage.LogsHandler)
// /manage/:id/logs/view/:uuid
router.GET("/manage/:id/logs/view/:uuid", manage.LogViewHandler)
if err := router.Run(config.Conf.Server.Host); err != nil { if err := router.Run(config.Conf.Server.Host); err != nil {
panic(err) panic(err)
} }

View File

@ -11,10 +11,10 @@ type Layout struct {
type Template struct { type Template struct {
compiled *mustache.Template compiled *mustache.Template
Layout Layout Layout Layout
} }
var( var (
LayoutMain Layout LayoutMain Layout
TemplateIndex Template TemplateIndex Template
@ -35,20 +35,21 @@ func LoadLayouts() {
func LoadTemplates() { func LoadTemplates() {
TemplateIndex = Template{ TemplateIndex = Template{
compiled: loadTemplate("index"), compiled: loadTemplate("index"),
Layout: LayoutMain, Layout: LayoutMain,
} }
TemplateLogs = Template{ TemplateLogs = Template{
compiled: loadTemplate("logs"), compiled: loadTemplate("logs"),
Layout: LayoutMain, Layout: LayoutMain,
} }
TemplateSettings = Template{ TemplateSettings = Template{
compiled: loadTemplate("settings"), compiled: loadTemplate("settings"),
Layout: LayoutMain, Layout: LayoutMain,
} }
} }
func loadLayout(name string) *mustache.Template { func loadLayout(name string) *mustache.Template {
tmpl, err := mustache.ParseFile(fmt.Sprintf("./public/templates/layouts/%s.mustache", name)); if err != nil { tmpl, err := mustache.ParseFile(fmt.Sprintf("./public/templates/layouts/%s.mustache", name))
if err != nil {
panic(err) panic(err)
} }
@ -56,7 +57,8 @@ func loadLayout(name string) *mustache.Template {
} }
func loadTemplate(name string) *mustache.Template { func loadTemplate(name string) *mustache.Template {
tmpl, err := mustache.ParseFile(fmt.Sprintf("./public/templates/views/%s.mustache", name)); if err != nil { tmpl, err := mustache.ParseFile(fmt.Sprintf("./public/templates/views/%s.mustache", name))
if err != nil {
panic(err) panic(err)
} }

View File

@ -5,46 +5,46 @@ import (
"io/ioutil" "io/ioutil"
) )
type( type (
Config struct { Config struct {
Server Server Server Server
Oauth Oauth Oauth Oauth
MariaDB MariaDB MariaDB MariaDB
Bot Bot Bot Bot
Redis Redis Redis Redis
} }
Server struct { Server struct {
Host string Host string
BaseUrl string BaseUrl string
MainSite string MainSite string
CsrfKey string CsrfKey string
Ratelimit Ratelimit Ratelimit Ratelimit
Session Session Session Session
} }
Ratelimit struct { Ratelimit struct {
Window int Window int
Max int Max int
} }
Session struct { Session struct {
Threads int Threads int
Secret string Secret string
} }
Oauth struct { Oauth struct {
Id int64 Id int64
Secret string Secret string
RedirectUri string RedirectUri string
} }
MariaDB struct { MariaDB struct {
Host string Host string
Username string Username string
Password string Password string
Database string Database string
Threads int Threads int
} }
Bot struct { Bot struct {
@ -52,22 +52,24 @@ type(
} }
Redis struct { Redis struct {
Host string Host string
Port int Port int
Password string Password string
} }
) )
var( var (
Conf Config Conf Config
) )
func LoadConfig() { func LoadConfig() {
raw, err := ioutil.ReadFile("config.toml"); if err != nil { raw, err := ioutil.ReadFile("config.toml")
if err != nil {
panic(err) panic(err)
} }
_, err = toml.Decode(string(raw), &Conf); if err != nil { _, err = toml.Decode(string(raw), &Conf)
if err != nil {
panic(err) panic(err)
} }
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
) )
var( var (
Database gorm.DB Database gorm.DB
) )
@ -18,9 +18,10 @@ func ConnectToDatabase() {
config.Conf.MariaDB.Password, config.Conf.MariaDB.Password,
config.Conf.MariaDB.Host, config.Conf.MariaDB.Host,
config.Conf.MariaDB.Database, config.Conf.MariaDB.Database,
) )
db, err := gorm.Open("mysql", uri); if err != nil { db, err := gorm.Open("mysql", uri)
if err != nil {
panic(err) panic(err)
} }

View File

@ -0,0 +1,29 @@
package table
import (
"fmt"
"github.com/TicketsBot/GoPanel/database"
)
type ArchiveChannel struct {
Guild int64 `gorm:"column:GUILDID"`
Channel int64 `gorm:"column:CHANNELID"`
}
func (ArchiveChannel) TableName() string {
return "archivechannel"
}
func UpdateArchiveChannel(guildId int64, channelId int64) {
fmt.Println(channelId)
var channel ArchiveChannel
database.Database.Where(ArchiveChannel{Guild: guildId}).Assign(ArchiveChannel{Channel: channelId}).FirstOrCreate(&channel)
}
func GetArchiveChannel(guildId int64) int64 {
var channel ArchiveChannel
database.Database.Where(&ArchiveChannel{Guild: guildId}).First(&channel)
return channel.Channel
}

View File

@ -5,7 +5,7 @@ import (
) )
type ChannelCategory struct { type ChannelCategory struct {
GuildId int64 `gorm:"column:GUILDID"` GuildId int64 `gorm:"column:GUILDID"`
Category int64 `gorm:"column:CATEGORYID"` Category int64 `gorm:"column:CATEGORYID"`
} }

View File

@ -24,7 +24,8 @@ func UpdateGuilds(userId string, guilds string) {
func GetGuilds(userId string) []objects.Guild { func GetGuilds(userId string) []objects.Guild {
var cache GuildCache var cache GuildCache
database.Database.Where(&GuildCache{UserId: userId}).First(&cache) database.Database.Where(&GuildCache{UserId: userId}).First(&cache)
decoded, err := base64.StdEncoding.DecodeString(cache.Guilds); if err != nil { decoded, err := base64.StdEncoding.DecodeString(cache.Guilds)
if err != nil {
return make([]objects.Guild, 0) return make([]objects.Guild, 0)
} }

View File

@ -3,10 +3,10 @@ package table
import "github.com/TicketsBot/GoPanel/database" import "github.com/TicketsBot/GoPanel/database"
type PermissionNode struct { type PermissionNode struct {
GuildId int64 `gorm:"column:GUILDID"` GuildId int64 `gorm:"column:GUILDID"`
UserId int64 `gorm:"column:USERID"` UserId int64 `gorm:"column:USERID"`
IsSupport bool `gorm:"column:ISSUPPORT"` IsSupport bool `gorm:"column:ISSUPPORT"`
IsAdmin bool `gorm:"column:ISADMIN"` IsAdmin bool `gorm:"column:ISADMIN"`
} }
func (PermissionNode) TableName() string { func (PermissionNode) TableName() string {

View File

@ -5,8 +5,8 @@ import (
) )
type Prefix struct { type Prefix struct {
GuildId int64 `gorm:"column:GUILDID"` GuildId int64 `gorm:"column:GUILDID"`
Prefix string `gorm:"column:PREFIX;type:varchar(8)"` Prefix string `gorm:"column:PREFIX;type:varchar(8)"`
} }
func (Prefix) TableName() string { func (Prefix) TableName() string {
@ -18,7 +18,7 @@ func UpdatePrefix(guildId int64, prefix string) {
} }
func GetPrefix(guildId int64) string { func GetPrefix(guildId int64) string {
prefix := Prefix{Prefix:"t!"} prefix := Prefix{Prefix: "t!"}
database.Database.Where(&Prefix{GuildId: guildId}).First(&prefix) database.Database.Where(&Prefix{GuildId: guildId}).First(&prefix)
return prefix.Prefix return prefix.Prefix

View File

@ -5,12 +5,12 @@ import (
) )
type TicketArchive struct { type TicketArchive struct {
Uuid string `gorm:"column:UUID;type:varchar(36)"` Uuid string `gorm:"column:UUID;type:varchar(36)"`
Guild int64 `gorm:"column:GUILDID"` Guild int64 `gorm:"column:GUILDID"`
User int64 `gorm:"column:USERID"` User int64 `gorm:"column:USERID"`
Username string `gorm:"column:USERNAME;type:varchar(32)"` Username string `gorm:"column:USERNAME;type:varchar(32)"`
TicketId int `gorm:"column:TICKETID"` TicketId int `gorm:"column:TICKETID"`
CdnUrl string `gorm:"column:CDNURL;type:varchar(100)"` CdnUrl string `gorm:"column:CDNURL;type:varchar(100)"`
} }
func (TicketArchive) TableName() string { func (TicketArchive) TableName() string {
@ -19,7 +19,7 @@ func (TicketArchive) TableName() string {
func GetTicketArchives(guildId int64) []TicketArchive { func GetTicketArchives(guildId int64) []TicketArchive {
var archives []TicketArchive var archives []TicketArchive
database.Database.Where(&TicketArchive{Guild: guildId}).Find(&archives) database.Database.Where(&TicketArchive{Guild: guildId}).Order("TICKETID desc").Find(&archives)
return archives return archives
} }
@ -38,7 +38,13 @@ func GetFilteredTicketArchives(guildId int64, userId int64, username string, tic
query = query.Where(&TicketArchive{TicketId: ticketId}) query = query.Where(&TicketArchive{TicketId: ticketId})
} }
query.Find(&archives) query.Order("TICKETID desc").Find(&archives)
return archives return archives
} }
func GetCdnUrl(guildId int64, uuid string) string {
var archive TicketArchive
database.Database.Where(&TicketArchive{Guild: guildId, Uuid: uuid}).First(&archive)
return archive.CdnUrl
}

View File

@ -6,7 +6,7 @@ import (
type TicketLimit struct { type TicketLimit struct {
GuildId int64 `gorm:"column:GUILDID"` GuildId int64 `gorm:"column:GUILDID"`
Limit int `gorm:"column:TICKETLIMIT"` Limit int `gorm:"column:TICKETLIMIT"`
} }
func (TicketLimit) TableName() string { func (TicketLimit) TableName() string {

View File

@ -5,7 +5,7 @@ import (
) )
type WelcomeMessage struct { type WelcomeMessage struct {
GuildId int64 `gorm:"column:GUILDID"` GuildId int64 `gorm:"column:GUILDID"`
Message string `gorm:"column:MESSAGE;type:text"` Message string `gorm:"column:MESSAGE;type:text"`
} }
@ -18,7 +18,7 @@ func UpdateWelcomeMessage(guildId int64, message string) {
} }
func GetWelcomeMessage(guildId int64) string { func GetWelcomeMessage(guildId int64) string {
message := WelcomeMessage{Message:"No message specified"} message := WelcomeMessage{Message: "No message specified"}
database.Database.Where(&WelcomeMessage{GuildId: guildId}).First(&message) database.Database.Where(&WelcomeMessage{GuildId: guildId}).First(&message)
return message.Message return message.Message

View File

@ -60,12 +60,11 @@
</thead> </thead>
<tbody> <tbody>
{{#logs}} {{#logs}}
{{{baseUrl}}}
<tr> <tr>
<td>{{TICKETID}}</td> <td>{{ticketid}}</td>
<td>{{USERNAME}}</td> <td>{{username}}</td>
<td>{{USERID}}</td> <td>{{userid}}</td>
<td><a href="{{baseUrl}}/logs/{{UUID}}">{{UUID}}</a></td> <td><a href="{{baseUrl}}/manage/{{guildId}}/logs/view/{{uuid}}">{{uuid}}</a></td>
</tr> </tr>
{{/logs}} {{/logs}}
</tbody> </tbody>

View File

@ -64,6 +64,22 @@
</div> </div>
</div> </div>
<div class="row">
<div class="input-field col s12">
<p><b>Archive Channel</b></p>
<select name="archivechannel">
{{#channels}}
{{#active}}
<option value="{{channelid}}" selected>#{{channelname}}</option>
{{/active}}
{{^active}}
<option value="{{channelid}}">#{{channelname}}</option>
{{/active}}
{{/channels}}
</select>
</div>
</div>
<div class="row"> <div class="row">
<div class="col s12 center-align"> <div class="col s12 center-align">
<button class="btn waves-effect waves-light indigo darken-1" type="submit" name="action">Save <button class="btn waves-effect waves-light indigo darken-1" type="submit" name="action">Save

View File

@ -11,31 +11,31 @@ import (
"time" "time"
) )
type( type (
TokenData struct { TokenData struct {
ClientId string `qs:"client_id"` ClientId string `qs:"client_id"`
ClientSecret string `qs:"client_secret"` ClientSecret string `qs:"client_secret"`
GrantType string `qs:"grant_type"` GrantType string `qs:"grant_type"`
Code string `qs:"code"` Code string `qs:"code"`
RedirectUri string `qs:"redirect_uri"` RedirectUri string `qs:"redirect_uri"`
Scope string `qs:"scope"` Scope string `qs:"scope"`
} }
RefreshData struct { RefreshData struct {
ClientId string `qs:"client_id"` ClientId string `qs:"client_id"`
ClientSecret string `qs:"client_secret"` ClientSecret string `qs:"client_secret"`
GrantType string `qs:"grant_type"` GrantType string `qs:"grant_type"`
RefreshToken string `qs:"refresh_token"` RefreshToken string `qs:"refresh_token"`
RedirectUri string `qs:"redirect_uri"` RedirectUri string `qs:"redirect_uri"`
Scope string `qs:"scope"` Scope string `qs:"scope"`
} }
TokenResponse struct { TokenResponse struct {
AccessToken string `json:"access_token"` AccessToken string `json:"access_token"`
TokenType string `json:"token_type"` TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"` ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"` RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"` Scope string `json:"scope"`
} }
) )
@ -43,15 +43,16 @@ const TokenEndpoint = "https://discordapp.com/api/oauth2/token"
func AccessToken(code string) (TokenResponse, error) { func AccessToken(code string) (TokenResponse, error) {
data := TokenData{ data := TokenData{
ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)), ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
ClientSecret: config.Conf.Oauth.Secret, ClientSecret: config.Conf.Oauth.Secret,
GrantType: "authorization_code", GrantType: "authorization_code",
Code: code, Code: code,
RedirectUri: config.Conf.Oauth.RedirectUri, RedirectUri: config.Conf.Oauth.RedirectUri,
Scope: "identify guilds", Scope: "identify guilds",
} }
res, err := tokenPost(data); if err != nil { res, err := tokenPost(data)
if err != nil {
return TokenResponse{}, err return TokenResponse{}, err
} }
@ -65,15 +66,16 @@ func AccessToken(code string) (TokenResponse, error) {
func RefreshToken(refreshToken string) (TokenResponse, error) { func RefreshToken(refreshToken string) (TokenResponse, error) {
data := RefreshData{ data := RefreshData{
ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)), ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
ClientSecret: config.Conf.Oauth.Secret, ClientSecret: config.Conf.Oauth.Secret,
GrantType: "refresh_token", GrantType: "refresh_token",
RefreshToken: refreshToken, RefreshToken: refreshToken,
RedirectUri: config.Conf.Oauth.RedirectUri, RedirectUri: config.Conf.Oauth.RedirectUri,
Scope: "identify guilds", Scope: "identify guilds",
} }
res, err := tokenPost(data); if err != nil { res, err := tokenPost(data)
if err != nil {
return TokenResponse{}, err return TokenResponse{}, err
} }
@ -86,12 +88,14 @@ func RefreshToken(refreshToken string) (TokenResponse, error) {
} }
func tokenPost(body ...interface{}) ([]byte, error) { func tokenPost(body ...interface{}) ([]byte, error) {
str, err := qs.Marshal(body[0]); if err != nil { str, err := qs.Marshal(body[0])
if err != nil {
return nil, err return nil, err
} }
encoded := []byte(str) encoded := []byte(str)
req, err := http.NewRequest("POST", TokenEndpoint, bytes.NewBuffer([]byte(encoded))); if err != nil { req, err := http.NewRequest("POST", TokenEndpoint, bytes.NewBuffer([]byte(encoded)))
if err != nil {
return nil, err return nil, err
} }
@ -100,12 +104,14 @@ func tokenPost(body ...interface{}) ([]byte, error) {
client := &http.Client{} client := &http.Client{}
client.Timeout = 3 * time.Second client.Timeout = 3 * time.Second
res, err := client.Do(req); if err != nil { res, err := client.Do(req)
if err != nil {
return nil, err return nil, err
} }
defer res.Body.Close() defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body); if err != nil { content, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err return nil, err
} }

View File

@ -16,24 +16,24 @@ type RequestType string
type ContentType string type ContentType string
type AuthorizationType string type AuthorizationType string
const( const (
GET RequestType = "GET" GET RequestType = "GET"
POST RequestType = "POST" POST RequestType = "POST"
PATCH RequestType = "PATCH" PATCH RequestType = "PATCH"
BEARER AuthorizationType = "Bearer" BEARER AuthorizationType = "Bearer"
BOT AuthorizationType = "BOT" BOT AuthorizationType = "BOT"
ApplicationJson ContentType = "application/json" ApplicationJson ContentType = "application/json"
ApplicationFormUrlEncoded ContentType = "application/x-www-form-urlencoded" ApplicationFormUrlEncoded ContentType = "application/x-www-form-urlencoded"
BASE_URL = "https://discordapp.com/api/v6" BASE_URL = "https://discordapp.com/api/v6"
) )
type Endpoint struct { type Endpoint struct {
RequestType RequestType RequestType RequestType
AuthorizationType AuthorizationType AuthorizationType AuthorizationType
Endpoint string Endpoint string
} }
func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, body interface{}, response interface{}) error { func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, body interface{}, response interface{}) error {
@ -48,12 +48,14 @@ func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, bod
// Encode body // Encode body
var encoded []byte var encoded []byte
if *contentType == ApplicationJson { if *contentType == ApplicationJson {
raw, err := json.Marshal(body); if err != nil { raw, err := json.Marshal(body)
if err != nil {
return err return err
} }
encoded = raw encoded = raw
} else if *contentType == ApplicationFormUrlEncoded { } else if *contentType == ApplicationFormUrlEncoded {
str, err := qs.Marshal(body); if err != nil { str, err := qs.Marshal(body)
if err != nil {
return err return err
} }
encoded = []byte(str) encoded = []byte(str)
@ -80,33 +82,38 @@ func (e *Endpoint) Request(store sessions.Session, contentType *ContentType, bod
// Check if needs refresh // Check if needs refresh
if (time.Now().UnixNano() / int64(time.Second)) > int64(expiry) { if (time.Now().UnixNano() / int64(time.Second)) > int64(expiry) {
res, err := RefreshToken(refreshToken); if err != nil { res, err := RefreshToken(refreshToken)
if err != nil {
store.Clear() store.Clear()
_ = store.Save() _ = store.Save()
return errors.New("Please login again!") return errors.New("Please login again!")
} }
store.Set("access_token", res.AccessToken) store.Set("access_token", res.AccessToken)
store.Set("expiry", (time.Now().UnixNano() / int64(time.Second)) + int64(res.ExpiresIn)) store.Set("expiry", (time.Now().UnixNano()/int64(time.Second))+int64(res.ExpiresIn))
store.Set("refresh_token", res.RefreshToken) store.Set("refresh_token", res.RefreshToken)
accessToken = res.AccessToken accessToken = res.AccessToken
} }
switch e.AuthorizationType{ switch e.AuthorizationType {
case BEARER: req.Header.Set("Authorization", "Bearer " + accessToken) case BEARER:
case BOT: req.Header.Set("Authorization", "Bot " + config.Conf.Bot.Token) req.Header.Set("Authorization", "Bearer "+accessToken)
case BOT:
req.Header.Set("Authorization", "Bot "+config.Conf.Bot.Token)
} }
client := &http.Client{} client := &http.Client{}
client.Timeout = 3 * time.Second client.Timeout = 3 * time.Second
res, err := client.Do(req); if err != nil { res, err := client.Do(req)
if err != nil {
return err return err
} }
defer res.Body.Close() defer res.Body.Close()
content, err := ioutil.ReadAll(res.Body); if err != nil { content, err := ioutil.ReadAll(res.Body)
if err != nil {
return err return err
} }

View File

@ -8,8 +8,8 @@ import (
func GetGuild(id int) discord.Endpoint { func GetGuild(id int) discord.Endpoint {
return discord.Endpoint{ return discord.Endpoint{
RequestType: discord.GET, RequestType: discord.GET,
AuthorizationType: discord.BOT, AuthorizationType: discord.BOT,
Endpoint: fmt.Sprintf("/guilds/%s", strconv.Itoa(id)), Endpoint: fmt.Sprintf("/guilds/%s", strconv.Itoa(id)),
} }
} }

View File

@ -7,8 +7,8 @@ import (
func GetGuildChannels(id int) discord.Endpoint { func GetGuildChannels(id int) discord.Endpoint {
return discord.Endpoint{ return discord.Endpoint{
RequestType: discord.GET, RequestType: discord.GET,
AuthorizationType: discord.BOT, AuthorizationType: discord.BOT,
Endpoint: fmt.Sprintf("/guilds/%d/channels", id), Endpoint: fmt.Sprintf("/guilds/%d/channels", id),
} }
} }

View File

@ -3,7 +3,7 @@ package user
import "github.com/TicketsBot/GoPanel/utils/discord" import "github.com/TicketsBot/GoPanel/utils/discord"
var CurrentUser = discord.Endpoint{ var CurrentUser = discord.Endpoint{
RequestType: discord.GET, RequestType: discord.GET,
AuthorizationType: discord.BEARER, AuthorizationType: discord.BEARER,
Endpoint: "/users/@me", Endpoint: "/users/@me",
} }

View File

@ -3,7 +3,7 @@ package user
import "github.com/TicketsBot/GoPanel/utils/discord" import "github.com/TicketsBot/GoPanel/utils/discord"
var CurrentUserGuilds = discord.Endpoint{ var CurrentUserGuilds = discord.Endpoint{
RequestType: discord.GET, RequestType: discord.GET,
AuthorizationType: discord.BEARER, AuthorizationType: discord.BEARER,
Endpoint: "/users/@me/guilds", Endpoint: "/users/@me/guilds",
} }

View File

@ -1,16 +1,16 @@
package objects package objects
type Activity struct { type Activity struct {
Name string Name string
Type int Type int
Url string Url string
Timestamps Timestamp Timestamps Timestamp
ApplicationId string ApplicationId string
Details string Details string
State string State string
Party Party Party Party
Assets Asset Assets Asset
Secrets Secret Secrets Secret
Instance bool Instance bool
Flags int Flags int
} }

View File

@ -2,7 +2,7 @@ package objects
type Asset struct { type Asset struct {
LargeImage string LargeImage string
LargeText string LargeText string
SmallImage string SmallImage string
SmallText string SmallText string
} }

View File

@ -1,22 +1,22 @@
package objects package objects
type Channel struct { type Channel struct {
Id string Id string
Type int Type int
GuildId string GuildId string
Position int Position int
PermissionsOverwrites []Overwrite PermissionsOverwrites []Overwrite
Name string Name string
Topic string Topic string
Nsfw bool Nsfw bool
LastMessageId string LastMessageId string
Bitrate int Bitrate int
userLimit int userLimit int
RateLimitPerUser int RateLimitPerUser int
Recipients []User Recipients []User
Icon string Icon string
Ownerid string Ownerid string
ApplicationId string ApplicationId string
ParentId string ParentId string
LastPinTimestamp string LastPinTimestamp string
} }

View File

@ -2,6 +2,6 @@ package objects
type ClientStatus struct { type ClientStatus struct {
Desktop string Desktop string
Mobile string Mobile string
Web string Web string
} }

View File

@ -1,11 +1,11 @@
package objects package objects
type Emoji struct { type Emoji struct {
Id string Id string
Name string Name string
Roles []string Roles []string
User User User User
RequireColons bool RequireColons bool
Managed bool Managed bool
Animated bool Animated bool
} }

View File

@ -1,42 +1,42 @@
package objects package objects
type Guild struct { type Guild struct {
Id string Id string
Name string Name string
Icon string Icon string
Splash string Splash string
Owner bool Owner bool
OwnerId string OwnerId string
Permissions int Permissions int
Region string Region string
AfkChannelid string AfkChannelid string
AfkTimeout int AfkTimeout int
EmbedEnabled bool EmbedEnabled bool
EmbedChannelId string EmbedChannelId string
VerificationLevel int VerificationLevel int
DefaultMessageNotifications int DefaultMessageNotifications int
ExplicitContentFilter int ExplicitContentFilter int
Roles []Role Roles []Role
Emojis []Emoji Emojis []Emoji
Features []string Features []string
MfaLevel int MfaLevel int
ApplicationId string ApplicationId string
WidgetEnabled bool WidgetEnabled bool
WidgetChannelId string WidgetChannelId string
SystemChannelId string SystemChannelId string
JoinedAt string JoinedAt string
Large bool Large bool
Unavailable bool Unavailable bool
MemberCount int MemberCount int
VoiceStates []VoiceState VoiceStates []VoiceState
Members []Member Members []Member
Channels []Channel Channels []Channel
Presences []Presence Presences []Presence
MaxPresences int MaxPresences int
Maxmembers int Maxmembers int
VanityUrlCode string VanityUrlCode string
Description string Description string
Banner string Banner string
} }
func (g *Guild) GetCategories() []Channel { func (g *Guild) GetCategories() []Channel {

View File

@ -1,10 +1,10 @@
package objects package objects
type Member struct { type Member struct {
User User User User
Nick string Nick string
Roles []string Roles []string
JoinedAt string JoinedAt string
Deaf bool Deaf bool
Mute bool Mute bool
} }

View File

@ -1,8 +1,8 @@
package objects package objects
type Overwrite struct { type Overwrite struct {
Id string Id string
Type string Type string
Allow int Allow int
Deny int Deny int
} }

View File

@ -1,6 +1,6 @@
package objects package objects
type Party struct { type Party struct {
Id string Id string
Size []int Size []int
} }

View File

@ -1,11 +1,11 @@
package objects package objects
type Presence struct { type Presence struct {
User User User User
Roles []string Roles []string
Game Activity Game Activity
GuildId string GuildId string
Status string Status string
Activities []Activity Activities []Activity
ClientStatus ClientStatus ClientStatus ClientStatus
} }

View File

@ -1,12 +1,12 @@
package objects package objects
type Role struct { type Role struct {
Id string Id string
Name string Name string
Color int Color int
Hoist bool Hoist bool
Position int Position int
Permissions int Permissions int
Managed bool Managed bool
Mentionable bool Mentionable bool
} }

View File

@ -1,7 +1,7 @@
package objects package objects
type Secret struct { type Secret struct {
Join string Join string
Spectate string Spectate string
Match string Match string
} }

View File

@ -2,5 +2,5 @@ package objects
type Timestamp struct { type Timestamp struct {
Start int Start int
End int End int
} }

View File

@ -1,12 +1,12 @@
package objects package objects
type User struct { type User struct {
Id string Id string
Username string Username string
Discriminator string Discriminator string
Avatar string Avatar string
Verified bool Verified bool
Email string Email string
Flags int Flags int
PremiumType int PremiumType int
} }

View File

@ -1,14 +1,14 @@
package objects package objects
type VoiceState struct { type VoiceState struct {
GuildId string GuildId string
ChannelId string ChannelId string
UserId string UserId string
Member Member Member Member
SessionId string SessionId string
Deaf bool Deaf bool
Mute bool Mute bool
SelfDeaf bool SelfDeaf bool
SelfMute bool SelfMute bool
Suppress bool Suppress bool
} }

View File

@ -3,7 +3,8 @@ package utils
import "io/ioutil" import "io/ioutil"
func ReadFile(path string) (string, error) { func ReadFile(path string) (string, error) {
content, err := ioutil.ReadFile(path); if err != nil { content, err := ioutil.ReadFile(path)
if err != nil {
return "", err return "", err
} }

View File

@ -22,7 +22,7 @@ func Contains(s interface{}, elem interface{}) bool {
return false return false
} }
func Insert(slice []objects.Guild, index int , value objects.Guild) []objects.Guild { func Insert(slice []objects.Guild, index int, value objects.Guild) []objects.Guild {
// Grow the slice by one element. // Grow the slice by one element.
slice = slice[0 : len(slice)+1] slice = slice[0 : len(slice)+1]
// Use copy to move the upper part of the slice out of the way and open a hole. // Use copy to move the upper part of the slice out of the way and open a hole.