583 lines
13 KiB
Go
583 lines
13 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/TicketsBot/GoPanel/botcontext"
|
|
dbclient "github.com/TicketsBot/GoPanel/database"
|
|
"github.com/TicketsBot/GoPanel/utils"
|
|
"github.com/TicketsBot/GoPanel/utils/types"
|
|
"github.com/TicketsBot/database"
|
|
v2 "github.com/TicketsBot/logarchiver/pkg/model/v2"
|
|
"github.com/TicketsBot/worker/bot/customisation"
|
|
"github.com/gin-gonic/gin"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
var activeColours = []customisation.Colour{customisation.Green, customisation.Red}
|
|
|
|
func ExportHandler(ctx *gin.Context) {
|
|
guildId, selfId := ctx.Keys["guildid"].(uint64), ctx.Keys["userid"].(uint64)
|
|
|
|
botCtx, err := botcontext.ContextForGuild(guildId)
|
|
if err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
guild, err := botCtx.GetGuild(context.Background(), guildId)
|
|
if err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
if guild.OwnerId != selfId {
|
|
ctx.JSON(403, utils.ErrorStr("Only the server owner export server data"))
|
|
return
|
|
}
|
|
|
|
settings := getSettings(ctx, guildId)
|
|
|
|
multiPanels, err := dbclient.Client.MultiPanels.GetByGuild(ctx, guildId)
|
|
if err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
multiPanelData := make([]MultiPanel, len(multiPanels))
|
|
|
|
group, _ := errgroup.WithContext(context.Background())
|
|
|
|
var dbTickets []database.Ticket
|
|
|
|
// ticket list
|
|
group.Go(func() (err error) {
|
|
dbTickets, err = dbclient.Client.Tickets.GetByOptions(ctx, database.TicketQueryOptions{
|
|
GuildId: guildId,
|
|
})
|
|
|
|
return
|
|
})
|
|
|
|
for i := range multiPanels {
|
|
i := i
|
|
multiPanel := multiPanels[i]
|
|
|
|
multiPanelData[i] = MultiPanel{
|
|
MultiPanel: multiPanel,
|
|
}
|
|
|
|
group.Go(func() error {
|
|
panels, err := dbclient.Client.MultiPanelTargets.GetPanels(ctx, multiPanel.Id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
panelIds := make([]int, len(panels))
|
|
for i, panel := range panels {
|
|
panelIds[i] = panel.PanelId
|
|
}
|
|
|
|
multiPanelData[i].Panels = panelIds
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
var dbPanels []database.PanelWithWelcomeMessage
|
|
var panelACLs map[int][]database.PanelAccessControlRule
|
|
var panelFields map[int][]database.EmbedField
|
|
// panels
|
|
group.Go(func() (err error) {
|
|
dbPanels, err = dbclient.Client.Panel.GetByGuildWithWelcomeMessage(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// access control lists
|
|
group.Go(func() (err error) {
|
|
panelACLs, err = dbclient.Client.PanelAccessControlRules.GetAllForGuild(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// all fields
|
|
group.Go(func() (err error) {
|
|
panelFields, err = dbclient.Client.EmbedFields.GetAllFieldsForPanels(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
if err := group.Wait(); err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
// ratings
|
|
ticketIds := make([]int, len(dbTickets))
|
|
for i, ticket := range dbTickets {
|
|
ticketIds[i] = ticket.Id
|
|
}
|
|
|
|
ticketGroup, _ := errgroup.WithContext(context.Background())
|
|
|
|
var (
|
|
ratings map[int]uint8
|
|
closeReasons map[int]database.CloseMetadata
|
|
tickets = make([]Ticket, len(dbTickets))
|
|
)
|
|
|
|
ticketGroup.Go(func() (err error) {
|
|
ratings, err = dbclient.Client.ServiceRatings.GetMulti(ctx, guildId, ticketIds)
|
|
return
|
|
})
|
|
|
|
ticketGroup.Go(func() (err error) {
|
|
closeReasons, err = dbclient.Client.CloseReason.GetMulti(ctx, guildId, ticketIds)
|
|
return
|
|
})
|
|
|
|
if err := ticketGroup.Wait(); err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
transcriptGroup, _ := errgroup.WithContext(context.Background())
|
|
|
|
for i := range dbTickets {
|
|
ticket := dbTickets[i]
|
|
|
|
transcriptGroup.Go(func() (err error) {
|
|
var transcriptMessages v2.Transcript
|
|
transcriptMessages, err = utils.ArchiverClient.Get(ctx, guildId, ticket.Id)
|
|
if err != nil {
|
|
if err.Error() == "Transcript not found" {
|
|
err = nil
|
|
}
|
|
return
|
|
}
|
|
|
|
transcript := Ticket{
|
|
TicketId: ticket.Id,
|
|
Transcript: transcriptMessages,
|
|
}
|
|
|
|
if v, ok := ratings[ticket.Id]; ok {
|
|
transcript.Rating = &v
|
|
}
|
|
|
|
if v, ok := closeReasons[ticket.Id]; ok {
|
|
transcript.CloseReason = v.Reason
|
|
transcript.ClosedBy = v.ClosedBy
|
|
}
|
|
|
|
tickets[i] = transcript
|
|
|
|
return
|
|
})
|
|
|
|
}
|
|
|
|
if err := transcriptGroup.Wait(); err != nil {
|
|
fmt.Println(err)
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
panels := make([]Panel, len(dbPanels))
|
|
|
|
panelGroup, _ := errgroup.WithContext(context.Background())
|
|
|
|
for i, p := range dbPanels {
|
|
i := i
|
|
p := p
|
|
|
|
panelGroup.Go(func() error {
|
|
var mentions []string
|
|
|
|
// get if we should mention the ticket opener
|
|
shouldMention, err := dbclient.Client.PanelUserMention.ShouldMentionUser(ctx, p.PanelId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if shouldMention {
|
|
mentions = append(mentions, "user")
|
|
}
|
|
|
|
// get role mentions
|
|
roles, err := dbclient.Client.PanelRoleMentions.GetRoles(ctx, p.PanelId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// convert to strings
|
|
for _, roleId := range roles {
|
|
mentions = append(mentions, strconv.FormatUint(roleId, 10))
|
|
}
|
|
|
|
teams, err := dbclient.Client.PanelTeams.GetTeamIds(ctx, p.PanelId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if teams == nil {
|
|
teams = make([]int, 0)
|
|
}
|
|
|
|
var welcomeMessage *types.CustomEmbed
|
|
if p.WelcomeMessage != nil {
|
|
fields := panelFields[p.WelcomeMessage.Id]
|
|
welcomeMessage = types.NewCustomEmbed(p.WelcomeMessage, fields)
|
|
}
|
|
|
|
acl := panelACLs[p.PanelId]
|
|
if acl == nil {
|
|
acl = make([]database.PanelAccessControlRule, 0)
|
|
}
|
|
|
|
panels[i] = Panel{
|
|
Panel: p.Panel,
|
|
WelcomeMessage: welcomeMessage,
|
|
UseCustomEmoji: p.EmojiId != nil,
|
|
Emoji: types.NewEmoji(p.EmojiName, p.EmojiId),
|
|
Mentions: mentions,
|
|
Teams: teams,
|
|
UseServerDefaultNamingScheme: p.NamingScheme == nil,
|
|
AccessControlList: acl,
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
}
|
|
|
|
if err := panelGroup.Wait(); err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
var (
|
|
tags []Tag
|
|
blacklist *Blacklist
|
|
)
|
|
|
|
itemGroup, _ := errgroup.WithContext(context.Background())
|
|
|
|
itemGroup.Go(func() (err error) {
|
|
tags, err = getTags(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
itemGroup.Go(func() (err error) {
|
|
blacklist, err = getBlacklist(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
if err := itemGroup.Wait(); err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
forms, err := getForms(ctx, guildId)
|
|
if err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
staffTeams, err := getStaffTeams(ctx, guildId)
|
|
if err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
return
|
|
}
|
|
|
|
ctx.JSON(200, Export{
|
|
GuildId: guildId,
|
|
Settings: settings,
|
|
Panels: panels,
|
|
MultiPanels: multiPanelData,
|
|
Tickets: tickets,
|
|
Tags: tags,
|
|
Blacklist: *blacklist,
|
|
Forms: forms,
|
|
StaffTeams: staffTeams,
|
|
})
|
|
}
|
|
|
|
func getStaffTeams(ctx *gin.Context, guildId uint64) ([]SupportTeam, error) {
|
|
dbTeams, err := dbclient.Client.SupportTeam.Get(ctx, guildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// prevent serving null
|
|
if dbTeams == nil {
|
|
dbTeams = make([]database.SupportTeam, 0)
|
|
}
|
|
|
|
var teams []SupportTeam
|
|
|
|
for i := range dbTeams {
|
|
group, _ := errgroup.WithContext(context.Background())
|
|
i := i
|
|
team := dbTeams[i]
|
|
var (
|
|
users []uint64
|
|
roles []uint64
|
|
)
|
|
|
|
group.Go(func() error {
|
|
users, err = dbclient.Client.SupportTeamMembers.Get(ctx, team.Id)
|
|
return err
|
|
})
|
|
|
|
group.Go(func() error {
|
|
roles, err = dbclient.Client.SupportTeamRoles.Get(ctx, team.Id)
|
|
return err
|
|
})
|
|
|
|
if err := group.Wait(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
teams = append(teams, SupportTeam{
|
|
Id: team.Id,
|
|
Name: team.Name,
|
|
OnCallRole: team.OnCallRole,
|
|
Users: users,
|
|
Roles: roles,
|
|
})
|
|
}
|
|
|
|
return teams, nil
|
|
}
|
|
|
|
func getForms(ctx *gin.Context, guildId uint64) ([]Form, error) {
|
|
dbForms, err := dbclient.Client.Forms.GetForms(ctx, guildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dbFormInputs, err := dbclient.Client.FormInput.GetInputsForGuild(ctx, guildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
forms := make([]Form, len(dbForms))
|
|
for i, form := range dbForms {
|
|
formInputs, ok := dbFormInputs[form.Id]
|
|
if !ok {
|
|
formInputs = make([]database.FormInput, 0)
|
|
}
|
|
|
|
forms[i] = Form{
|
|
Form: form,
|
|
Inputs: formInputs,
|
|
}
|
|
}
|
|
return forms, nil
|
|
}
|
|
|
|
func getBlacklist(ctx *gin.Context, guildId uint64) (*Blacklist, error) {
|
|
userBlacklist, err := dbclient.Client.Blacklist.GetBlacklistedUsers(ctx, guildId, 100000, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
roleBlacklist, err := dbclient.Client.RoleBlacklist.GetBlacklistedRoles(ctx, guildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Blacklist{
|
|
Users: userBlacklist,
|
|
Roles: roleBlacklist,
|
|
}, nil
|
|
}
|
|
|
|
func getTags(ctx *gin.Context, guildId uint64) ([]Tag, error) {
|
|
dbTags, err := dbclient.Client.Tag.GetByGuild(ctx, guildId)
|
|
fmt.Println(len(dbTags))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tags := make([]Tag, len(dbTags))
|
|
|
|
i := 0
|
|
for _, tag := range dbTags {
|
|
var embed *types.CustomEmbed
|
|
if tag.Embed != nil {
|
|
embed = types.NewCustomEmbed(tag.Embed.CustomEmbed, tag.Embed.Fields)
|
|
}
|
|
|
|
tags[i] = Tag{
|
|
Id: tag.Id,
|
|
UseGuildCommand: tag.ApplicationCommandId != nil,
|
|
Content: tag.Content,
|
|
UseEmbed: tag.Embed != nil,
|
|
Embed: embed,
|
|
}
|
|
|
|
i++
|
|
}
|
|
return tags, nil
|
|
}
|
|
|
|
func getSettings(ctx *gin.Context, guildId uint64) Settings {
|
|
var settings Settings
|
|
group, _ := errgroup.WithContext(context.Background())
|
|
|
|
// main settings
|
|
group.Go(func() (err error) {
|
|
settings.Settings, err = dbclient.Client.Settings.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// claim settings
|
|
group.Go(func() (err error) {
|
|
settings.ClaimSettings, err = dbclient.Client.ClaimSettings.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// auto close settings
|
|
group.Go(func() error {
|
|
tmp, err := dbclient.Client.AutoClose.Get(ctx, guildId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
settings.AutoCloseSettings = convertToAutoCloseData(tmp)
|
|
return nil
|
|
})
|
|
|
|
// ticket permissions
|
|
group.Go(func() (err error) {
|
|
settings.TicketPermissions, err = dbclient.Client.TicketPermissions.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// colour map
|
|
group.Go(func() (err error) {
|
|
settings.Colours, err = getColourMap(guildId)
|
|
return
|
|
})
|
|
|
|
// welcome message
|
|
group.Go(func() (err error) {
|
|
settings.WelcomeMessage, err = dbclient.Client.WelcomeMessages.Get(ctx, guildId)
|
|
if err == nil && settings.WelcomeMessage == "" {
|
|
settings.WelcomeMessage = "Thank you for contacting support.\nPlease describe your issue and await a response."
|
|
}
|
|
|
|
return
|
|
})
|
|
|
|
// ticket limit
|
|
group.Go(func() (err error) {
|
|
settings.TicketLimit, err = dbclient.Client.TicketLimit.Get(ctx, guildId)
|
|
if err == nil && settings.TicketLimit == 0 {
|
|
settings.TicketLimit = 5 // Set default
|
|
}
|
|
|
|
return
|
|
})
|
|
|
|
// category
|
|
group.Go(func() (err error) {
|
|
settings.Category, err = dbclient.Client.ChannelCategory.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// archive channel
|
|
group.Go(func() (err error) {
|
|
settings.ArchiveChannel, err = dbclient.Client.ArchiveChannel.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// allow users to close
|
|
group.Go(func() (err error) {
|
|
settings.UsersCanClose, err = dbclient.Client.UsersCanClose.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// naming scheme
|
|
group.Go(func() (err error) {
|
|
settings.NamingScheme, err = dbclient.Client.NamingScheme.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// close confirmation
|
|
group.Go(func() (err error) {
|
|
settings.CloseConfirmation, err = dbclient.Client.CloseConfirmation.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// close confirmation
|
|
group.Go(func() (err error) {
|
|
settings.FeedbackEnabled, err = dbclient.Client.FeedbackEnabled.Get(ctx, guildId)
|
|
return
|
|
})
|
|
|
|
// language
|
|
group.Go(func() error {
|
|
locale, err := dbclient.Client.ActiveLanguage.Get(ctx, guildId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if locale != "" {
|
|
settings.Language = utils.Ptr(locale)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err := group.Wait(); err != nil {
|
|
ctx.JSON(500, utils.ErrorJson(err))
|
|
}
|
|
|
|
return settings
|
|
}
|
|
|
|
func getColourMap(guildId uint64) (ColourMap, error) {
|
|
raw, err := dbclient.Client.CustomColours.GetAll(context.Background(), guildId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
colours := make(ColourMap)
|
|
for id, hex := range raw {
|
|
if !utils.Exists(activeColours, customisation.Colour(id)) {
|
|
continue
|
|
}
|
|
|
|
colours[customisation.Colour(id)] = utils.HexColour(hex)
|
|
}
|
|
|
|
for _, id := range activeColours {
|
|
if _, ok := colours[id]; !ok {
|
|
colours[id] = utils.HexColour(customisation.DefaultColours[id])
|
|
}
|
|
}
|
|
|
|
return colours, nil
|
|
}
|
|
|
|
func convertToAutoCloseData(settings database.AutoCloseSettings) (body AutoCloseData) {
|
|
body.Enabled = settings.Enabled
|
|
|
|
if settings.SinceOpenWithNoResponse != nil {
|
|
body.SinceOpenWithNoResponse = int64(*settings.SinceOpenWithNoResponse / time.Second)
|
|
}
|
|
|
|
if settings.SinceLastMessage != nil {
|
|
body.SinceLastMessage = int64(*settings.SinceLastMessage / time.Second)
|
|
}
|
|
|
|
if settings.OnUserLeave != nil {
|
|
body.OnUserLeave = *settings.OnUserLeave
|
|
}
|
|
|
|
return
|
|
}
|