Overhaul filters
This commit is contained in:
parent
2f2111d576
commit
2b355f42eb
@ -1,30 +1,14 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TicketsBot/GoPanel/botcontext"
|
||||
dbclient "github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/rpc/cache"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"math"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
pageLimit = 30
|
||||
)
|
||||
|
||||
type filterType uint8
|
||||
|
||||
const (
|
||||
filterTypeNone filterType = iota
|
||||
filterTypeTicketId
|
||||
filterTypeUsername
|
||||
filterTypeUserId
|
||||
)
|
||||
const pageLimit = 15
|
||||
|
||||
type transcript struct {
|
||||
TicketId int `json:"ticket_id"`
|
||||
@ -36,6 +20,24 @@ type transcript struct {
|
||||
func ListTranscripts(ctx *gin.Context) {
|
||||
guildId := ctx.Keys["guildid"].(uint64)
|
||||
|
||||
var queryOptions wrappedQueryOptions
|
||||
if err := ctx.BindJSON(&queryOptions); err != nil {
|
||||
ctx.JSON(400, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
opts, err := queryOptions.toQueryOptions(guildId)
|
||||
if err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
tickets, err := dbclient.Client.Tickets.GetByOptions(opts)
|
||||
if err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
botContext, err := botcontext.ContextForGuild(guildId)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(500, gin.H{
|
||||
@ -45,30 +47,6 @@ func ListTranscripts(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// db functions will handle if 0
|
||||
before, _ := strconv.Atoi(ctx.Query("before"))
|
||||
after, _ := strconv.Atoi(ctx.Query("after"))
|
||||
|
||||
var tickets []database.TicketWithCloseReason
|
||||
var status int
|
||||
|
||||
filterType := getFilterType(ctx)
|
||||
switch filterType {
|
||||
case filterTypeNone:
|
||||
tickets, status, err = getTickets(guildId, before, after)
|
||||
case filterTypeTicketId:
|
||||
tickets, status, err = getTicketsByTicketId(guildId, ctx)
|
||||
case filterTypeUsername:
|
||||
tickets, status, err = getTicketsByUsername(guildId, before, after, ctx)
|
||||
case filterTypeUserId:
|
||||
tickets, status, err = getTicketsByUserId(guildId, before, after, ctx)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(status, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
// Create a mapping user_id -> username so we can skip duplicates
|
||||
usernames := make(map[uint64]string)
|
||||
for _, ticket := range tickets {
|
||||
@ -102,164 +80,30 @@ func ListTranscripts(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
transcripts := make([]transcript, len(tickets))
|
||||
for i, ticket := range tickets {
|
||||
var rating *uint8
|
||||
if v, ok := ratings[ticket.Id]; ok {
|
||||
rating = &v
|
||||
// Get close reasons
|
||||
closeReasons, err := dbclient.Client.CloseReason.GetMulti(guildId, ticketIds)
|
||||
if err != nil {
|
||||
ctx.JSON(500, utils.ErrorJson(err))
|
||||
return
|
||||
}
|
||||
|
||||
transcripts[i] = transcript{
|
||||
transcripts := make([]transcript, len(tickets))
|
||||
for i, ticket := range tickets {
|
||||
transcript := transcript{
|
||||
TicketId: ticket.Id,
|
||||
Username: usernames[ticket.UserId],
|
||||
CloseReason: ticket.CloseReason,
|
||||
Rating: rating,
|
||||
}
|
||||
|
||||
if v, ok := ratings[ticket.Id]; ok {
|
||||
transcript.Rating = &v
|
||||
}
|
||||
|
||||
if v, ok := closeReasons[ticket.Id]; ok {
|
||||
transcript.CloseReason = &v
|
||||
}
|
||||
|
||||
transcripts[i] = transcript
|
||||
}
|
||||
|
||||
ctx.JSON(200, transcripts)
|
||||
}
|
||||
|
||||
func getFilterType(ctx *gin.Context) filterType {
|
||||
if ctx.Query("ticketid") != "" {
|
||||
return filterTypeTicketId
|
||||
} else if ctx.Query("username") != "" {
|
||||
return filterTypeUsername
|
||||
} else if ctx.Query("userid") != "" {
|
||||
return filterTypeUserId
|
||||
} else {
|
||||
return filterTypeNone
|
||||
}
|
||||
}
|
||||
|
||||
func getTickets(guildId uint64, before, after int) ([]database.TicketWithCloseReason, int, error) {
|
||||
var tickets []database.TicketWithCloseReason
|
||||
var err error
|
||||
|
||||
if before <= 0 && after <= 0 {
|
||||
tickets, err = dbclient.Client.Tickets.GetGuildClosedTicketsBeforeWithCloseReason(guildId, pageLimit, math.MaxInt32)
|
||||
} else if before > 0 {
|
||||
tickets, err = dbclient.Client.Tickets.GetGuildClosedTicketsBeforeWithCloseReason(guildId, pageLimit, before)
|
||||
} else { // after > 0
|
||||
// returns in ascending order, must reverse
|
||||
tickets, err = dbclient.Client.Tickets.GetGuildClosedTicketsAfterWithCloseReason(guildId, pageLimit, after)
|
||||
if err == nil {
|
||||
reverse(tickets)
|
||||
}
|
||||
}
|
||||
|
||||
status := http.StatusOK
|
||||
if err != nil {
|
||||
status = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
return tickets, status, err
|
||||
}
|
||||
|
||||
// (tickets, statusCode, error)
|
||||
func getTicketsByTicketId(guildId uint64, ctx *gin.Context) ([]database.TicketWithCloseReason, int, error) {
|
||||
ticketId, err := strconv.Atoi(ctx.Query("ticketid"))
|
||||
if err != nil {
|
||||
return nil, 400, err
|
||||
}
|
||||
|
||||
ticket, err := dbclient.Client.Tickets.Get(ticketId, guildId)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
if ticket.Id == 0 {
|
||||
return nil, http.StatusNotFound, errors.New("ticket not found")
|
||||
}
|
||||
|
||||
closeReason, ok, err := dbclient.Client.CloseReason.Get(guildId, ticketId)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
data := database.TicketWithCloseReason{
|
||||
Ticket: ticket,
|
||||
}
|
||||
|
||||
if ok {
|
||||
data.CloseReason = &closeReason
|
||||
}
|
||||
|
||||
return []database.TicketWithCloseReason{data}, http.StatusOK, nil
|
||||
}
|
||||
|
||||
// (tickets, statusCode, error)
|
||||
func getTicketsByUsername(guildId uint64, before, after int, ctx *gin.Context) ([]database.TicketWithCloseReason, int, error) {
|
||||
username := ctx.Query("username")
|
||||
|
||||
botContext, err := botcontext.ContextForGuild(guildId)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
members, err := botContext.SearchMembers(guildId, username)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
userIds := make([]uint64, len(members)) // capped at 100
|
||||
for i, member := range members {
|
||||
userIds[i] = member.User.Id
|
||||
}
|
||||
|
||||
var tickets []database.TicketWithCloseReason
|
||||
if before <= 0 && after <= 0 {
|
||||
tickets, err = dbclient.Client.Tickets.GetClosedByAnyBeforeWithCloseReason(guildId, userIds, math.MaxInt32, pageLimit)
|
||||
} else if before > 0 {
|
||||
tickets, err = dbclient.Client.Tickets.GetClosedByAnyBeforeWithCloseReason(guildId, userIds, before, pageLimit)
|
||||
} else { // after > 0
|
||||
// returns in ascending order, must reverse
|
||||
tickets, err = dbclient.Client.Tickets.GetClosedByAnyAfterWithCloseReason(guildId, userIds, after, pageLimit)
|
||||
if err == nil {
|
||||
reverse(tickets)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
return tickets, http.StatusOK, nil
|
||||
}
|
||||
|
||||
// (tickets, statusCode, error)
|
||||
func getTicketsByUserId(guildId uint64, before, after int, ctx *gin.Context) ([]database.TicketWithCloseReason, int, error) {
|
||||
userId, err := strconv.ParseUint(ctx.Query("userid"), 10, 64)
|
||||
if err != nil {
|
||||
return nil, 400, err
|
||||
}
|
||||
|
||||
var tickets []database.TicketWithCloseReason
|
||||
if before <= 0 && after <= 0 {
|
||||
tickets, err = dbclient.Client.Tickets.GetClosedByAnyBeforeWithCloseReason(guildId, []uint64{userId}, math.MaxInt32, pageLimit)
|
||||
} else if before > 0 {
|
||||
tickets, err = dbclient.Client.Tickets.GetClosedByAnyBeforeWithCloseReason(guildId, []uint64{userId}, before, pageLimit)
|
||||
} else { // after > 0
|
||||
// returns in ascending order, must reverse
|
||||
tickets, err = dbclient.Client.Tickets.GetClosedByAnyAfterWithCloseReason(guildId, []uint64{userId}, after, pageLimit)
|
||||
if err == nil {
|
||||
reverse(tickets)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
return tickets, http.StatusOK, nil
|
||||
}
|
||||
|
||||
func reverse(slice []database.TicketWithCloseReason) {
|
||||
if len(slice) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
}
|
||||
|
74
app/http/endpoints/api/transcripts/queryoptions.go
Normal file
74
app/http/endpoints/api/transcripts/queryoptions.go
Normal file
@ -0,0 +1,74 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/TicketsBot/GoPanel/botcontext"
|
||||
"github.com/TicketsBot/database"
|
||||
"github.com/rxdn/gdl/utils"
|
||||
)
|
||||
|
||||
type wrappedQueryOptions struct {
|
||||
Id int `json:"id,string"`
|
||||
Username string `json:"username"`
|
||||
UserId uint64 `json:"user_id,string"`
|
||||
Page int `json:"page"`
|
||||
}
|
||||
|
||||
func (o *wrappedQueryOptions) toQueryOptions(guildId uint64) (database.TicketQueryOptions, error) {
|
||||
var userIds []uint64
|
||||
if len(o.Username) > 0 {
|
||||
var err error
|
||||
userIds, err = usernameToIds(guildId, o.Username)
|
||||
if err != nil {
|
||||
return database.TicketQueryOptions{}, err
|
||||
}
|
||||
|
||||
// TODO: Do this better
|
||||
if len(userIds) == 0 {
|
||||
return database.TicketQueryOptions{}, errors.New("User not found")
|
||||
}
|
||||
}
|
||||
|
||||
if o.UserId != 0 {
|
||||
userIds = append(userIds, o.UserId)
|
||||
}
|
||||
|
||||
var offset int
|
||||
if o.Page > 1 {
|
||||
offset = pageLimit * (o.Page - 1)
|
||||
}
|
||||
|
||||
opts := database.TicketQueryOptions{
|
||||
Id: o.Id,
|
||||
GuildId: guildId,
|
||||
UserIds: userIds,
|
||||
Open: utils.BoolPtr(false),
|
||||
Order: database.OrderTypeDescending,
|
||||
Limit: pageLimit,
|
||||
Offset: offset,
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
func usernameToIds(guildId uint64, username string) ([]uint64, error) {
|
||||
if len(username) > 32 {
|
||||
return nil, errors.New("username too long")
|
||||
}
|
||||
|
||||
botContext, err := botcontext.ContextForGuild(guildId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
members, err := botContext.SearchMembers(guildId, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userIds := make([]uint64, len(members)) // capped at 100
|
||||
for i, member := range members {
|
||||
userIds[i] = member.User.Id
|
||||
}
|
||||
|
||||
return userIds, nil
|
||||
}
|
@ -99,7 +99,7 @@
|
||||
let filterSettings = {};
|
||||
let transcripts = [];
|
||||
|
||||
const pageLimit = 30;
|
||||
const pageLimit = 15;
|
||||
let page = 1;
|
||||
|
||||
let handleInputTicketId = () => {
|
||||
@ -122,10 +122,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
let paginationSettings = {
|
||||
after: transcripts[0].ticket_id,
|
||||
};
|
||||
|
||||
let paginationSettings = buildPaginationSettings(page - 1);
|
||||
if (await loadData(paginationSettings)) {
|
||||
page--;
|
||||
}
|
||||
@ -136,42 +134,25 @@
|
||||
return;
|
||||
}
|
||||
|
||||
let paginationSettings = {
|
||||
before: transcripts[transcripts.length - 1].ticket_id,
|
||||
};
|
||||
|
||||
let paginationSettings = buildPaginationSettings(page + 1);
|
||||
if (await loadData(paginationSettings)) {
|
||||
page++;
|
||||
}
|
||||
}
|
||||
|
||||
function buildQuery(paginationSettings) {
|
||||
let query = new URLSearchParams();
|
||||
if (paginationSettings['before'] !== undefined) {
|
||||
query.append('before', paginationSettings['before']);
|
||||
}
|
||||
|
||||
if (paginationSettings['after'] !== undefined) {
|
||||
query.append('after', paginationSettings['after']);
|
||||
}
|
||||
|
||||
if (filterSettings['ticketId'] !== undefined) {
|
||||
query.append('ticketid', filterSettings.ticketId);
|
||||
}
|
||||
|
||||
if (filterSettings['username'] !== undefined) {
|
||||
query.append('username', filterSettings.username);
|
||||
}
|
||||
|
||||
if (filterSettings['userId'] !== undefined) {
|
||||
query.append('userid', filterSettings.userId);
|
||||
}
|
||||
|
||||
return query;
|
||||
function buildPaginationSettings(page) {
|
||||
// Undefined fields won't be included in the JSON
|
||||
return {
|
||||
id: filterSettings.ticketId,
|
||||
username: filterSettings.username,
|
||||
user_id: filterSettings.userId,
|
||||
page: page,
|
||||
};
|
||||
}
|
||||
|
||||
async function filter() {
|
||||
await loadData({});
|
||||
let opts = buildPaginationSettings(1);
|
||||
await loadData(opts);
|
||||
page = 1;
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -6,7 +6,7 @@ require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/TicketsBot/archiverclient v0.0.0-20210220155137-a562b2f1bbbb
|
||||
github.com/TicketsBot/common v0.0.0-20210727134627-35eb7ed03a44
|
||||
github.com/TicketsBot/database v0.0.0-20210809170854-748ae1fff443
|
||||
github.com/TicketsBot/database v0.0.0-20210816195201-90c765ca95c8
|
||||
github.com/TicketsBot/worker v0.0.0-20210727130432-3df3cd1246a3
|
||||
github.com/apex/log v1.1.2
|
||||
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
|
||||
|
Loading…
x
Reference in New Issue
Block a user