From 707bb6f89e21ecc19884efec92bdebd4e384134b Mon Sep 17 00:00:00 2001 From: kolaente Date: Wed, 8 Nov 2023 22:56:10 +0100 Subject: [PATCH] fix(migration): make sub project hierarchy work when importing from other services --- .../microsoft-todo/microsoft_todo.go | 12 +- .../microsoft-todo/microsoft_todo_test.go | 129 ++--- pkg/modules/migration/ticktick/ticktick.go | 25 +- .../migration/ticktick/ticktick_test.go | 68 +-- pkg/modules/migration/todoist/todoist.go | 18 +- pkg/modules/migration/todoist/todoist_test.go | 463 +++++++++--------- pkg/modules/migration/trello/trello.go | 15 +- pkg/modules/migration/trello/trello_test.go | 273 ++++++----- 8 files changed, 518 insertions(+), 485 deletions(-) diff --git a/pkg/modules/migration/microsoft-todo/microsoft_todo.go b/pkg/modules/migration/microsoft-todo/microsoft_todo.go index 9c34b084db3..838d4f7e26c 100644 --- a/pkg/modules/migration/microsoft-todo/microsoft_todo.go +++ b/pkg/modules/migration/microsoft-todo/microsoft_todo.go @@ -261,26 +261,30 @@ func getMicrosoftTodoData(token string) (microsoftTodoData []*project, err error func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.ProjectWithTasksAndBuckets, err error) { + var pseudoParentID int64 = 1 + // One project with all child projects vikunjsStructure = []*models.ProjectWithTasksAndBuckets{ { Project: models.Project{ + ID: pseudoParentID, Title: "Migrated from Microsoft Todo", }, - ChildProjects: []*models.ProjectWithTasksAndBuckets{}, }, } log.Debugf("[Microsoft Todo Migration] Converting %d projects", len(todoData)) - for _, l := range todoData { + for index, l := range todoData { log.Debugf("[Microsoft Todo Migration] Converting project %s", l.ID) // Projects only with title project := &models.ProjectWithTasksAndBuckets{ Project: models.Project{ - Title: l.DisplayName, + Title: l.DisplayName, + ID: int64(index+1) + pseudoParentID, + ParentProjectID: pseudoParentID, }, } @@ -364,7 +368,7 @@ func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.P log.Debugf("[Microsoft Todo Migration] Done converted %d tasks", len(l.Tasks)) } - vikunjsStructure[0].ChildProjects = append(vikunjsStructure[0].ChildProjects, project) + vikunjsStructure = append(vikunjsStructure, project) log.Debugf("[Microsoft Todo Migration] Done converting project %s", l.ID) } diff --git a/pkg/modules/migration/microsoft-todo/microsoft_todo_test.go b/pkg/modules/migration/microsoft-todo/microsoft_todo_test.go index 216a200d96e..69d55d481eb 100644 --- a/pkg/modules/migration/microsoft-todo/microsoft_todo_test.go +++ b/pkg/modules/migration/microsoft-todo/microsoft_todo_test.go @@ -106,78 +106,81 @@ func TestConverting(t *testing.T) { { Project: models.Project{ Title: "Migrated from Microsoft Todo", + ID: 1, }, - ChildProjects: []*models.ProjectWithTasksAndBuckets{ + }, + { + Project: models.Project{ + ID: 2, + ParentProjectID: 1, + Title: "Project 1", + }, + Tasks: []*models.TaskWithComments{ { - Project: models.Project{ - Title: "Project 1", + Task: models.Task{ + Title: "Task 1", + Description: "This is a description", }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Task 1", - Description: "This is a description", - }, - }, - { - Task: models.Task{ - Title: "Task 2", - Done: true, - DoneAt: testtimeTime, - }, - }, - { - Task: models.Task{ - Title: "Task 3", - Priority: 1, - }, - }, - { - Task: models.Task{ - Title: "Task 4", - Priority: 3, - }, - }, - { - Task: models.Task{ - Title: "Task 5", - Reminders: []*models.TaskReminder{ - { - Reminder: testtimeTime, - }, - }, - }, - }, - { - Task: models.Task{ - Title: "Task 6", - DueDate: testtimeTime, - }, - }, - { - Task: models.Task{ - Title: "Task 7", - DueDate: testtimeTime, - RepeatAfter: 60 * 60 * 24 * 7, // The amount of seconds in a week + }, + { + Task: models.Task{ + Title: "Task 2", + Done: true, + DoneAt: testtimeTime, + }, + }, + { + Task: models.Task{ + Title: "Task 3", + Priority: 1, + }, + }, + { + Task: models.Task{ + Title: "Task 4", + Priority: 3, + }, + }, + { + Task: models.Task{ + Title: "Task 5", + Reminders: []*models.TaskReminder{ + { + Reminder: testtimeTime, }, }, }, }, { - Project: models.Project{ - Title: "Project 2", + Task: models.Task{ + Title: "Task 6", + DueDate: testtimeTime, }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Task 1", - }, - }, - { - Task: models.Task{ - Title: "Task 2", - }, - }, + }, + { + Task: models.Task{ + Title: "Task 7", + DueDate: testtimeTime, + RepeatAfter: 60 * 60 * 24 * 7, // The amount of seconds in a week + }, + }, + }, + }, + { + Project: models.Project{ + Title: "Project 2", + ID: 3, + ParentProjectID: 1, + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Task 1", + }, + }, + { + Task: models.Task{ + Title: "Task 2", }, }, }, diff --git a/pkg/modules/migration/ticktick/ticktick.go b/pkg/modules/migration/ticktick/ticktick.go index d161554bfd9..33a24d97511 100644 --- a/pkg/modules/migration/ticktick/ticktick.go +++ b/pkg/modules/migration/ticktick/ticktick.go @@ -75,20 +75,25 @@ func (date *tickTickTime) UnmarshalCSV(csv string) (err error) { } func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.ProjectWithTasksAndBuckets) { - parent := &models.ProjectWithTasksAndBuckets{ - Project: models.Project{ - Title: "Migrated from TickTick", + var pseudoParentID int64 = 1 + result = []*models.ProjectWithTasksAndBuckets{ + { + Project: models.Project{ + ID: pseudoParentID, + Title: "Migrated from TickTick", + }, }, - ChildProjects: []*models.ProjectWithTasksAndBuckets{}, } projects := make(map[string]*models.ProjectWithTasksAndBuckets) - for _, t := range tasks { + for index, t := range tasks { _, has := projects[t.ProjectName] if !has { projects[t.ProjectName] = &models.ProjectWithTasksAndBuckets{ Project: models.Project{ - Title: t.ProjectName, + ID: int64(index+1) + pseudoParentID, + ParentProjectID: pseudoParentID, + Title: t.ProjectName, }, } } @@ -134,14 +139,14 @@ func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.ProjectWi } for _, l := range projects { - parent.ChildProjects = append(parent.ChildProjects, l) + result = append(result, l) } - sort.Slice(parent.ChildProjects, func(i, j int) bool { - return parent.ChildProjects[i].Title < parent.ChildProjects[j].Title + sort.Slice(result, func(i, j int) bool { + return result[i].Title < result[j].Title }) - return []*models.ProjectWithTasksAndBuckets{parent} + return } // Name is used to get the name of the ticktick migration - we're using the docs here to annotate the status route. diff --git a/pkg/modules/migration/ticktick/ticktick_test.go b/pkg/modules/migration/ticktick/ticktick_test.go index 1e6c7378600..5e9792418f2 100644 --- a/pkg/modules/migration/ticktick/ticktick_test.go +++ b/pkg/modules/migration/ticktick/ticktick_test.go @@ -86,31 +86,33 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) { vikunjaTasks := convertTickTickToVikunja(tickTickTasks) - assert.Len(t, vikunjaTasks, 1) - assert.Len(t, vikunjaTasks[0].ChildProjects, 2) + assert.Len(t, vikunjaTasks, 3) - assert.Len(t, vikunjaTasks[0].ChildProjects[0].Tasks, 3) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Title, tickTickTasks[0].ProjectName) + assert.Equal(t, vikunjaTasks[1].ParentProjectID, vikunjaTasks[0].ID) + assert.Equal(t, vikunjaTasks[2].ParentProjectID, vikunjaTasks[0].ID) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Title, tickTickTasks[0].Title) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Description, tickTickTasks[0].Content) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].StartDate, tickTickTasks[0].StartDate.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].EndDate, tickTickTasks[0].DueDate.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].DueDate, tickTickTasks[0].DueDate.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Labels, []*models.Label{ + assert.Len(t, vikunjaTasks[1].Tasks, 3) + assert.Equal(t, vikunjaTasks[1].Title, tickTickTasks[0].ProjectName) + + assert.Equal(t, vikunjaTasks[1].Tasks[0].Title, tickTickTasks[0].Title) + assert.Equal(t, vikunjaTasks[1].Tasks[0].Description, tickTickTasks[0].Content) + assert.Equal(t, vikunjaTasks[1].Tasks[0].StartDate, tickTickTasks[0].StartDate.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[0].EndDate, tickTickTasks[0].DueDate.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[0].DueDate, tickTickTasks[0].DueDate.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[0].Labels, []*models.Label{ {Title: "label1"}, {Title: "label2"}, }) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Reminders[0].RelativeTo, models.ReminderRelation("due_date")) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Reminders[0].RelativePeriod, int64(-24*3600)) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Position, tickTickTasks[0].Order) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Done, false) + assert.Equal(t, vikunjaTasks[1].Tasks[0].Reminders[0].RelativeTo, models.ReminderRelation("due_date")) + assert.Equal(t, vikunjaTasks[1].Tasks[0].Reminders[0].RelativePeriod, int64(-24*3600)) + assert.Equal(t, vikunjaTasks[1].Tasks[0].Position, tickTickTasks[0].Order) + assert.Equal(t, vikunjaTasks[1].Tasks[0].Done, false) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].Title, tickTickTasks[1].Title) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].Position, tickTickTasks[1].Order) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].Done, true) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].DoneAt, tickTickTasks[1].CompletedTime.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].RelatedTasks, models.RelatedTaskMap{ + assert.Equal(t, vikunjaTasks[1].Tasks[1].Title, tickTickTasks[1].Title) + assert.Equal(t, vikunjaTasks[1].Tasks[1].Position, tickTickTasks[1].Order) + assert.Equal(t, vikunjaTasks[1].Tasks[1].Done, true) + assert.Equal(t, vikunjaTasks[1].Tasks[1].DoneAt, tickTickTasks[1].CompletedTime.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[1].RelatedTasks, models.RelatedTaskMap{ models.RelationKindParenttask: []*models.Task{ { ID: tickTickTasks[1].ParentID, @@ -118,24 +120,24 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) { }, }) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Title, tickTickTasks[2].Title) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Description, tickTickTasks[2].Content) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].StartDate, tickTickTasks[2].StartDate.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].EndDate, tickTickTasks[2].DueDate.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].DueDate, tickTickTasks[2].DueDate.Time) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Labels, []*models.Label{ + assert.Equal(t, vikunjaTasks[1].Tasks[2].Title, tickTickTasks[2].Title) + assert.Equal(t, vikunjaTasks[1].Tasks[2].Description, tickTickTasks[2].Content) + assert.Equal(t, vikunjaTasks[1].Tasks[2].StartDate, tickTickTasks[2].StartDate.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[2].EndDate, tickTickTasks[2].DueDate.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[2].DueDate, tickTickTasks[2].DueDate.Time) + assert.Equal(t, vikunjaTasks[1].Tasks[2].Labels, []*models.Label{ {Title: "label1"}, {Title: "label2"}, {Title: "other label"}, }) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Reminders[0].RelativeTo, models.ReminderRelation("due_date")) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Reminders[0].RelativePeriod, int64(-24*3600)) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Position, tickTickTasks[2].Order) - assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Done, false) + assert.Equal(t, vikunjaTasks[1].Tasks[2].Reminders[0].RelativeTo, models.ReminderRelation("due_date")) + assert.Equal(t, vikunjaTasks[1].Tasks[2].Reminders[0].RelativePeriod, int64(-24*3600)) + assert.Equal(t, vikunjaTasks[1].Tasks[2].Position, tickTickTasks[2].Order) + assert.Equal(t, vikunjaTasks[1].Tasks[2].Done, false) - assert.Len(t, vikunjaTasks[0].ChildProjects[1].Tasks, 1) - assert.Equal(t, vikunjaTasks[0].ChildProjects[1].Title, tickTickTasks[3].ProjectName) + assert.Len(t, vikunjaTasks[2].Tasks, 1) + assert.Equal(t, vikunjaTasks[2].Title, tickTickTasks[3].ProjectName) - assert.Equal(t, vikunjaTasks[0].ChildProjects[1].Tasks[0].Title, tickTickTasks[3].Title) - assert.Equal(t, vikunjaTasks[0].ChildProjects[1].Tasks[0].Position, tickTickTasks[3].Order) + assert.Equal(t, vikunjaTasks[2].Tasks[0].Title, tickTickTasks[3].Title) + assert.Equal(t, vikunjaTasks[2].Tasks[0].Position, tickTickTasks[3].Order) } diff --git a/pkg/modules/migration/todoist/todoist.go b/pkg/modules/migration/todoist/todoist.go index a85f59cbde3..031b4dabae3 100644 --- a/pkg/modules/migration/todoist/todoist.go +++ b/pkg/modules/migration/todoist/todoist.go @@ -247,11 +247,15 @@ func parseDate(dateString string) (date time.Time, err error) { func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVikunjaHierachie []*models.ProjectWithTasksAndBuckets, err error) { + var pseudoParentID int64 = 1 + parent := &models.ProjectWithTasksAndBuckets{ Project: models.Project{ + ID: pseudoParentID, Title: "Migrated from todoist", }, } + fullVikunjaHierachie = append(fullVikunjaHierachie, parent) // A map for all vikunja lists with the project id they're coming from as key lists := make(map[string]*models.ProjectWithTasksAndBuckets, len(sync.Projects)) @@ -264,18 +268,20 @@ func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVi sections := make(map[string]int64) - for _, p := range sync.Projects { + for index, p := range sync.Projects { project := &models.ProjectWithTasksAndBuckets{ Project: models.Project{ - Title: p.Name, - HexColor: todoistColors[p.Color], - IsArchived: p.IsArchived, + ID: int64(index+1) + pseudoParentID, + ParentProjectID: pseudoParentID, + Title: p.Name, + HexColor: todoistColors[p.Color], + IsArchived: p.IsArchived, }, } lists[p.ID] = project - parent.ChildProjects = append(parent.ChildProjects, project) + fullVikunjaHierachie = append(fullVikunjaHierachie, project) } sort.Slice(sync.Sections, func(i, j int) bool { @@ -471,7 +477,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVi ) } - return []*models.ProjectWithTasksAndBuckets{parent}, err + return } func getAccessTokenFromAuthToken(authToken string) (accessToken string, err error) { diff --git a/pkg/modules/migration/todoist/todoist_test.go b/pkg/modules/migration/todoist/todoist_test.go index 27df2b74587..1fa145dcea2 100644 --- a/pkg/modules/migration/todoist/todoist_test.go +++ b/pkg/modules/migration/todoist/todoist_test.go @@ -366,256 +366,261 @@ func TestConvertTodoistToVikunja(t *testing.T) { expectedHierachie := []*models.ProjectWithTasksAndBuckets{ { Project: models.Project{ + ID: 1, Title: "Migrated from todoist", }, - ChildProjects: []*models.ProjectWithTasksAndBuckets{ + }, + { + Project: models.Project{ + ID: 2, + ParentProjectID: 1, + Title: "Project1", + Description: "Lorem Ipsum dolor sit amet\nLorem Ipsum dolor sit amet 2\nLorem Ipsum dolor sit amet 3", + HexColor: todoistColors["berry_red"], + }, + Buckets: []*models.Bucket{ { - Project: models.Project{ - Title: "Project1", - Description: "Lorem Ipsum dolor sit amet\nLorem Ipsum dolor sit amet 2\nLorem Ipsum dolor sit amet 3", - HexColor: todoistColors["berry_red"], - }, - Buckets: []*models.Bucket{ - { - ID: 1, - Title: "Some Bucket", + ID: 1, + Title: "Some Bucket", + }, + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Task400000000", + Description: "Lorem Ipsum dolor sit amet", + Done: false, + Created: time1, + Reminders: []*models.TaskReminder{ + {Reminder: time.Date(2020, time.June, 15, 23, 59, 0, 0, time.UTC).In(config.GetTimeZone())}, + {Reminder: time.Date(2020, time.June, 16, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, }, }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Task400000000", - Description: "Lorem Ipsum dolor sit amet", - Done: false, - Created: time1, - Reminders: []*models.TaskReminder{ - {Reminder: time.Date(2020, time.June, 15, 23, 59, 0, 0, time.UTC).In(config.GetTimeZone())}, - {Reminder: time.Date(2020, time.June, 16, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, + }, + { + Task: models.Task{ + Title: "Task400000001", + Description: "Lorem Ipsum dolor sit amet", + Done: false, + Created: time1, + }, + }, + { + Task: models.Task{ + Title: "Task400000002", + Done: false, + Created: time1, + Reminders: []*models.TaskReminder{ + {Reminder: time.Date(2020, time.July, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, + }, + }, + }, + { + Task: models.Task{ + Title: "Task400000003", + Description: "Lorem Ipsum dolor sit amet", + Done: true, + DueDate: dueTime, + Created: time1, + DoneAt: time3, + Labels: vikunjaLabels, + Reminders: []*models.TaskReminder{ + {Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, + }, + }, + }, + { + Task: models.Task{ + Title: "Task400000004", + Done: false, + Created: time1, + Labels: vikunjaLabels, + }, + }, + { + Task: models.Task{ + Title: "Task400000005", + Done: true, + DueDate: dueTime, + Created: time1, + DoneAt: time3, + Reminders: []*models.TaskReminder{ + {Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, + }, + }, + }, + { + Task: models.Task{ + Title: "Task400000006", + Done: true, + DueDate: dueTime, + Created: time1, + DoneAt: time3, + RelatedTasks: map[models.RelationKind][]*models.Task{ + models.RelationKindSubtask: { + { + Title: "Task with parent", + Done: false, + Priority: 2, + Created: time1, + DoneAt: nilTime, }, }, }, - { - Task: models.Task{ - Title: "Task400000001", - Description: "Lorem Ipsum dolor sit amet", - Done: false, - Created: time1, - }, - }, - { - Task: models.Task{ - Title: "Task400000002", - Done: false, - Created: time1, - Reminders: []*models.TaskReminder{ - {Reminder: time.Date(2020, time.July, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, - }, - }, - }, - { - Task: models.Task{ - Title: "Task400000003", - Description: "Lorem Ipsum dolor sit amet", - Done: true, - DueDate: dueTime, - Created: time1, - DoneAt: time3, - Labels: vikunjaLabels, - Reminders: []*models.TaskReminder{ - {Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, - }, - }, - }, - { - Task: models.Task{ - Title: "Task400000004", - Done: false, - Created: time1, - Labels: vikunjaLabels, - }, - }, - { - Task: models.Task{ - Title: "Task400000005", - Done: true, - DueDate: dueTime, - Created: time1, - DoneAt: time3, - Reminders: []*models.TaskReminder{ - {Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, - }, - }, - }, - { - Task: models.Task{ - Title: "Task400000006", - Done: true, - DueDate: dueTime, - Created: time1, - DoneAt: time3, - RelatedTasks: map[models.RelationKind][]*models.Task{ - models.RelationKindSubtask: { - { - Title: "Task with parent", - Done: false, - Priority: 2, - Created: time1, - DoneAt: nilTime, - }, - }, - }, - }, - }, - { - Task: models.Task{ - Title: "Task400000106", - Done: true, - DueDate: dueTimeWithTime, - Created: time1, - DoneAt: time3, - Labels: vikunjaLabels, - }, - }, - { - Task: models.Task{ - Title: "Task400000107", - Done: true, - Created: time1, - DoneAt: time3, - }, - }, - { - Task: models.Task{ - Title: "Task400000108", - Done: true, - Created: time1, - DoneAt: time3, - }, - }, - { - Task: models.Task{ - Title: "Task400000109", - Done: true, - Created: time1, - DoneAt: time3, - BucketID: 1, - }, - }, }, }, { - Project: models.Project{ - Title: "Project2", - Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5", - HexColor: todoistColors["mint_green"], + Task: models.Task{ + Title: "Task400000106", + Done: true, + DueDate: dueTimeWithTime, + Created: time1, + DoneAt: time3, + Labels: vikunjaLabels, }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Task400000007", - Done: false, - DueDate: dueTime, - Created: time1, - }, + }, + { + Task: models.Task{ + Title: "Task400000107", + Done: true, + Created: time1, + DoneAt: time3, + }, + }, + { + Task: models.Task{ + Title: "Task400000108", + Done: true, + Created: time1, + DoneAt: time3, + }, + }, + { + Task: models.Task{ + Title: "Task400000109", + Done: true, + Created: time1, + DoneAt: time3, + BucketID: 1, + }, + }, + }, + }, + { + Project: models.Project{ + ID: 3, + ParentProjectID: 1, + Title: "Project2", + Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5", + HexColor: todoistColors["mint_green"], + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Task400000007", + Done: false, + DueDate: dueTime, + Created: time1, + }, + }, + { + Task: models.Task{ + Title: "Task400000008", + Done: false, + DueDate: dueTime, + Created: time1, + }, + }, + { + Task: models.Task{ + Title: "Task400000009", + Done: false, + Created: time1, + Reminders: []*models.TaskReminder{ + {Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, }, - { - Task: models.Task{ - Title: "Task400000008", - Done: false, - DueDate: dueTime, - Created: time1, - }, - }, - { - Task: models.Task{ - Title: "Task400000009", - Done: false, - Created: time1, - Reminders: []*models.TaskReminder{ - {Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, + }, + }, + { + Task: models.Task{ + Title: "Task400000010", + Description: "Lorem Ipsum dolor sit amet", + Done: true, + Created: time1, + DoneAt: time3, + }, + }, + { + Task: models.Task{ + Title: "Task400000101", + Description: "Lorem Ipsum dolor sit amet", + Done: false, + Created: time1, + Attachments: []*models.TaskAttachment{ + { + File: &files.File{ + Name: "file.md", + Mime: "text/plain", + Size: 12345, + Created: time1, + FileContent: exampleFile, }, - }, - }, - { - Task: models.Task{ - Title: "Task400000010", - Description: "Lorem Ipsum dolor sit amet", - Done: true, - Created: time1, - DoneAt: time3, - }, - }, - { - Task: models.Task{ - Title: "Task400000101", - Description: "Lorem Ipsum dolor sit amet", - Done: false, - Created: time1, - Attachments: []*models.TaskAttachment{ - { - File: &files.File{ - Name: "file.md", - Mime: "text/plain", - Size: 12345, - Created: time1, - FileContent: exampleFile, - }, - Created: time1, - }, - }, - }, - }, - { - Task: models.Task{ - Title: "Task400000102", - Done: false, - DueDate: dueTime, Created: time1, - Labels: vikunjaLabels, - }, - }, - { - Task: models.Task{ - Title: "Task400000103", - Done: false, - Created: time1, - Labels: vikunjaLabels, - }, - }, - { - Task: models.Task{ - Title: "Task400000104", - Done: false, - Created: time1, - Labels: vikunjaLabels, - }, - }, - { - Task: models.Task{ - Title: "Task400000105", - Done: false, - DueDate: dueTime, - Created: time1, - Labels: vikunjaLabels, }, }, }, }, { - Project: models.Project{ - Title: "Project3 - Archived", - HexColor: todoistColors["mint_green"], - IsArchived: true, + Task: models.Task{ + Title: "Task400000102", + Done: false, + DueDate: dueTime, + Created: time1, + Labels: vikunjaLabels, }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Task400000111", - Done: true, - Created: time1, - DoneAt: time3, - }, - }, + }, + { + Task: models.Task{ + Title: "Task400000103", + Done: false, + Created: time1, + Labels: vikunjaLabels, + }, + }, + { + Task: models.Task{ + Title: "Task400000104", + Done: false, + Created: time1, + Labels: vikunjaLabels, + }, + }, + { + Task: models.Task{ + Title: "Task400000105", + Done: false, + DueDate: dueTime, + Created: time1, + Labels: vikunjaLabels, + }, + }, + }, + }, + { + Project: models.Project{ + ID: 4, + ParentProjectID: 1, + Title: "Project3 - Archived", + HexColor: todoistColors["mint_green"], + IsArchived: true, + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Task400000111", + Done: true, + Created: time1, + DoneAt: time3, }, }, }, diff --git a/pkg/modules/migration/trello/trello.go b/pkg/modules/migration/trello/trello.go index 01527725e6a..3ff89486299 100644 --- a/pkg/modules/migration/trello/trello.go +++ b/pkg/modules/migration/trello/trello.go @@ -166,12 +166,13 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullV log.Debugf("[Trello Migration] ") + var pseudoParentID int64 = 1 fullVikunjaHierachie = []*models.ProjectWithTasksAndBuckets{ { Project: models.Project{ + ID: pseudoParentID, Title: "Imported from Trello", }, - ChildProjects: []*models.ProjectWithTasksAndBuckets{}, }, } @@ -179,12 +180,14 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullV log.Debugf("[Trello Migration] Converting %d boards to vikunja projects", len(trelloData)) - for _, board := range trelloData { + for index, board := range trelloData { project := &models.ProjectWithTasksAndBuckets{ Project: models.Project{ - Title: board.Name, - Description: board.Desc, - IsArchived: board.Closed, + ID: int64(index+1) + pseudoParentID, + ParentProjectID: pseudoParentID, + Title: board.Name, + Description: board.Desc, + IsArchived: board.Closed, }, } @@ -300,7 +303,7 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullV log.Debugf("[Trello Migration] Converted all cards to tasks for board %s", board.ID) - fullVikunjaHierachie[0].ChildProjects = append(fullVikunjaHierachie[0].ChildProjects, project) + fullVikunjaHierachie = append(fullVikunjaHierachie, project) } return diff --git a/pkg/modules/migration/trello/trello_test.go b/pkg/modules/migration/trello/trello_test.go index 0eb7f8a3d3d..32201b095d1 100644 --- a/pkg/modules/migration/trello/trello_test.go +++ b/pkg/modules/migration/trello/trello_test.go @@ -190,59 +190,62 @@ func TestConvertTrelloToVikunja(t *testing.T) { expectedHierachie := []*models.ProjectWithTasksAndBuckets{ { Project: models.Project{ + ID: 1, Title: "Imported from Trello", }, - ChildProjects: []*models.ProjectWithTasksAndBuckets{ + }, + { + Project: models.Project{ + ID: 2, + ParentProjectID: 1, + Title: "TestBoard", + Description: "This is a description", + BackgroundInformation: bytes.NewBuffer(exampleFile), + }, + Buckets: []*models.Bucket{ { - Project: models.Project{ - Title: "TestBoard", - Description: "This is a description", - BackgroundInformation: bytes.NewBuffer(exampleFile), - }, - Buckets: []*models.Bucket{ - { - ID: 1, - Title: "Test Project 1", + ID: 1, + Title: "Test Project 1", + }, + { + ID: 2, + Title: "Test Project 2", + }, + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Test Card 1", + Description: "Card Description", + BucketID: 1, + KanbanPosition: 123, + DueDate: time1, + Labels: []*models.Label{ + { + Title: "Label 1", + HexColor: trelloColorMap["green"], + }, + { + Title: "Label 2", + HexColor: trelloColorMap["orange"], + }, }, - { - ID: 2, - Title: "Test Project 2", - }, - }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Test Card 1", - Description: "Card Description", - BucketID: 1, - KanbanPosition: 123, - DueDate: time1, - Labels: []*models.Label{ - { - Title: "Label 1", - HexColor: trelloColorMap["green"], - }, - { - Title: "Label 2", - HexColor: trelloColorMap["orange"], - }, - }, - Attachments: []*models.TaskAttachment{ - { - File: &files.File{ - Name: "Testimage.jpg", - Mime: "image/jpg", - Size: uint64(len(exampleFile)), - FileContent: exampleFile, - }, - }, + Attachments: []*models.TaskAttachment{ + { + File: &files.File{ + Name: "Testimage.jpg", + Mime: "image/jpg", + Size: uint64(len(exampleFile)), + FileContent: exampleFile, }, }, }, - { - Task: models.Task{ - Title: "Test Card 2", - Description: ` + }, + }, + { + Task: models.Task{ + Title: "Test Card 2", + Description: ` ## Checkproject 1 @@ -253,106 +256,108 @@ func TestConvertTrelloToVikunja(t *testing.T) { * [ ] Pending Task * [ ] Another Pending Task`, - BucketID: 1, - KanbanPosition: 124, - }, - }, - { - Task: models.Task{ - Title: "Test Card 3", - BucketID: 1, - KanbanPosition: 126, - }, - }, - { - Task: models.Task{ - Title: "Test Card 4", - BucketID: 1, - KanbanPosition: 127, - Labels: []*models.Label{ - { - Title: "Label 2", - HexColor: trelloColorMap["orange"], - }, - }, - }, - }, - { - Task: models.Task{ - Title: "Test Card 5", - BucketID: 2, - KanbanPosition: 111, - Labels: []*models.Label{ - { - Title: "Label 3", - HexColor: trelloColorMap["blue"], - }, - }, - }, - }, - { - Task: models.Task{ - Title: "Test Card 6", - BucketID: 2, - KanbanPosition: 222, - DueDate: time1, - }, - }, - { - Task: models.Task{ - Title: "Test Card 7", - BucketID: 2, - KanbanPosition: 333, - }, - }, - { - Task: models.Task{ - Title: "Test Card 8", - BucketID: 2, - KanbanPosition: 444, + BucketID: 1, + KanbanPosition: 124, + }, + }, + { + Task: models.Task{ + Title: "Test Card 3", + BucketID: 1, + KanbanPosition: 126, + }, + }, + { + Task: models.Task{ + Title: "Test Card 4", + BucketID: 1, + KanbanPosition: 127, + Labels: []*models.Label{ + { + Title: "Label 2", + HexColor: trelloColorMap["orange"], }, }, }, }, { - Project: models.Project{ - Title: "TestBoard 2", - }, - Buckets: []*models.Bucket{ - { - ID: 3, - Title: "Test Project 4", - }, - }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Test Card 634", - BucketID: 3, - KanbanPosition: 123, + Task: models.Task{ + Title: "Test Card 5", + BucketID: 2, + KanbanPosition: 111, + Labels: []*models.Label{ + { + Title: "Label 3", + HexColor: trelloColorMap["blue"], }, }, }, }, { - Project: models.Project{ - Title: "TestBoard Archived", - IsArchived: true, + Task: models.Task{ + Title: "Test Card 6", + BucketID: 2, + KanbanPosition: 222, + DueDate: time1, }, - Buckets: []*models.Bucket{ - { - ID: 4, - Title: "Test Project 5", - }, + }, + { + Task: models.Task{ + Title: "Test Card 7", + BucketID: 2, + KanbanPosition: 333, }, - Tasks: []*models.TaskWithComments{ - { - Task: models.Task{ - Title: "Test Card 63423", - BucketID: 4, - KanbanPosition: 123, - }, - }, + }, + { + Task: models.Task{ + Title: "Test Card 8", + BucketID: 2, + KanbanPosition: 444, + }, + }, + }, + }, + { + Project: models.Project{ + ID: 3, + ParentProjectID: 1, + Title: "TestBoard 2", + }, + Buckets: []*models.Bucket{ + { + ID: 3, + Title: "Test Project 4", + }, + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Test Card 634", + BucketID: 3, + KanbanPosition: 123, + }, + }, + }, + }, + { + Project: models.Project{ + ID: 4, + ParentProjectID: 1, + Title: "TestBoard Archived", + IsArchived: true, + }, + Buckets: []*models.Bucket{ + { + ID: 4, + Title: "Test Project 5", + }, + }, + Tasks: []*models.TaskWithComments{ + { + Task: models.Task{ + Title: "Test Card 63423", + BucketID: 4, + KanbanPosition: 123, }, }, },