feat(migration): use new structure for migration

This commit is contained in:
kolaente 2022-12-29 18:11:15 +01:00
parent 92f0a50996
commit e8e2e205f4
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
8 changed files with 44 additions and 44 deletions

View File

@ -85,6 +85,8 @@ type Project struct {
type ProjectWithTasksAndBuckets struct { type ProjectWithTasksAndBuckets struct {
Project Project
ChildProjects []*ProjectWithTasksAndBuckets `xorm:"-" json:"child_projects"`
// An array of tasks which belong to the project. // An array of tasks which belong to the project.
Tasks []*TaskWithComments `xorm:"-" json:"tasks"` Tasks []*TaskWithComments `xorm:"-" json:"tasks"`
// Only used for migration. // Only used for migration.

View File

@ -127,7 +127,7 @@ func getProjectsToDelete(s *xorm.Session, u *user.User) (projectsToDelete []*Pro
return return
} }
// DeleteUser completely removes a user and all their associated projects, namespaces and tasks. // DeleteUser completely removes a user and all their associated projects and tasks.
// This action is irrevocable. // This action is irrevocable.
// Public to allow deletion from the CLI. // Public to allow deletion from the CLI.
func DeleteUser(s *xorm.Session, u *user.User) (err error) { func DeleteUser(s *xorm.Session, u *user.User) (err error) {

View File

@ -31,7 +31,7 @@ import (
// InsertFromStructure takes a fully nested Vikunja data structure and a user and then creates everything for this user // InsertFromStructure takes a fully nested Vikunja data structure and a user and then creates everything for this user
// (Namespaces, tasks, etc. Even attachments and relations.) // (Namespaces, tasks, etc. Even attachments and relations.)
func InsertFromStructure(str []*models.NamespaceWithProjectsAndTasks, user *user.User) (err error) { func InsertFromStructure(str []*models.ProjectWithTasksAndBuckets, user *user.User) (err error) {
s := db.NewSession() s := db.NewSession()
defer s.Close() defer s.Close()
@ -45,7 +45,7 @@ func InsertFromStructure(str []*models.NamespaceWithProjectsAndTasks, user *user
return s.Commit() return s.Commit()
} }
func insertFromStructure(s *xorm.Session, str []*models.NamespaceWithProjectsAndTasks, user *user.User) (err error) { func insertFromStructure(s *xorm.Session, str []*models.ProjectWithTasksAndBuckets, user *user.User) (err error) {
log.Debugf("[creating structure] Creating %d namespaces", len(str)) log.Debugf("[creating structure] Creating %d namespaces", len(str))
@ -55,30 +55,30 @@ func insertFromStructure(s *xorm.Session, str []*models.NamespaceWithProjectsAnd
archivedNamespaces := []int64{} archivedNamespaces := []int64{}
// Create all namespaces // Create all namespaces
for _, n := range str { for _, p := range str {
n.ID = 0 p.ID = 0
// Saving the archived status to archive the namespace again after creating it // Saving the archived status to archive the namespace again after creating it
var wasArchived bool var wasArchived bool
if n.IsArchived { if p.IsArchived {
n.IsArchived = false p.IsArchived = false
wasArchived = true wasArchived = true
} }
err = n.Create(s, user) err = p.Create(s, user)
if err != nil { if err != nil {
return return
} }
if wasArchived { if wasArchived {
archivedNamespaces = append(archivedNamespaces, n.ID) archivedNamespaces = append(archivedNamespaces, p.ID)
} }
log.Debugf("[creating structure] Created namespace %d", n.ID) log.Debugf("[creating structure] Created project %d", p.ID)
log.Debugf("[creating structure] Creating %d projects", len(n.Projects)) log.Debugf("[creating structure] Creating %d projects", len(p.ChildProjects))
// Create all projects // Create all projects
for _, l := range n.Projects { for _, l := range p.ChildProjects {
// The tasks and bucket slices are going to be reset during the creation of the project so we rescue it here // The tasks and bucket slices are going to be reset during the creation of the project so we rescue it here
// to be able to still loop over them aftere the project was created. // to be able to still loop over them aftere the project was created.
tasks := l.Tasks tasks := l.Tasks
@ -93,7 +93,7 @@ func insertFromStructure(s *xorm.Session, str []*models.NamespaceWithProjectsAnd
l.IsArchived = false l.IsArchived = false
} }
l.NamespaceID = n.ID l.ParentProjectID = p.ID
l.ID = 0 l.ID = 0
err = l.Create(s, user) err = l.Create(s, user)
if err != nil { if err != nil {
@ -291,7 +291,7 @@ func insertFromStructure(s *xorm.Session, str []*models.NamespaceWithProjectsAnd
_, err = s. _, err = s.
Cols("is_archived"). Cols("is_archived").
In("id", archivedNamespaces). In("id", archivedNamespaces).
Update(&models.Namespace{IsArchived: true}) Update(&models.Project{IsArchived: true})
if err != nil { if err != nil {
return err return err
} }

View File

@ -259,15 +259,15 @@ func getMicrosoftTodoData(token string) (microsoftTodoData []*project, err error
return return
} }
func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.NamespaceWithProjectsAndTasks, err error) { func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.ProjectWithTasksAndBuckets, err error) {
// One namespace with all projects // One namespace with all projects
vikunjsStructure = []*models.NamespaceWithProjectsAndTasks{ vikunjsStructure = []*models.ProjectWithTasksAndBuckets{
{ {
Namespace: models.Namespace{ Project: models.Project{
Title: "Migrated from Microsoft Todo", Title: "Migrated from Microsoft Todo",
}, },
Projects: []*models.ProjectWithTasksAndBuckets{}, ChildProjects: []*models.ProjectWithTasksAndBuckets{},
}, },
} }
@ -362,7 +362,7 @@ func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.N
log.Debugf("[Microsoft Todo Migration] Done converted %d tasks", len(l.Tasks)) log.Debugf("[Microsoft Todo Migration] Done converted %d tasks", len(l.Tasks))
} }
vikunjsStructure[0].Projects = append(vikunjsStructure[0].Projects, project) vikunjsStructure[0].ChildProjects = append(vikunjsStructure[0].ChildProjects, project)
log.Debugf("[Microsoft Todo Migration] Done converting project %s", l.ID) log.Debugf("[Microsoft Todo Migration] Done converting project %s", l.ID)
} }

View File

@ -88,12 +88,12 @@ func parseDurationPart(value string, unit time.Duration) time.Duration {
return 0 return 0
} }
func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.NamespaceWithProjectsAndTasks) { func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.ProjectWithTasksAndBuckets) {
namespace := &models.NamespaceWithProjectsAndTasks{ parent := &models.ProjectWithTasksAndBuckets{
Namespace: models.Namespace{ Project: models.Project{
Title: "Migrated from TickTick", Title: "Migrated from TickTick",
}, },
Projects: []*models.ProjectWithTasksAndBuckets{}, ChildProjects: []*models.ProjectWithTasksAndBuckets{},
} }
projects := make(map[string]*models.ProjectWithTasksAndBuckets) projects := make(map[string]*models.ProjectWithTasksAndBuckets)
@ -142,14 +142,14 @@ func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.Namespace
} }
for _, l := range projects { for _, l := range projects {
namespace.Projects = append(namespace.Projects, l) parent.ChildProjects = append(parent.ChildProjects, l)
} }
sort.Slice(namespace.Projects, func(i, j int) bool { sort.Slice(parent.ChildProjects, func(i, j int) bool {
return namespace.Projects[i].Title < namespace.Projects[j].Title return parent.ChildProjects[i].Title < parent.ChildProjects[j].Title
}) })
return []*models.NamespaceWithProjectsAndTasks{namespace} return []*models.ProjectWithTasksAndBuckets{parent}
} }
// Name is used to get the name of the ticktick migration - we're using the docs here to annotate the status route. // Name is used to get the name of the ticktick migration - we're using the docs here to annotate the status route.

View File

@ -251,10 +251,10 @@ func parseDate(dateString string) (date time.Time, err error) {
return date, err return date, err
} }
func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVikunjaHierachie []*models.NamespaceWithProjectsAndTasks, err error) { func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVikunjaHierachie []*models.ProjectWithTasksAndBuckets, err error) {
newNamespace := &models.NamespaceWithProjectsAndTasks{ parent := &models.ProjectWithTasksAndBuckets{
Namespace: models.Namespace{ Project: models.Project{
Title: "Migrated from todoist", Title: "Migrated from todoist",
}, },
} }
@ -281,7 +281,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVi
lists[p.ID] = project lists[p.ID] = project
newNamespace.Projects = append(newNamespace.Projects, project) parent.ChildProjects = append(parent.ChildProjects, project)
} }
sort.Slice(sync.Sections, func(i, j int) bool { sort.Slice(sync.Sections, func(i, j int) bool {
@ -463,9 +463,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVi
tasks[r.ItemID].Reminders = append(tasks[r.ItemID].Reminders, date.In(config.GetTimeZone())) tasks[r.ItemID].Reminders = append(tasks[r.ItemID].Reminders, date.In(config.GetTimeZone()))
} }
return []*models.NamespaceWithProjectsAndTasks{ return []*models.ProjectWithTasksAndBuckets{parent}, err
newNamespace,
}, err
} }
func getAccessTokenFromAuthToken(authToken string) (accessToken string, err error) { func getAccessTokenFromAuthToken(authToken string) (accessToken string, err error) {

View File

@ -144,16 +144,16 @@ func getTrelloData(token string) (trelloData []*trello.Board, err error) {
// Converts all previously obtained data from trello into the vikunja format. // Converts all previously obtained data from trello into the vikunja format.
// `trelloData` should contain all boards with their projects and cards respectively. // `trelloData` should contain all boards with their projects and cards respectively.
func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullVikunjaHierachie []*models.NamespaceWithProjectsAndTasks, err error) { func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullVikunjaHierachie []*models.ProjectWithTasksAndBuckets, err error) {
log.Debugf("[Trello Migration] ") log.Debugf("[Trello Migration] ")
fullVikunjaHierachie = []*models.NamespaceWithProjectsAndTasks{ fullVikunjaHierachie = []*models.ProjectWithTasksAndBuckets{
{ {
Namespace: models.Namespace{ Project: models.Project{
Title: "Imported from Trello", Title: "Imported from Trello",
}, },
Projects: []*models.ProjectWithTasksAndBuckets{}, ChildProjects: []*models.ProjectWithTasksAndBuckets{},
}, },
} }
@ -282,7 +282,7 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullV
log.Debugf("[Trello Migration] Converted all cards to tasks for board %s", board.ID) log.Debugf("[Trello Migration] Converted all cards to tasks for board %s", board.ID)
fullVikunjaHierachie[0].Projects = append(fullVikunjaHierachie[0].Projects, project) fullVikunjaHierachie[0].ChildProjects = append(fullVikunjaHierachie[0].ChildProjects, project)
} }
return return

View File

@ -113,13 +113,13 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
return fmt.Errorf("could not read data file: %w", err) return fmt.Errorf("could not read data file: %w", err)
} }
namespaces := []*models.NamespaceWithProjectsAndTasks{} parent := []*models.ProjectWithTasksAndBuckets{}
if err := json.Unmarshal(bufData.Bytes(), &namespaces); err != nil { if err := json.Unmarshal(bufData.Bytes(), &parent); err != nil {
return fmt.Errorf("could not read data: %w", err) return fmt.Errorf("could not read data: %w", err)
} }
for _, n := range namespaces { for _, n := range parent {
for _, l := range n.Projects { for _, l := range n.ChildProjects {
if b, exists := storedFiles[l.BackgroundFileID]; exists { if b, exists := storedFiles[l.BackgroundFileID]; exists {
bf, err := b.Open() bf, err := b.Open()
if err != nil { if err != nil {
@ -158,7 +158,7 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
} }
} }
err = migration.InsertFromStructure(namespaces, user) err = migration.InsertFromStructure(parent, user)
if err != nil { if err != nil {
return fmt.Errorf("could not insert data: %w", err) return fmt.Errorf("could not insert data: %w", err)
} }