355 lines
12 KiB
Go
355 lines
12 KiB
Go
package transfer
|
|
|
|
import (
|
|
"bamort/config"
|
|
"bamort/database"
|
|
"bamort/models"
|
|
"bamort/user"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// DatabaseExport contains all database tables for export/import
|
|
type DatabaseExport struct {
|
|
Version string `json:"version"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
|
|
// User data
|
|
Users []user.User `json:"users"`
|
|
|
|
// Character data
|
|
Characters []models.Char `json:"characters"`
|
|
Eigenschaften []models.Eigenschaft `json:"eigenschaften"`
|
|
Lps []models.Lp `json:"lps"`
|
|
Aps []models.Ap `json:"aps"`
|
|
Bs []models.B `json:"bs"`
|
|
Merkmale []models.Merkmale `json:"merkmale"`
|
|
Erfahrungsschatze []models.Erfahrungsschatz `json:"erfahrungsschatze"`
|
|
Bennies []models.Bennies `json:"bennies"`
|
|
Vermoegen []models.Vermoegen `json:"vermoegen"`
|
|
CharacterCreationSessions []models.CharacterCreationSession `json:"character_creation_sessions"`
|
|
|
|
// Skills
|
|
SkFertigkeiten []models.SkFertigkeit `json:"sk_fertigkeiten"`
|
|
SkWaffenfertigkeiten []models.SkWaffenfertigkeit `json:"sk_waffenfertigkeiten"`
|
|
SkZauber []models.SkZauber `json:"sk_zauber"`
|
|
|
|
// Equipment
|
|
EqAusruestungen []models.EqAusruestung `json:"eq_ausruestungen"`
|
|
EqWaffen []models.EqWaffe `json:"eq_waffen"`
|
|
EqContainers []models.EqContainer `json:"eq_containers"`
|
|
|
|
// GSMaster data
|
|
GsmSkills []models.Skill `json:"gsm_skills"`
|
|
GsmWeaponSkills []models.WeaponSkill `json:"gsm_weapon_skills"`
|
|
GsmSpells []models.Spell `json:"gsm_spells"`
|
|
GsmEquipment []models.Equipment `json:"gsm_equipment"`
|
|
GsmWeapons []models.Weapon `json:"gsm_weapons"`
|
|
GsmContainers []models.Container `json:"gsm_containers"`
|
|
GsmTransportations []models.Transportation `json:"gsm_transportations"`
|
|
GsmBelieves []models.Believe `json:"gsm_believes"`
|
|
|
|
// Learning data
|
|
Sources []models.Source `json:"learning_sources"`
|
|
CharacterClasses []models.CharacterClass `json:"learning_character_classes"`
|
|
SkillCategories []models.SkillCategory `json:"learning_skill_categories"`
|
|
SkillDifficulties []models.SkillDifficulty `json:"learning_skill_difficulties"`
|
|
SpellSchools []models.SpellSchool `json:"learning_spell_schools"`
|
|
ClassCategoryEPCosts []models.ClassCategoryEPCost `json:"learning_class_category_ep_costs"`
|
|
ClassSpellSchoolEPCosts []models.ClassSpellSchoolEPCost `json:"learning_class_spell_school_ep_costs"`
|
|
SpellLevelLECosts []models.SpellLevelLECost `json:"learning_spell_level_le_costs"`
|
|
SkillCategoryDifficulties []models.SkillCategoryDifficulty `json:"learning_skill_category_difficulties"`
|
|
SkillImprovementCosts []models.SkillImprovementCost `json:"learning_skill_improvement_costs"`
|
|
AuditLogEntries []models.AuditLogEntry `json:"audit_log_entries"`
|
|
}
|
|
|
|
// ExportResult contains information about the export operation
|
|
type ExportResult struct {
|
|
Filename string `json:"filename"`
|
|
FilePath string `json:"filepath"`
|
|
RecordCount int `json:"record_count"`
|
|
Timestamp string `json:"timestamp"`
|
|
}
|
|
|
|
// ImportResult contains information about the import operation
|
|
type ImportResult struct {
|
|
RecordCount int `json:"record_count"`
|
|
Timestamp string `json:"timestamp"`
|
|
}
|
|
|
|
// ExportDatabase exports all database content to a JSON file
|
|
func ExportDatabase(exportDir string) (*ExportResult, error) {
|
|
// Create export directory if it doesn't exist
|
|
if err := os.MkdirAll(exportDir, 0755); err != nil {
|
|
return nil, fmt.Errorf("failed to create export directory: %w", err)
|
|
}
|
|
|
|
export := DatabaseExport{
|
|
Version: config.GetVersion(),
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
// Export all tables
|
|
if err := database.DB.Find(&export.Users).Error; err != nil {
|
|
return nil, fmt.Errorf("failed to export users: %w", err)
|
|
}
|
|
|
|
if err := database.DB.Find(&export.Characters).Error; err != nil {
|
|
return nil, fmt.Errorf("failed to export characters: %w", err)
|
|
}
|
|
|
|
database.DB.Find(&export.Eigenschaften)
|
|
database.DB.Find(&export.Lps)
|
|
database.DB.Find(&export.Aps)
|
|
database.DB.Find(&export.Bs)
|
|
database.DB.Find(&export.Merkmale)
|
|
database.DB.Find(&export.Erfahrungsschatze)
|
|
database.DB.Find(&export.Bennies)
|
|
database.DB.Find(&export.Vermoegen)
|
|
database.DB.Find(&export.CharacterCreationSessions)
|
|
|
|
database.DB.Find(&export.SkFertigkeiten)
|
|
database.DB.Find(&export.SkWaffenfertigkeiten)
|
|
database.DB.Find(&export.SkZauber)
|
|
|
|
database.DB.Find(&export.EqAusruestungen)
|
|
database.DB.Find(&export.EqWaffen)
|
|
database.DB.Find(&export.EqContainers)
|
|
|
|
database.DB.Find(&export.GsmSkills)
|
|
database.DB.Find(&export.GsmWeaponSkills)
|
|
database.DB.Find(&export.GsmSpells)
|
|
database.DB.Find(&export.GsmEquipment)
|
|
database.DB.Find(&export.GsmWeapons)
|
|
database.DB.Find(&export.GsmContainers)
|
|
database.DB.Find(&export.GsmTransportations)
|
|
database.DB.Find(&export.GsmBelieves)
|
|
|
|
database.DB.Find(&export.Sources)
|
|
database.DB.Find(&export.CharacterClasses)
|
|
database.DB.Find(&export.SkillCategories)
|
|
database.DB.Find(&export.SkillDifficulties)
|
|
database.DB.Find(&export.SpellSchools)
|
|
database.DB.Find(&export.ClassCategoryEPCosts)
|
|
database.DB.Find(&export.ClassSpellSchoolEPCosts)
|
|
database.DB.Find(&export.SpellLevelLECosts)
|
|
database.DB.Find(&export.SkillCategoryDifficulties)
|
|
database.DB.Find(&export.SkillImprovementCosts)
|
|
database.DB.Find(&export.AuditLogEntries)
|
|
|
|
// Count total records
|
|
recordCount := len(export.Users) + len(export.Characters) +
|
|
len(export.Eigenschaften) + len(export.Lps) + len(export.Aps) +
|
|
len(export.Bs) + len(export.Merkmale) + len(export.Erfahrungsschatze) +
|
|
len(export.Bennies) + len(export.Vermoegen) +
|
|
len(export.SkFertigkeiten) + len(export.SkWaffenfertigkeiten) + len(export.SkZauber) +
|
|
len(export.EqAusruestungen) + len(export.EqWaffen) + len(export.EqContainers) +
|
|
len(export.GsmSkills) + len(export.GsmWeaponSkills) + len(export.GsmSpells) +
|
|
len(export.GsmEquipment) + len(export.GsmWeapons) + len(export.GsmContainers) +
|
|
len(export.GsmTransportations) + len(export.GsmBelieves) +
|
|
len(export.Sources) + len(export.CharacterClasses) + len(export.SkillCategories) +
|
|
len(export.SkillDifficulties) + len(export.SpellSchools) +
|
|
len(export.ClassCategoryEPCosts) + len(export.ClassSpellSchoolEPCosts) +
|
|
len(export.SpellLevelLECosts) + len(export.SkillCategoryDifficulties) +
|
|
len(export.SkillImprovementCosts) + len(export.AuditLogEntries) +
|
|
len(export.CharacterCreationSessions)
|
|
|
|
// Generate filename with timestamp
|
|
filename := fmt.Sprintf("database_export_%s.json", time.Now().Format("20060102_150405"))
|
|
filepath := filepath.Join(exportDir, filename)
|
|
|
|
// Marshal to JSON
|
|
data, err := json.MarshalIndent(export, "", " ")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to marshal export data: %w", err)
|
|
}
|
|
|
|
// Write to file
|
|
if err := os.WriteFile(filepath, data, 0644); err != nil {
|
|
return nil, fmt.Errorf("failed to write export file: %w", err)
|
|
}
|
|
|
|
return &ExportResult{
|
|
Filename: filename,
|
|
FilePath: filepath,
|
|
RecordCount: recordCount,
|
|
Timestamp: time.Now().Format(time.RFC3339),
|
|
}, nil
|
|
}
|
|
|
|
// ImportDatabase imports all database content from a JSON file
|
|
func ImportDatabase(filePath string) (*ImportResult, error) {
|
|
// Read file
|
|
data, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read import file: %w", err)
|
|
}
|
|
|
|
// Unmarshal JSON
|
|
var export DatabaseExport
|
|
if err := json.Unmarshal(data, &export); err != nil {
|
|
return nil, fmt.Errorf("failed to unmarshal import data: %w", err)
|
|
}
|
|
|
|
// Import all tables in transaction
|
|
err = database.DB.Transaction(func(tx *gorm.DB) error {
|
|
// Import users (upsert to handle existing IDs)
|
|
for _, item := range export.Users {
|
|
if err := tx.Save(&item).Error; err != nil {
|
|
return fmt.Errorf("failed to import user: %w", err)
|
|
}
|
|
}
|
|
|
|
// Import characters (upsert)
|
|
for _, item := range export.Characters {
|
|
if err := tx.Save(&item).Error; err != nil {
|
|
return fmt.Errorf("failed to import character: %w", err)
|
|
}
|
|
}
|
|
|
|
// Import character-related data (upsert)
|
|
for _, item := range export.Eigenschaften {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Lps {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Aps {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Bs {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Merkmale {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Erfahrungsschatze {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Bennies {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.Vermoegen {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.CharacterCreationSessions {
|
|
tx.Save(&item)
|
|
}
|
|
|
|
// Import skills
|
|
for _, item := range export.SkFertigkeiten {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SkWaffenfertigkeiten {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SkZauber {
|
|
tx.Save(&item)
|
|
}
|
|
|
|
// Import equipment
|
|
for _, item := range export.EqAusruestungen {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.EqWaffen {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.EqContainers {
|
|
tx.Save(&item)
|
|
}
|
|
|
|
// Import GSMaster data
|
|
for _, item := range export.GsmSkills {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmWeaponSkills {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmSpells {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmEquipment {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmWeapons {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmContainers {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmTransportations {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.GsmBelieves {
|
|
tx.Save(&item)
|
|
}
|
|
|
|
// Import learning data
|
|
for _, item := range export.Sources {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.CharacterClasses {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SkillCategories {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SkillDifficulties {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SpellSchools {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.ClassCategoryEPCosts {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.ClassSpellSchoolEPCosts {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SpellLevelLECosts {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SkillCategoryDifficulties {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.SkillImprovementCosts {
|
|
tx.Save(&item)
|
|
}
|
|
for _, item := range export.AuditLogEntries {
|
|
tx.Save(&item)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
recordCount := len(export.Users) + len(export.Characters) +
|
|
len(export.Eigenschaften) + len(export.Lps) + len(export.Aps) +
|
|
len(export.Bs) + len(export.Merkmale) + len(export.Erfahrungsschatze) +
|
|
len(export.Bennies) + len(export.Vermoegen) +
|
|
len(export.SkFertigkeiten) + len(export.SkWaffenfertigkeiten) + len(export.SkZauber) +
|
|
len(export.EqAusruestungen) + len(export.EqWaffen) + len(export.EqContainers) +
|
|
len(export.GsmSkills) + len(export.GsmWeaponSkills) + len(export.GsmSpells) +
|
|
len(export.GsmEquipment) + len(export.GsmWeapons) + len(export.GsmContainers) +
|
|
len(export.GsmTransportations) + len(export.GsmBelieves) +
|
|
len(export.Sources) + len(export.CharacterClasses) + len(export.SkillCategories) +
|
|
len(export.SkillDifficulties) + len(export.SpellSchools) +
|
|
len(export.ClassCategoryEPCosts) + len(export.ClassSpellSchoolEPCosts) +
|
|
len(export.SpellLevelLECosts) + len(export.SkillCategoryDifficulties) +
|
|
len(export.SkillImprovementCosts) + len(export.AuditLogEntries) +
|
|
len(export.CharacterCreationSessions)
|
|
|
|
return &ImportResult{
|
|
RecordCount: recordCount,
|
|
Timestamp: time.Now().Format(time.RFC3339),
|
|
}, nil
|
|
}
|