New logging

This commit is contained in:
Dot-Rar 2020-04-17 19:07:19 +01:00
parent 0c79deb2ad
commit ec67702406
12 changed files with 307 additions and 216 deletions

View File

@ -1,102 +0,0 @@
package manage
import (
"github.com/TicketsBot/GoPanel/config"
"github.com/TicketsBot/GoPanel/database/table"
"github.com/TicketsBot/GoPanel/rpc/cache"
"github.com/TicketsBot/GoPanel/utils"
"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) {
userId := utils.GetUserId(store)
// Verify the guild exists
guildIdStr := ctx.Param("id")
guildId, err := strconv.ParseUint(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
guild, _ := cache.Instance.GetGuild(guildId, false)
// Verify the user has permissions to be here
isAdmin := make(chan bool)
go utils.IsAdmin(guild, userId, isAdmin)
if !<-isAdmin {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
return
}
pageLimit := 30
// Get logs
// Get user ID from URL
var filteredUserId uint64
if utils.IsInt(ctx.Query("userid")) {
filteredUserId, _ = strconv.ParseUint(ctx.Query("userid"), 10, 64)
}
// Get ticket ID from URL
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,
})
}
ctx.HTML(200, "manage/logs",gin.H{
"name": store.Get("name").(string),
"guildId": guildIdStr,
"avatar": store.Get("avatar").(string),
"baseUrl": config.Conf.Server.BaseUrl,
"isPageOne": page == 1,
"previousPage": page - 1,
"nextPage": page + 1,
"logs": formattedLogs,
"page": page,
})
} else {
ctx.Redirect(302, "/login")
}
}

View File

@ -0,0 +1,153 @@
package manage
import (
"context"
"github.com/TicketsBot/GoPanel/config"
"github.com/TicketsBot/GoPanel/database/table"
"github.com/TicketsBot/GoPanel/rpc/cache"
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
"github.com/TicketsBot/GoPanel/utils"
"github.com/apex/log"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/rest"
"strconv"
)
func LogsHandler(ctx *gin.Context) {
store := sessions.Default(ctx)
if store == nil {
return
}
defer store.Save()
if utils.IsLoggedIn(store) {
userId := utils.GetUserId(store)
// Verify the guild exists
guildIdStr := ctx.Param("id")
guildId, err := strconv.ParseUint(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
guild, _ := cache.Instance.GetGuild(guildId, false)
// Verify the user has permissions to be here
isAdmin := make(chan bool)
go utils.IsAdmin(guild, userId, isAdmin)
if !<-isAdmin {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
return
}
pageLimit := 30
// Get ticket ID from URL
var ticketId int
if utils.IsInt(ctx.Query("ticketid")) {
ticketId, _ = strconv.Atoi(ctx.Query("ticketid"))
}
var tickets []table.Ticket
// Get tickets from DB
if ticketId > 0 {
ticketChan := make(chan table.Ticket)
go table.GetTicketById(guildId, ticketId, ticketChan)
ticket := <-ticketChan
if ticket.Uuid != "" && !ticket.IsOpen {
tickets = append(tickets, ticket)
}
} else {
// make slice of user IDs to filter by
filteredIds := make([]uint64, 0)
// Add userid param to slice
filteredUserId, _ := strconv.ParseUint(ctx.Query("userid"), 10, 64)
if filteredUserId != 0 {
filteredIds = append(filteredIds, filteredUserId)
}
// Get username from URL
if username := ctx.Query("username"); username != "" {
// username -> user id
rows, err := cache.Instance.PgCache.Query(context.Background(), `select users.user_id from users where "data"->>'Username'=$1 and exists(SELECT FROM members where members.guild_id=$2);`, username, guildId)
defer rows.Close()
if err != nil {
log.Error(err.Error())
return
}
for rows.Next() {
var filteredId uint64
if err := rows.Scan(&filteredId); err != nil {
continue
}
if filteredId != 0 {
filteredIds = append(filteredIds, filteredId)
}
}
}
if ctx.Query("userid") != "" || ctx.Query("username") != "" {
tickets = table.GetClosedTicketsByUserId(guildId, filteredIds)
} else {
tickets = table.GetClosedTickets(guildId)
}
}
// Select 30 logs + format them
var formattedLogs []map[string]interface{}
for i := (page - 1) * pageLimit; i < (page - 1) * pageLimit + pageLimit; i++ {
if i >= len(tickets) {
break
}
ticket := tickets[i]
// get username
user, found := cache.Instance.GetUser(ticket.Owner)
if !found {
user, err = rest.GetUser(config.Conf.Bot.Token, ratelimit.Ratelimiter, ticket.Owner)
if err != nil {
log.Error(err.Error())
}
go cache.Instance.StoreUser(user)
}
formattedLogs = append(formattedLogs, map[string]interface{}{
"ticketid": ticket.TicketId,
"userid": ticket.Owner,
"username": user.Username,
})
}
ctx.HTML(200, "manage/logs",gin.H{
"name": store.Get("name").(string),
"guildId": guildIdStr,
"avatar": store.Get("avatar").(string),
"baseUrl": config.Conf.Server.BaseUrl,
"isPageOne": page == 1,
"previousPage": page - 1,
"nextPage": page + 1,
"logs": formattedLogs,
"page": page,
})
} else {
ctx.Redirect(302, "/login")
}
}

View File

@ -0,0 +1,86 @@
package manage
import (
"errors"
"fmt"
"github.com/TicketsBot/GoPanel/config"
"github.com/TicketsBot/GoPanel/database/table"
"github.com/TicketsBot/GoPanel/rpc/cache"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/archiverclient"
"github.com/gin-gonic/contrib/sessions"
"github.com/gin-gonic/gin"
"strconv"
)
var Archiver archiverclient.ArchiverClient
func LogViewHandler(ctx *gin.Context) {
store := sessions.Default(ctx)
if store == nil {
return
}
defer store.Save()
if utils.IsLoggedIn(store) {
userId := utils.GetUserId(store)
// Verify the guild exists
guildId, err := strconv.ParseUint(ctx.Param("id"), 10, 64)
if err != nil {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
return
}
// Get object for selected guild
guild, _ := cache.Instance.GetGuild(guildId, false)
// format ticket ID
ticketId, err := strconv.Atoi(ctx.Param("ticket")); if err != nil {
ctx.Redirect(302, fmt.Sprintf("/manage/%d/logs/page/1", guild.Id))
return
}
// get ticket object
ticketChan := make(chan table.Ticket)
go table.GetTicketById(guildId, ticketId, ticketChan)
ticket := <-ticketChan
// Verify this is a valid ticket and it is closed
if ticket.Uuid == "" || ticket.IsOpen {
ctx.Redirect(302, fmt.Sprintf("/manage/%d/logs/page/1", guild.Id))
return
}
// Verify the user has permissions to be here
isAdmin := make(chan bool)
go utils.IsAdmin(guild, userId, isAdmin)
if !<-isAdmin && ticket.Owner != userId {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
return
}
// retrieve ticket messages from bucket
messages, err := Archiver.Get(guildId, ticketId)
if err != nil {
if errors.Is(err, archiverclient.ErrExpired) {
ctx.String(200, "Archives expired: Purchase premium for permanent log storage") // TODO: Actual error page
return
}
ctx.String(500, fmt.Sprintf("Failed to archives - please contact the developers: %s", err.Error()))
return
}
// format to html
html, err := Archiver.Encode(messages, ticketId)
if err != nil {
ctx.String(500, fmt.Sprintf("Failed to archives - please contact the developers: %s", err.Error()))
return
}
ctx.Data(200, gin.MIMEHTML, html)
} else {
ctx.Redirect(302, fmt.Sprintf("/login?noguilds&state=viewlog.%s.%s", ctx.Param("id"), ctx.Param("ticket")))
}
}

View File

@ -1,79 +0,0 @@
package manage
import (
"fmt"
"github.com/TicketsBot/GoPanel/config"
"github.com/TicketsBot/GoPanel/database/table"
"github.com/TicketsBot/GoPanel/rpc/cache"
"github.com/TicketsBot/GoPanel/utils"
"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) {
userId := utils.GetUserId(store)
// Verify the guild exists
guildIdStr := ctx.Param("id")
guildId, err := strconv.ParseUint(guildIdStr, 10, 64)
if err != nil {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
return
}
// Get object for selected guild
guild, _ := cache.Instance.GetGuild(guildId, false)
// Verify the user has permissions to be here
isAdmin := make(chan bool)
go utils.IsAdmin(guild, userId, isAdmin)
if !<-isAdmin {
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
return
}
uuid := ctx.Param("uuid")
// Doesn't need guild = ticket.guild check, since we select where uuid=uuid and guild=guild
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))
}
} else {
ctx.Redirect(302, "/login")
}
}

View File

@ -14,6 +14,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/rxdn/gdl/objects/guild"
"github.com/rxdn/gdl/objects/user"
"strings"
"time"
)
@ -48,8 +49,8 @@ func CallbackHandler(ctx *gin.Context) {
return
}
code := ctx.DefaultQuery("code", "")
if code == "" {
code, ok := ctx.GetQuery("code")
if !ok {
ctx.String(400, "Discord provided an invalid Oauth2 code")
return
}
@ -80,7 +81,7 @@ func CallbackHandler(ctx *gin.Context) {
log.Error(err.Error())
}
ctx.Redirect(302, config.Conf.Server.BaseUrl)
handleRedirect(ctx)
// Cache guilds because Discord takes like 2 whole seconds to return then
go func() {
@ -110,3 +111,13 @@ func CallbackHandler(ctx *gin.Context) {
table.UpdateGuilds(currentUser.Id, base64.StdEncoding.EncodeToString(marshalled))
}()
}
func handleRedirect(ctx *gin.Context) {
state := strings.Split(ctx.Query("state"), ".")
if len(state) == 3 && state[0] == "viewlog" {
ctx.Redirect(302, fmt.Sprintf("%s/manage/%s/logs/view/%s", config.Conf.Server.BaseUrl, state[1], state[2]))
} else {
ctx.Redirect(302, config.Conf.Server.BaseUrl)
}
}

View File

@ -20,6 +20,12 @@ func LoginHandler(ctx *gin.Context) {
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))
var guildsScope string
if _, noGuilds := ctx.GetQuery("noguilds"); !noGuilds {
guildsScope = "+guilds"
}
ctx.Redirect(302, fmt.Sprintf("https://discordapp.com/oauth2/authorize?response_type=code&redirect_uri=%s&scope=identify%s&client_id=%d&state=%s", redirect, guildsScope, config.Conf.Oauth.Id, ctx.Query("state")))
}
}

View File

@ -44,7 +44,7 @@ func StartServer() {
router.POST("/manage/:id/settings", manage.UpdateSettingsHandler)
router.GET("/manage/:id/logs/page/:page", manage.LogsHandler)
router.GET("/manage/:id/logs/view/:uuid", manage.LogViewHandler)
router.GET("/manage/:id/logs/view/:ticket", manage.LogViewHandler)
router.GET("/manage/:id/blacklist", manage.BlacklistHandler)
router.GET("/manage/:id/blacklist/remove/:user", manage.BlacklistRemoveHandler)

View File

@ -12,6 +12,7 @@ import (
"github.com/TicketsBot/GoPanel/rpc/cache"
"github.com/TicketsBot/GoPanel/rpc/ratelimit"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/archiverclient"
"github.com/apex/log"
gdlratelimit "github.com/rxdn/gdl/rest/ratelimit"
"math/rand"
@ -32,12 +33,14 @@ func main() {
database.ConnectToDatabase()
cache.Instance = cache.NewCache()
manage.Archiver = archiverclient.NewArchiverClient(config.Conf.Bot.ObjectStore)
utils.LoadEmoji()
messagequeue.Client = messagequeue.NewRedisClient()
go Listen(messagequeue.Client)
ratelimit.Ratelimiter = gdlratelimit.NewRateLimiter(gdlratelimit.NewRedisStore(messagequeue.Client.Client, "ratelimit")) // TODO: Use values from config
ratelimit.Ratelimiter = gdlratelimit.NewRateLimiter(gdlratelimit.NewRedisStore(messagequeue.Client.Client, "ratelimit"), 1) // TODO: Use values from config
http.StartServer()
}

View File

@ -52,6 +52,7 @@ type (
Token string
PremiumLookupProxyUrl string `toml:"premium-lookup-proxy-url"`
PremiumLookupProxyKey string `toml:"premium-lookup-proxy-key"`
ObjectStore string
}
Redis struct {

View File

@ -23,6 +23,18 @@ func GetTickets(guild uint64) []Ticket {
return tickets
}
func GetClosedTickets(guildId uint64) []Ticket {
var tickets []Ticket
database.Database.Where(&Ticket{Guild: guildId, IsOpen: false}).Order("ID asc").Find(&tickets)
return tickets
}
func GetClosedTicketsByUserId(guildId uint64, userIds []uint64) []Ticket {
var tickets []Ticket
database.Database.Where(&Ticket{Guild: guildId, IsOpen: false}).Where("OWNERID IN (?)", userIds).Order("ID asc").Find(&tickets)
return tickets
}
func GetOpenTickets(guild uint64) []Ticket {
var tickets []Ticket
database.Database.Where(&Ticket{Guild: guild, IsOpen: true}).Order("ID asc").Find(&tickets)

4
go.mod
View File

@ -4,6 +4,7 @@ go 1.14
require (
github.com/BurntSushi/toml v0.3.1
github.com/TicketsBot/archiverclient v0.0.0-20200417174514-cf009e9a2547
github.com/apex/log v1.1.2
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
github.com/gin-contrib/multitemplate v0.0.0-20200226145339-3e397ee01bc6
@ -19,6 +20,5 @@ require (
github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c
github.com/pkg/errors v0.9.1
github.com/robfig/go-cache v0.0.0-20130306151617-9fc39e0dbf62
github.com/rxdn/gdl v0.0.0-20200410134146-c1b0871088c5
github.com/vmihailenco/msgpack v4.0.4+incompatible
github.com/rxdn/gdl v0.0.0-20200417164852-76b2d3c847c1
)

View File

@ -70,7 +70,7 @@
<td>{{.ticketid}}</td>
<td>{{.username}}</td>
<td>{{.userid}}</td>
<td><a href="/manage/{{$.guildId}}/logs/view/{{.uuid}}">{{.uuid}}</a></td>
<td><a href="/manage/{{$.guildId}}/logs/view/{{.ticketid}}">View</a></td>
</tr>
{{end}}
</tbody>