Ben Hall 34027ad95a bump db & fix imports
Signed-off-by: Ben Hall <ben@benh.codes>
2025-02-15 20:44:01 +00:00

1196 lines
38 KiB
Go

package api
import (
"bytes"
"context"
"crypto/ed25519"
"crypto/x509"
"encoding/pem"
"fmt"
"io"
"os"
"time"
database2 "github.com/TicketsBot-cloud/database"
"github.com/TicketsBot/GoPanel/app/http/endpoints/api/export/validator"
"github.com/TicketsBot/GoPanel/botcontext"
"github.com/TicketsBot/GoPanel/config"
dbclient "github.com/TicketsBot/GoPanel/database"
"github.com/TicketsBot/GoPanel/log"
"github.com/TicketsBot/GoPanel/rpc"
"github.com/TicketsBot/GoPanel/s3"
"github.com/TicketsBot/GoPanel/utils"
"github.com/TicketsBot/common/premium"
"github.com/TicketsBot/database"
"github.com/gin-gonic/gin"
"github.com/jackc/pgx/v4"
"github.com/minio/minio-go/v7"
"go.uber.org/zap"
"golang.org/x/sync/errgroup"
)
// func ImportHandler(ctx *gin.Context) {
// ctx.JSON(401, "This endpoint is disabled")
// }
func ImportHandler(ctx *gin.Context) {
// Return slices
successfulItems := make([]string, 0)
failedItems := make([]string, 0)
skippedItems := make([]string, 0)
// Parse request body from multipart form
queryCtx, cancel := context.WithTimeout(context.Background(), time.Minute*1500)
defer cancel()
var transcriptOutput *validator.GuildTranscriptsOutput
var data *validator.GuildData
dataFile, _, dataErr := ctx.Request.FormFile("data_file")
dataFileExists := dataErr == nil
transcriptsFile, _, transcriptsErr := ctx.Request.FormFile("transcripts_file")
transcriptFileExists := transcriptsErr == nil
// Decrypt file
publicKeyBlock, _ := pem.Decode([]byte(os.Getenv("V1_PUBLIC_KEY")))
if publicKeyBlock == nil {
ctx.JSON(400, utils.ErrorStr("Invalid public key"))
return
}
parsedKey, err := x509.ParsePKIXPublicKey(publicKeyBlock.Bytes)
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
return
}
decryptedPublicKey, ok := parsedKey.(ed25519.PublicKey)
if !ok {
ctx.JSON(400, utils.ErrorStr("Invalid public key"))
return
}
v := validator.NewValidator(
decryptedPublicKey,
validator.WithMaxUncompressedSize(500*1024*1024),
validator.WithMaxIndividualFileSize(100*1024*1024),
)
if dataFileExists {
defer dataFile.Close()
dataBuffer := bytes.NewBuffer(nil)
if _, err := io.Copy(dataBuffer, dataFile); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
dataReader := bytes.NewReader(dataBuffer.Bytes())
data, err = v.ValidateGuildData(dataReader, dataReader.Size())
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
return
}
}
guildId, selfId := ctx.Keys["guildid"].(uint64), ctx.Keys["userid"].(uint64)
if transcriptFileExists {
defer transcriptsFile.Close()
transcriptsBuffer := bytes.NewBuffer(nil)
if _, err := io.Copy(transcriptsBuffer, transcriptsFile); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
transcriptReader := bytes.NewReader(transcriptsBuffer.Bytes())
transcriptOutput, err = v.ValidateGuildTranscripts(transcriptReader, transcriptReader.Size())
if err != nil {
ctx.JSON(400, utils.ErrorJson(err))
return
}
// Upload transcripts
if transcriptFileExists {
if _, err := s3.S3Client.PutObject(ctx, config.Conf.S3Import.Bucket, fmt.Sprintf("transcripts/%d.zip", guildId), transcriptReader, transcriptReader.Size(), minio.PutObjectOptions{}); err != nil {
failedItems = append(failedItems, "Transcripts")
} else {
successfulItems = append(successfulItems, "Transcripts")
}
}
}
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 import server data"))
return
}
if dataFileExists && data.GuildId != guildId || transcriptFileExists && transcriptOutput.GuildId != guildId {
ctx.JSON(400, utils.ErrorStr("Invalid guild Id"))
return
}
premiumTier, err := rpc.PremiumClient.GetTierByGuildId(queryCtx, guildId, true, botCtx.Token, botCtx.RateLimiter)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
// Get ticket maps
mapping, err := dbclient.Client2.ImportMappingTable.GetMapping(queryCtx, guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
var (
ticketIdMap = mapping["ticket"]
formIdMap = mapping["form"]
formInputIdMap = mapping["form_input"]
panelIdMap = mapping["panel"]
)
if ticketIdMap == nil {
ticketIdMap = make(map[int]int)
}
if formIdMap == nil {
formIdMap = make(map[int]int)
}
if formInputIdMap == nil {
formInputIdMap = make(map[int]int)
}
if panelIdMap == nil {
panelIdMap = make(map[int]int)
}
if dataFileExists {
if data.GuildIsGloballyBlacklisted {
reason := "Blacklisted on v1"
_ = dbclient.Client.ServerBlacklist.Add(queryCtx, guildId, &reason)
log.Logger.Info("Imported globally blacklisted", zap.Uint64("guild", guildId))
ctx.JSON(403, "This server is blacklisted on v1")
return
}
group, _ := errgroup.WithContext(queryCtx)
// Import active language
group.Go(func() (err error) {
lang := "en"
if data.ActiveLanguage != nil {
lang = *data.ActiveLanguage
}
if err := dbclient.Client.ActiveLanguage.Set(queryCtx, guildId, lang); err != nil {
failedItems = append(failedItems, "Language")
} else {
successfulItems = append(successfulItems, "Language")
}
log.Logger.Info("Imported active language", zap.Uint64("guild", guildId), zap.String("language", lang))
return
})
// Import archive channel
group.Go(func() (err error) {
if data.ArchiveChannel != nil {
if err := dbclient.Client.ArchiveChannel.Set(queryCtx, guildId, data.ArchiveChannel); err != nil {
failedItems = append(failedItems, "Archive Channel")
} else {
successfulItems = append(successfulItems, "Archive Channel")
}
log.Logger.Info("Imported archive channel", zap.Uint64("guild", guildId), zap.Uint64("channel", *data.ArchiveChannel))
}
return
})
// import AutocloseSettings
group.Go(func() (err error) {
if data.AutocloseSettings != nil {
if premiumTier < premium.Premium {
data.AutocloseSettings.Enabled = false
}
if err := dbclient.Client.AutoClose.Set(queryCtx, guildId, *data.AutocloseSettings); err != nil {
failedItems = append(failedItems, "Autoclose Settings")
} else {
successfulItems = append(successfulItems, "Autoclose Settings")
}
log.Logger.Info("Imported autoclose settings", zap.Uint64("guild", guildId), zap.Bool("enabled", data.AutocloseSettings.Enabled))
}
return
})
// Import blacklisted users
group.Go(func() (err error) {
failedUsers := 0
for _, user := range data.GuildBlacklistedUsers {
err = dbclient.Client.Blacklist.Add(queryCtx, guildId, user)
log.Logger.Info("Imported blacklisted user", zap.Uint64("guild", guildId), zap.Uint64("user", user))
if err != nil {
failedUsers++
}
}
if failedUsers == 0 {
successfulItems = append(successfulItems, "Blacklisted Users")
} else {
failedItems = append(failedItems, fmt.Sprintf("Blacklisted Users (x%d)", failedUsers))
}
return
})
// Import channel category
group.Go(func() (err error) {
if data.ChannelCategory != nil {
if err := dbclient.Client.ChannelCategory.Set(queryCtx, guildId, *data.ChannelCategory); err != nil {
failedItems = append(failedItems, "Channel Category")
} else {
successfulItems = append(successfulItems, "Channel Category")
}
log.Logger.Info("Imported channel category", zap.Uint64("guild", guildId), zap.Uint64("category", *data.ChannelCategory))
}
return
})
// Import claim settings
group.Go(func() (err error) {
if data.ClaimSettings != nil {
if err := dbclient.Client.ClaimSettings.Set(queryCtx, guildId, *data.ClaimSettings); err != nil {
failedItems = append(failedItems, "Claim Settings")
} else {
successfulItems = append(successfulItems, "Claim Settings")
}
log.Logger.Info("Imported claim settings", zap.Uint64("guild", guildId), zap.Any("settings", data.ClaimSettings))
}
return
})
// Import close confirmation enabled
group.Go(func() (err error) {
if err := dbclient.Client.CloseConfirmation.Set(queryCtx, guildId, data.CloseConfirmationEnabled); err != nil {
failedItems = append(failedItems, "Close Confirmation")
} else {
successfulItems = append(successfulItems, "Close Confirmation")
}
log.Logger.Info("Imported close confirmation enabled", zap.Uint64("guild", guildId), zap.Bool("enabled", data.CloseConfirmationEnabled))
return
})
// Import custom colours
group.Go(func() (err error) {
if premiumTier < premium.Premium {
return
}
failedColours := 0
for k, v := range data.CustomColors {
err = dbclient.Client.CustomColours.Set(queryCtx, guildId, k, v)
log.Logger.Info("Imported custom colour", zap.Uint64("guild", guildId), zap.Int16("key", k), zap.Int("value", v))
if err != nil {
failedColours++
}
}
if failedColours == 0 {
successfulItems = append(successfulItems, "Custom Colours")
} else {
failedItems = append(failedItems, fmt.Sprintf("Custom Colours (x%d)", failedColours))
}
return
})
// Import feedback enabled
group.Go(func() (err error) {
if err := dbclient.Client.FeedbackEnabled.Set(queryCtx, guildId, data.FeedbackEnabled); err != nil {
failedItems = append(failedItems, "Feedback Enabled")
} else {
successfulItems = append(successfulItems, "Feedback Enabled")
}
log.Logger.Info("Imported feedback enabled", zap.Uint64("guild", guildId), zap.Bool("enabled", data.FeedbackEnabled))
return
})
// Import Guild Metadata
group.Go(func() (err error) {
if err := dbclient.Client.GuildMetadata.Set(queryCtx, guildId, data.GuildMetadata); err != nil {
failedItems = append(failedItems, "Guild Metadata")
} else {
successfulItems = append(successfulItems, "Guild Metadata")
}
log.Logger.Info("Imported guild metadata", zap.Uint64("guild", guildId), zap.Any("metadata", data.GuildMetadata))
return
})
// Import Naming Scheme
group.Go(func() (err error) {
if data.NamingScheme != nil {
if err := dbclient.Client.NamingScheme.Set(queryCtx, guildId, *data.NamingScheme); err != nil {
failedItems = append(failedItems, "Naming Scheme")
} else {
successfulItems = append(successfulItems, "Naming Scheme")
}
log.Logger.Info("Imported naming scheme", zap.Uint64("guild", guildId), zap.Any("scheme", data.NamingScheme))
}
return
})
// Import On Call Users
group.Go(func() (err error) {
failedUsers := 0
for _, user := range data.OnCallUsers {
if isOnCall, oncallerr := dbclient.Client.OnCall.IsOnCall(queryCtx, guildId, user); oncallerr != nil {
return oncallerr
} else if !isOnCall {
if _, err := dbclient.Client.OnCall.Toggle(queryCtx, guildId, user); err != nil {
failedUsers++
}
}
}
if failedUsers == 0 {
successfulItems = append(successfulItems, "On Call Users")
} else {
failedItems = append(failedItems, fmt.Sprintf("On Call Users (x%d)", failedUsers))
}
return
})
// Import User Permissions
group.Go(func() (err error) {
failedUsers := 0
for _, perm := range data.UserPermissions {
if perm.IsSupport {
if err := dbclient.Client.Permissions.AddSupport(queryCtx, guildId, perm.Snowflake); err != nil {
failedUsers++
}
log.Logger.Info("Imported user permission", zap.Uint64("guild", guildId), zap.Uint64("user", perm.Snowflake), zap.Bool("support", true))
}
if perm.IsAdmin {
if err := dbclient.Client.Permissions.AddAdmin(queryCtx, guildId, perm.Snowflake); err != nil {
failedUsers++
}
log.Logger.Info("Imported user permission", zap.Uint64("guild", guildId), zap.Uint64("user", perm.Snowflake), zap.Bool("admin", true))
}
}
if failedUsers == 0 {
successfulItems = append(successfulItems, "User Permissions")
} else {
failedItems = append(failedItems, fmt.Sprintf("User Permissions (x%d)", failedUsers))
}
return
})
// Import Guild Blacklisted Roles
group.Go(func() (err error) {
failedRoles := 0
for _, role := range data.GuildBlacklistedRoles {
if err := dbclient.Client.RoleBlacklist.Add(queryCtx, guildId, role); err != nil {
failedRoles++
}
log.Logger.Info("Imported guild blacklisted role", zap.Uint64("guild", guildId), zap.Uint64("role", role))
}
if failedRoles == 0 {
successfulItems = append(successfulItems, "Guild Blacklisted Roles")
} else {
failedItems = append(failedItems, fmt.Sprintf("Guild Blacklisted Roles (x%d)", failedRoles))
}
return
})
// Import Role Permissions
group.Go(func() (err error) {
failedRoles := 0
for _, perm := range data.RolePermissions {
if perm.IsSupport {
if err := dbclient.Client.RolePermissions.AddSupport(queryCtx, guildId, perm.Snowflake); err != nil {
failedRoles++
}
log.Logger.Info("Imported role permission", zap.Uint64("guild", guildId), zap.Uint64("role", perm.Snowflake), zap.Bool("support", true))
}
if perm.IsAdmin {
if err := dbclient.Client.RolePermissions.AddAdmin(queryCtx, guildId, perm.Snowflake); err != nil {
failedRoles++
}
log.Logger.Info("Imported role permission", zap.Uint64("guild", guildId), zap.Uint64("role", perm.Snowflake), zap.Bool("admin", true))
}
}
if failedRoles == 0 {
successfulItems = append(successfulItems, "Role Permissions")
} else {
failedItems = append(failedItems, fmt.Sprintf("Role Permissions (x%d)", failedRoles))
}
return
})
// Import Tags
group.Go(func() (err error) {
failedTags := 0
for _, tag := range data.Tags {
if err := dbclient.Client.Tag.Set(queryCtx, tag); err != nil {
failedTags++
}
log.Logger.Info("Imported tag", zap.Uint64("guild", guildId), zap.String("name", tag.Id))
}
if failedTags == 0 {
successfulItems = append(successfulItems, "Tags")
} else {
failedItems = append(failedItems, fmt.Sprintf("Tags (x%d)", failedTags))
}
return
})
// Import Ticket Limit
group.Go(func() (err error) {
if data.TicketLimit != nil {
if err := dbclient.Client.TicketLimit.Set(queryCtx, guildId, uint8(*data.TicketLimit)); err != nil {
failedItems = append(failedItems, "Ticket Limit")
} else {
successfulItems = append(successfulItems, "Ticket Limit")
}
log.Logger.Info("Imported ticket limit", zap.Uint64("guild", guildId), zap.Uint8("limit", uint8(*data.TicketLimit)))
}
return
})
// Import Ticket Permissions
group.Go(func() (err error) {
if err := dbclient.Client.TicketPermissions.Set(queryCtx, guildId, data.TicketPermissions); err != nil {
failedItems = append(failedItems, "Ticket Permissions")
} else {
successfulItems = append(successfulItems, "Ticket Permissions")
}
log.Logger.Info("Imported ticket permissions", zap.Uint64("guild", guildId), zap.Any("permissions", data.TicketPermissions))
return
})
// Import Users Can Close
group.Go(func() (err error) {
if err := dbclient.Client.UsersCanClose.Set(queryCtx, guildId, data.UsersCanClose); err != nil {
failedItems = append(failedItems, "Users Can Close")
} else {
successfulItems = append(successfulItems, "Users Can Close")
}
log.Logger.Info("Imported users can close", zap.Uint64("guild", guildId), zap.Bool("can_close", data.UsersCanClose))
return
})
// Import Welcome Message
group.Go(func() (err error) {
if data.WelcomeMessage != nil {
if err := dbclient.Client.WelcomeMessages.Set(queryCtx, guildId, *data.WelcomeMessage); err != nil {
failedItems = append(failedItems, "Welcome Message")
} else {
successfulItems = append(successfulItems, "Welcome Message")
}
log.Logger.Info("Imported welcome message", zap.Uint64("guild", guildId), zap.String("message", *data.WelcomeMessage))
}
return
})
_ = group.Wait()
supportTeamIdMap := make(map[int]int)
failedSupportTeams := 0
// Import Support Teams
for _, team := range data.SupportTeams {
teamId, err := dbclient.Client.SupportTeam.Create(queryCtx, guildId, fmt.Sprintf("%s (Imported)", team.Name))
if err != nil {
failedSupportTeams++
}
log.Logger.Info("Imported support team", zap.Uint64("guild", guildId), zap.String("name", team.Name))
supportTeamIdMap[team.Id] = teamId
}
if failedSupportTeams == 0 {
successfulItems = append(successfulItems, "Support Teams")
} else {
failedItems = append(failedItems, fmt.Sprintf("Support Teams (x%d)", failedSupportTeams))
}
failedSupportTeamUsers := 0
// Import Support Team Users
log.Logger.Info("Importing support team users", zap.Uint64("guild", guildId))
for teamId, users := range data.SupportTeamUsers {
for _, user := range users {
if err := dbclient.Client.SupportTeamMembers.Add(queryCtx, supportTeamIdMap[teamId], user); err != nil {
failedSupportTeamUsers++
}
}
}
if failedSupportTeamUsers == 0 {
successfulItems = append(successfulItems, "Support Team Users")
} else {
failedItems = append(failedItems, fmt.Sprintf("Support Team Users (x%d)", failedSupportTeamUsers))
}
failedSupportTeamRoles := 0
// Import Support Team Roles
log.Logger.Info("Importing support team roles", zap.Uint64("guild", guildId))
for teamId, roles := range data.SupportTeamRoles {
for _, role := range roles {
if err := dbclient.Client.SupportTeamRoles.Add(queryCtx, supportTeamIdMap[teamId], role); err != nil {
failedSupportTeamRoles++
}
}
}
if failedSupportTeamRoles == 0 {
successfulItems = append(successfulItems, "Support Team Roles")
} else {
failedItems = append(failedItems, fmt.Sprintf("Support Team Roles (x%d)", failedSupportTeamRoles))
}
// Import forms
log.Logger.Info("Importing forms", zap.Uint64("guild", guildId))
failedForms := make([]int, 0)
for _, form := range data.Forms {
if _, ok := formIdMap[form.Id]; !ok {
newCustomId, _ := utils.RandString(30)
formId, err := dbclient.Client.Forms.Create(queryCtx, guildId, fmt.Sprintf("%s (Imported)", form.Title), newCustomId)
log.Logger.Info("Imported form", zap.Uint64("guild", guildId), zap.String("title", form.Title))
if err != nil {
failedForms = append(failedForms, form.Id)
} else {
formIdMap[form.Id] = formId
}
} else {
skippedItems = append(skippedItems, fmt.Sprintf("Form (Title: %s)", form.Title))
}
}
if len(failedForms) == 0 {
successfulItems = append(successfulItems, "Forms")
} else {
failedItems = append(failedItems, fmt.Sprintf("Forms (x%d)", len(failedForms)))
}
log.Logger.Info("Importing mapping for forms", zap.Uint64("guild", guildId))
for area, m := range map[string]map[int]int{"form": formIdMap} {
for sourceId, targetId := range m {
if err := dbclient.Client2.ImportMappingTable.Set(queryCtx, guildId, area, sourceId, targetId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
}
}
// Import form inputs
log.Logger.Info("Importing form inputs", zap.Uint64("guild", guildId))
failedFormInputs := make([]int, 0)
for _, input := range data.FormInputs {
if failedForms != nil && utils.Contains(failedForms, input.FormId) {
skippedItems = append(skippedItems, fmt.Sprintf("Form Input (Form: %d, ID: %d)", input.FormId, input.Id))
continue
}
if _, ok := formInputIdMap[input.Id]; !ok {
newCustomId, _ := utils.RandString(30)
newInputId, err := dbclient.Client.FormInput.Create(queryCtx, formIdMap[input.FormId], newCustomId, input.Style, input.Label, input.Placeholder, input.Required, input.MinLength, input.MaxLength)
if err != nil {
failedItems = append(failedItems, fmt.Sprintf("Form Input (Form: %d, ID: %d)", input.FormId, input.Id))
failedFormInputs = append(failedFormInputs, input.Id)
} else {
formInputIdMap[input.Id] = newInputId
}
} else {
skippedItems = append(skippedItems, fmt.Sprintf("Form Input (Form: %d, ID: %d)", input.FormId, input.Id))
}
}
log.Logger.Info("Importing mapping for forms inputs", zap.Uint64("guild", guildId))
for area, m := range map[string]map[int]int{"form_input": formInputIdMap} {
for sourceId, targetId := range m {
if err := dbclient.Client2.ImportMappingTable.Set(queryCtx, guildId, area, sourceId, targetId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
}
}
embedMap := make(map[int]int)
// Import embeds
log.Logger.Info("Importing embeds", zap.Uint64("guild", guildId))
failedEmbeds := make([]int, 0)
for _, embed := range data.Embeds {
var embedFields []database.EmbedField
for _, field := range data.EmbedFields {
if field.EmbedId == embed.Id {
embedFields = append(embedFields, field)
}
}
embed.GuildId = guildId
embedId, err := dbclient.Client.Embeds.CreateWithFields(queryCtx, &embed, embedFields)
if err != nil {
failedEmbeds = append(failedEmbeds, embed.Id)
} else {
log.Logger.Info("Imported embed", zap.Uint64("guild", guildId), zap.Int("embed", embed.Id), zap.Int("new_embed", embedId))
embedMap[embed.Id] = embedId
}
}
if len(failedEmbeds) == 0 {
successfulItems = append(successfulItems, "Embeds")
} else {
failedItems = append(failedItems, fmt.Sprintf("Embeds (x%d)", len(failedEmbeds)))
}
// Panel id map
existingPanels, err := dbclient.Client.Panel.GetByGuild(queryCtx, guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
panelCount := len(existingPanels)
panelTx, _ := dbclient.Client.Panel.BeginTx(queryCtx, pgx.TxOptions{})
// Import Panels
log.Logger.Info("Importing panels", zap.Uint64("guild", guildId))
failedPanels := make([]int, 0)
for _, panel := range data.Panels {
if _, ok := panelIdMap[panel.PanelId]; !ok {
if premiumTier < premium.Premium && panelCount > 2 {
panel.ForceDisabled = true
panel.Disabled = true
}
if panel.FormId != nil {
if failedForms != nil && utils.Contains(failedForms, *panel.FormId) {
skippedItems = append(skippedItems, fmt.Sprintf("Panel (ID: %d, missing form)", panel.PanelId))
continue
}
newFormId := formIdMap[*panel.FormId]
panel.FormId = &newFormId
}
if panel.ExitSurveyFormId != nil {
newFormId := formIdMap[*panel.ExitSurveyFormId]
panel.ExitSurveyFormId = &newFormId
}
if panel.WelcomeMessageEmbed != nil {
if failedEmbeds == nil || !utils.Contains(failedEmbeds, *panel.WelcomeMessageEmbed) {
newEmbedId := embedMap[*panel.WelcomeMessageEmbed]
panel.WelcomeMessageEmbed = &newEmbedId
}
}
panel.Title = fmt.Sprintf("%s (Imported)", panel.Title)
// TODO: Fix this permanently
panel.MessageId = panel.MessageId - 1
newCustomId, _ := utils.RandString(30)
panel.CustomId = newCustomId
panelId, err := dbclient.Client.Panel.CreateWithTx(queryCtx, panelTx, panel)
if err != nil {
failedPanels = append(failedPanels, panel.PanelId)
} else {
log.Logger.Info("Imported panel", zap.Uint64("guild", guildId), zap.Int("panel", panel.PanelId), zap.Int("new_panel", panelId))
panelIdMap[panel.PanelId] = panelId
panelCount++
}
}
}
if len(failedPanels) == 0 {
successfulItems = append(successfulItems, "Panels")
} else {
failedItems = append(failedItems, fmt.Sprintf("Panels (x%d)", len(failedPanels)))
}
if err := panelTx.Commit(queryCtx); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
log.Logger.Info("Importing mapping for panels", zap.Uint64("guild", guildId))
for area, m := range map[string]map[int]int{"panel": panelIdMap} {
for sourceId, targetId := range m {
if err := dbclient.Client2.ImportMappingTable.Set(queryCtx, guildId, area, sourceId, targetId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
}
}
// Import Panel Access Control Rules
log.Logger.Info("Importing panel access control rules", zap.Uint64("guild", guildId))
failedPanelAccessControlRules := 0
for panelId, rules := range data.PanelAccessControlRules {
if len(failedPanels) > 0 && utils.Contains(failedPanels, panelId) {
skippedItems = append(skippedItems, fmt.Sprintf("Panel Access Control Rules (Panel: %d)", panelId))
continue
}
if _, ok := panelIdMap[panelId]; ok {
if err := dbclient.Client.PanelAccessControlRules.Replace(queryCtx, panelIdMap[panelId], rules); err != nil {
failedPanelAccessControlRules++
}
} else {
skippedItems = append(skippedItems, fmt.Sprintf("Panel Access Control Rules (Panel: %d)", panelId))
}
}
if failedPanelAccessControlRules == 0 {
successfulItems = append(successfulItems, "Panel Access Control Rules")
} else {
failedItems = append(failedItems, fmt.Sprintf("Panel Access Control Rules (x%d)", failedPanelAccessControlRules))
}
// Import Panel Mention User
log.Logger.Info("Importing panel mention user", zap.Uint64("guild", guildId))
failedPanelMentionUser := 0
for panelId, shouldMention := range data.PanelMentionUser {
if len(failedPanels) > 0 && utils.Contains(failedPanels, panelId) {
skippedItems = append(skippedItems, fmt.Sprintf("Panel Mention User (Panel: %d)", panelId))
continue
}
if err := dbclient.Client.PanelUserMention.Set(queryCtx, panelIdMap[panelId], shouldMention); err != nil {
failedPanelMentionUser++
}
}
if failedPanelMentionUser == 0 {
successfulItems = append(successfulItems, "Panel Mention User")
} else {
failedItems = append(failedItems, fmt.Sprintf("Panel Mention User (x%d)", failedPanelMentionUser))
}
// Import Panel Role Mentions
failedPanelRoleMentions := 0
log.Logger.Info("Importing panel role mentions", zap.Uint64("guild", guildId))
for panelId, roles := range data.PanelRoleMentions {
if len(failedPanels) > 0 && utils.Contains(failedPanels, panelId) {
skippedItems = append(skippedItems, fmt.Sprintf("Panel Role Mentions (Panel: %d)", panelId))
continue
}
if err := dbclient.Client.PanelRoleMentions.Replace(queryCtx, panelIdMap[panelId], roles); err != nil {
failedPanelRoleMentions++
}
}
if failedPanelRoleMentions == 0 {
successfulItems = append(successfulItems, "Panel Role Mentions")
} else {
failedItems = append(failedItems, fmt.Sprintf("Panel Role Mentions (x%d)", failedPanelRoleMentions))
}
// Import Panel Teams
log.Logger.Info("Importing panel teams", zap.Uint64("guild", guildId))
failedPanelTeams := 0
for panelId, teams := range data.PanelTeams {
if len(failedPanels) > 0 && utils.Contains(failedPanels, panelId) {
skippedItems = append(skippedItems, fmt.Sprintf("Panel Teams (Panel: %d)", panelId))
continue
}
teamsToAdd := make([]int, len(teams))
for _, team := range teams {
teamsToAdd = append(teamsToAdd, supportTeamIdMap[team])
}
if err := dbclient.Client.PanelTeams.Replace(queryCtx, panelIdMap[panelId], teamsToAdd); err != nil {
failedPanelTeams++
}
}
if failedPanelTeams == 0 {
successfulItems = append(successfulItems, "Panel Teams")
} else {
failedItems = append(failedItems, fmt.Sprintf("Panel Teams (x%d)", failedPanelTeams))
}
// Import Multi panels
log.Logger.Info("Importing multi panels", zap.Uint64("guild", guildId))
multiPanelIdMap := make(map[int]int)
failedMultiPanels := make([]int, 0)
for _, multiPanel := range data.MultiPanels {
multiPanelId, err := dbclient.Client.MultiPanels.Create(queryCtx, multiPanel)
if err != nil {
failedMultiPanels = append(failedMultiPanels, multiPanel.Id)
} else {
log.Logger.Info("Imported multi panel", zap.Uint64("guild", guildId), zap.Int("multi_panel", multiPanel.Id), zap.Int("new_multi_panel", multiPanelId))
multiPanelIdMap[multiPanel.Id] = multiPanelId
}
}
if len(failedMultiPanels) == 0 {
successfulItems = append(successfulItems, "Multi Panels")
} else {
failedItems = append(failedItems, fmt.Sprintf("Multi Panels (x%d)", len(failedMultiPanels)))
}
// Import Multi Panel Targets
log.Logger.Info("Importing multi panel targets", zap.Uint64("guild", guildId))
failedMultiPanelTargets := 0
for multiPanelId, panelIds := range data.MultiPanelTargets {
if len(failedMultiPanels) > 0 && utils.Contains(failedMultiPanels, multiPanelId) {
skippedItems = append(skippedItems, fmt.Sprintf("Multi Panel Targets (Multi Panel: %d)", multiPanelId))
continue
}
for _, panelId := range panelIds {
if len(failedPanels) > 0 && utils.Contains(failedPanels, panelId) {
skippedItems = append(skippedItems, fmt.Sprintf("Multi Panel Targets (Multi Panel: %d, Panel: %d)", multiPanelId, panelId))
continue
}
if err := dbclient.Client.MultiPanelTargets.Insert(queryCtx, multiPanelIdMap[multiPanelId], panelIdMap[panelId]); err != nil {
failedMultiPanelTargets++
}
}
}
if failedMultiPanelTargets == 0 {
successfulItems = append(successfulItems, "Multi Panel Targets")
} else {
failedItems = append(failedItems, fmt.Sprintf("Multi Panel Targets (x%d)", failedMultiPanelTargets))
}
if data.Settings.ContextMenuPanel != nil {
newContextMenuPanel := panelIdMap[*data.Settings.ContextMenuPanel]
data.Settings.ContextMenuPanel = &newContextMenuPanel
}
// Import settings
log.Logger.Info("Importing settings", zap.Uint64("guild", guildId))
if err := dbclient.Client.Settings.Set(queryCtx, guildId, data.Settings); err != nil {
failedItems = append(failedItems, "Settings")
} else {
successfulItems = append(successfulItems, "Settings")
}
ticketCount, err := dbclient.Client.Tickets.GetTotalTicketCount(queryCtx, guildId)
if err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
ticketsToCreate := make([]database2.Ticket, len(data.Tickets))
ticketIdMapTwo := make(map[int]int)
// Import tickets
for i, ticket := range data.Tickets {
if _, ok := ticketIdMap[ticket.Id]; !ok {
log.Logger.Info("Importing ticket", zap.Uint64("guild", guildId), zap.Int("ticket", ticket.Id), zap.Int("new_ticket", ticket.Id+ticketCount))
var panelId *int
if ticket.PanelId != nil {
a := panelIdMap[*ticket.PanelId]
panelId = &a
}
ticketsToCreate[i] = database2.Ticket{
Id: ticket.Id + ticketCount,
GuildId: guildId,
ChannelId: ticket.ChannelId,
UserId: ticket.UserId,
Open: ticket.Open,
OpenTime: ticket.OpenTime,
WelcomeMessageId: ticket.WelcomeMessageId,
PanelId: panelId,
HasTranscript: ticket.HasTranscript,
CloseTime: ticket.CloseTime,
IsThread: ticket.IsThread,
JoinMessageId: ticket.JoinMessageId,
NotesThreadId: ticket.NotesThreadId,
}
ticketIdMapTwo[ticket.Id] = ticket.Id + ticketCount
} else {
skippedItems = append(skippedItems, fmt.Sprintf("Ticket (ID: %d)", ticket.Id))
}
}
log.Logger.Info("Importing tickets", zap.Uint64("guild", guildId))
if err := dbclient.Client2.Tickets.BulkImport(queryCtx, guildId, ticketsToCreate); err != nil {
failedItems = append(failedItems, "Tickets")
} else {
successfulItems = append(successfulItems, "Tickets")
}
// Update the mapping
log.Logger.Info("Importing mapping for tickets", zap.Uint64("guild", guildId))
for area, m := range map[string]map[int]int{"ticket": ticketIdMapTwo} {
for sourceId, targetId := range m {
if err := dbclient.Client2.ImportMappingTable.Set(queryCtx, guildId, area, sourceId, targetId); err != nil {
ctx.JSON(500, utils.ErrorJson(err))
return
}
}
}
ticketsExtrasGroup, _ := errgroup.WithContext(queryCtx)
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing ticket members", zap.Uint64("guild", guildId))
newMembersMap := make(map[int][]uint64)
for ticketId, members := range data.TicketAdditionalMembers {
if _, ok := ticketIdMap[ticketId]; !ok {
continue
}
newMembersMap[ticketIdMap[ticketId]] = members
}
if err := dbclient.Client2.TicketMembers.ImportBulk(queryCtx, guildId, newMembersMap); err != nil {
failedItems = append(failedItems, "Ticket Additional Members")
} else {
successfulItems = append(successfulItems, "Ticket Additional Members")
}
return
})
// Import ticket last messages
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing ticket last messages", zap.Uint64("guild", guildId))
msgs := map[int]database2.TicketLastMessage{}
for _, msg := range data.TicketLastMessages {
if _, ok := ticketIdMap[msg.TicketId]; !ok {
continue
}
msgs[ticketIdMap[msg.TicketId]] = database2.TicketLastMessage{
LastMessageId: msg.Data.LastMessageId,
LastMessageTime: msg.Data.LastMessageTime,
UserId: msg.Data.UserId,
UserIsStaff: msg.Data.UserIsStaff,
}
}
if err := dbclient.Client2.TicketLastMessage.ImportBulk(queryCtx, guildId, msgs); err != nil {
failedItems = append(failedItems, "Ticket Last Messages")
} else {
successfulItems = append(successfulItems, "Ticket Last Messages")
}
return
})
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing ticket claims", zap.Uint64("guild", guildId))
newClaimsMap := make(map[int]uint64)
for ticketId, user := range data.TicketClaims {
if _, ok := ticketIdMap[ticketId]; !ok {
continue
}
newClaimsMap[ticketIdMap[ticketId]] = user.Data
}
if err := dbclient.Client2.TicketClaims.ImportBulk(queryCtx, guildId, newClaimsMap); err != nil {
failedItems = append(failedItems, "Ticket Claims")
} else {
successfulItems = append(successfulItems, "Ticket Claims")
}
return
})
// Import ticket ratings
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing ticket ratings", zap.Uint64("guild", guildId))
newRatingsMap := make(map[int]uint8)
for ticketId, rating := range data.ServiceRatings {
if _, ok := ticketIdMapTwo[ticketId]; !ok {
continue
}
newRatingsMap[ticketIdMapTwo[ticketId]] = uint8(rating.Data)
}
if err := dbclient.Client2.ServiceRatings.ImportBulk(queryCtx, guildId, newRatingsMap); err != nil {
failedItems = append(failedItems, "Ticket Ratings")
} else {
successfulItems = append(successfulItems, "Ticket Ratings")
}
return
})
// Import participants
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing ticket participants", zap.Uint64("guild", guildId))
newParticipantsMap := make(map[int][]uint64)
for ticketId, participants := range data.Participants {
if _, ok := ticketIdMapTwo[ticketId]; !ok {
continue
}
newParticipantsMap[ticketIdMapTwo[ticketId]] = participants
}
if err := dbclient.Client2.Participants.ImportBulk(queryCtx, guildId, newParticipantsMap); err != nil {
failedItems = append(failedItems, "Ticket Participants")
} else {
successfulItems = append(successfulItems, "Ticket Participants")
}
return
})
// Import First Response Times
ticketsExtrasGroup.Go(func() (err error) {
failedFirstResponseTimes := 0
log.Logger.Info("Importing first response times", zap.Uint64("guild", guildId))
for _, frt := range data.FirstResponseTimes {
if _, ok := ticketIdMapTwo[frt.TicketId]; !ok {
continue
}
if err := dbclient.Client.FirstResponseTime.Set(queryCtx, guildId, frt.UserId, ticketIdMapTwo[frt.TicketId], frt.ResponseTime); err != nil {
failedFirstResponseTimes++
}
}
if failedFirstResponseTimes == 0 {
successfulItems = append(successfulItems, "First Response Times")
} else {
failedItems = append(failedItems, fmt.Sprintf("First Response Times (x%d)", failedFirstResponseTimes))
}
return
})
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing ticket survey responses", zap.Uint64("guild", guildId))
failedSurveyResponses := 0
for _, response := range data.ExitSurveyResponses {
if _, ok := ticketIdMapTwo[response.TicketId]; !ok {
continue
}
resps := map[int]string{
*response.Data.QuestionId: *response.Data.Response,
}
if err := dbclient.Client.ExitSurveyResponses.AddResponses(queryCtx, guildId, ticketIdMapTwo[response.TicketId], formIdMap[*response.Data.FormId], resps); err != nil {
failedSurveyResponses++
}
}
if failedSurveyResponses == 0 {
successfulItems = append(successfulItems, "Exit Survey Responses")
} else {
failedItems = append(failedItems, fmt.Sprintf("Exit Survey Responses (x%d)", failedSurveyResponses))
}
return
})
// Import Close Reasons
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing close reasons", zap.Uint64("guild", guildId))
failedCloseReasons := 0
for _, reason := range data.CloseReasons {
if _, ok := ticketIdMapTwo[reason.TicketId]; !ok {
continue
}
if err := dbclient.Client.CloseReason.Set(queryCtx, guildId, ticketIdMapTwo[reason.TicketId], reason.Data); err != nil {
failedCloseReasons++
}
}
if failedCloseReasons == 0 {
successfulItems = append(successfulItems, "Close Reasons")
} else {
failedItems = append(failedItems, fmt.Sprintf("Close Reasons (x%d)", failedCloseReasons))
}
return
})
// Import Autoclose Excluded Tickets
ticketsExtrasGroup.Go(func() (err error) {
failedAutocloseExcluded := 0
log.Logger.Info("Importing autoclose excluded tickets", zap.Uint64("guild", guildId))
for _, ticketId := range data.AutocloseExcluded {
if _, ok := ticketIdMapTwo[ticketId]; !ok {
continue
}
if err := dbclient.Client.AutoCloseExclude.Exclude(queryCtx, guildId, ticketIdMapTwo[ticketId]); err != nil {
failedAutocloseExcluded++
}
}
if failedAutocloseExcluded == 0 {
successfulItems = append(successfulItems, "Autoclose Excluded Tickets")
} else {
failedItems = append(failedItems, fmt.Sprintf("Autoclose Excluded Tickets (x%d)", failedAutocloseExcluded))
}
return
})
// Import Archive Messages
ticketsExtrasGroup.Go(func() (err error) {
log.Logger.Info("Importing archive messages", zap.Uint64("guild", guildId))
failedArchiveMessages := 0
for _, message := range data.ArchiveMessages {
if _, ok := ticketIdMapTwo[message.TicketId]; !ok {
continue
}
if err := dbclient.Client.ArchiveMessages.Set(queryCtx, guildId, ticketIdMapTwo[message.TicketId], message.Data.ChannelId, message.Data.MessageId); err != nil {
failedArchiveMessages++
}
}
if failedArchiveMessages == 0 {
successfulItems = append(successfulItems, "Archive Messages")
} else {
failedItems = append(failedItems, fmt.Sprintf("Archive Messages (x%d)", failedArchiveMessages))
}
return
})
_ = ticketsExtrasGroup.Wait()
}
ctx.JSON(200, map[string]interface{}{
"failed": failedItems,
"success": successfulItems,
"skipped": skippedItems,
})
}