fix(migration): make sub project hierarchy work when importing from other services

This commit is contained in:
kolaente 2023-11-08 22:56:10 +01:00
parent 8acc42cb0b
commit 707bb6f89e
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
8 changed files with 518 additions and 485 deletions

View File

@ -261,26 +261,30 @@ func getMicrosoftTodoData(token string) (microsoftTodoData []*project, err error
func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.ProjectWithTasksAndBuckets, err error) { func convertMicrosoftTodoData(todoData []*project) (vikunjsStructure []*models.ProjectWithTasksAndBuckets, err error) {
var pseudoParentID int64 = 1
// One project with all child projects // One project with all child projects
vikunjsStructure = []*models.ProjectWithTasksAndBuckets{ vikunjsStructure = []*models.ProjectWithTasksAndBuckets{
{ {
Project: models.Project{ Project: models.Project{
ID: pseudoParentID,
Title: "Migrated from Microsoft Todo", Title: "Migrated from Microsoft Todo",
}, },
ChildProjects: []*models.ProjectWithTasksAndBuckets{},
}, },
} }
log.Debugf("[Microsoft Todo Migration] Converting %d projects", len(todoData)) 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) log.Debugf("[Microsoft Todo Migration] Converting project %s", l.ID)
// Projects only with title // Projects only with title
project := &models.ProjectWithTasksAndBuckets{ project := &models.ProjectWithTasksAndBuckets{
Project: models.Project{ 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)) 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) log.Debugf("[Microsoft Todo Migration] Done converting project %s", l.ID)
} }

View File

@ -106,78 +106,81 @@ func TestConverting(t *testing.T) {
{ {
Project: models.Project{ Project: models.Project{
Title: "Migrated from Microsoft Todo", 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{ Task: models.Task{
Title: "Project 1", Title: "Task 1",
Description: "This is a description",
}, },
Tasks: []*models.TaskWithComments{ },
{ {
Task: models.Task{ Task: models.Task{
Title: "Task 1", Title: "Task 2",
Description: "This is a description", Done: true,
}, DoneAt: testtimeTime,
}, },
{ },
Task: models.Task{ {
Title: "Task 2", Task: models.Task{
Done: true, Title: "Task 3",
DoneAt: testtimeTime, Priority: 1,
}, },
}, },
{ {
Task: models.Task{ Task: models.Task{
Title: "Task 3", Title: "Task 4",
Priority: 1, Priority: 3,
}, },
}, },
{ {
Task: models.Task{ Task: models.Task{
Title: "Task 4", Title: "Task 5",
Priority: 3, Reminders: []*models.TaskReminder{
}, {
}, Reminder: testtimeTime,
{
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
}, },
}, },
}, },
}, },
{ {
Project: models.Project{ Task: models.Task{
Title: "Project 2", Title: "Task 6",
DueDate: testtimeTime,
}, },
Tasks: []*models.TaskWithComments{ },
{ {
Task: models.Task{ Task: models.Task{
Title: "Task 1", Title: "Task 7",
}, DueDate: testtimeTime,
}, RepeatAfter: 60 * 60 * 24 * 7, // The amount of seconds in a week
{ },
Task: models.Task{ },
Title: "Task 2", },
}, },
}, {
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",
}, },
}, },
}, },

View File

@ -75,20 +75,25 @@ func (date *tickTickTime) UnmarshalCSV(csv string) (err error) {
} }
func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.ProjectWithTasksAndBuckets) { func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.ProjectWithTasksAndBuckets) {
parent := &models.ProjectWithTasksAndBuckets{ var pseudoParentID int64 = 1
Project: models.Project{ result = []*models.ProjectWithTasksAndBuckets{
Title: "Migrated from TickTick", {
Project: models.Project{
ID: pseudoParentID,
Title: "Migrated from TickTick",
},
}, },
ChildProjects: []*models.ProjectWithTasksAndBuckets{},
} }
projects := make(map[string]*models.ProjectWithTasksAndBuckets) projects := make(map[string]*models.ProjectWithTasksAndBuckets)
for _, t := range tasks { for index, t := range tasks {
_, has := projects[t.ProjectName] _, has := projects[t.ProjectName]
if !has { if !has {
projects[t.ProjectName] = &models.ProjectWithTasksAndBuckets{ projects[t.ProjectName] = &models.ProjectWithTasksAndBuckets{
Project: models.Project{ 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 { for _, l := range projects {
parent.ChildProjects = append(parent.ChildProjects, l) result = append(result, l)
} }
sort.Slice(parent.ChildProjects, func(i, j int) bool { sort.Slice(result, func(i, j int) bool {
return parent.ChildProjects[i].Title < parent.ChildProjects[j].Title 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. // Name is used to get the name of the ticktick migration - we're using the docs here to annotate the status route.

View File

@ -86,31 +86,33 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) {
vikunjaTasks := convertTickTickToVikunja(tickTickTasks) vikunjaTasks := convertTickTickToVikunja(tickTickTasks)
assert.Len(t, vikunjaTasks, 1) assert.Len(t, vikunjaTasks, 3)
assert.Len(t, vikunjaTasks[0].ChildProjects, 2)
assert.Len(t, vikunjaTasks[0].ChildProjects[0].Tasks, 3) assert.Equal(t, vikunjaTasks[1].ParentProjectID, vikunjaTasks[0].ID)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Title, tickTickTasks[0].ProjectName) assert.Equal(t, vikunjaTasks[2].ParentProjectID, vikunjaTasks[0].ID)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Title, tickTickTasks[0].Title) assert.Len(t, vikunjaTasks[1].Tasks, 3)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Description, tickTickTasks[0].Content) assert.Equal(t, vikunjaTasks[1].Title, tickTickTasks[0].ProjectName)
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[1].Tasks[0].Title, tickTickTasks[0].Title)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].DueDate, tickTickTasks[0].DueDate.Time) assert.Equal(t, vikunjaTasks[1].Tasks[0].Description, tickTickTasks[0].Content)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Labels, []*models.Label{ 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: "label1"},
{Title: "label2"}, {Title: "label2"},
}) })
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Reminders[0].RelativeTo, models.ReminderRelation("due_date")) assert.Equal(t, vikunjaTasks[1].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[1].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[1].Tasks[0].Position, tickTickTasks[0].Order)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[0].Done, false) 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[1].Tasks[1].Title, tickTickTasks[1].Title)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].Position, tickTickTasks[1].Order) assert.Equal(t, vikunjaTasks[1].Tasks[1].Position, tickTickTasks[1].Order)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].Done, true) assert.Equal(t, vikunjaTasks[1].Tasks[1].Done, true)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[1].DoneAt, tickTickTasks[1].CompletedTime.Time) assert.Equal(t, vikunjaTasks[1].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].RelatedTasks, models.RelatedTaskMap{
models.RelationKindParenttask: []*models.Task{ models.RelationKindParenttask: []*models.Task{
{ {
ID: tickTickTasks[1].ParentID, 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[1].Tasks[2].Title, tickTickTasks[2].Title)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Description, tickTickTasks[2].Content) assert.Equal(t, vikunjaTasks[1].Tasks[2].Description, tickTickTasks[2].Content)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].StartDate, tickTickTasks[2].StartDate.Time) assert.Equal(t, vikunjaTasks[1].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[1].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[1].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].Labels, []*models.Label{
{Title: "label1"}, {Title: "label1"},
{Title: "label2"}, {Title: "label2"},
{Title: "other label"}, {Title: "other label"},
}) })
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Reminders[0].RelativeTo, models.ReminderRelation("due_date")) assert.Equal(t, vikunjaTasks[1].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[1].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[1].Tasks[2].Position, tickTickTasks[2].Order)
assert.Equal(t, vikunjaTasks[0].ChildProjects[0].Tasks[2].Done, false) assert.Equal(t, vikunjaTasks[1].Tasks[2].Done, false)
assert.Len(t, vikunjaTasks[0].ChildProjects[1].Tasks, 1) assert.Len(t, vikunjaTasks[2].Tasks, 1)
assert.Equal(t, vikunjaTasks[0].ChildProjects[1].Title, tickTickTasks[3].ProjectName) 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[2].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].Position, tickTickTasks[3].Order)
} }

View File

@ -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) { func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVikunjaHierachie []*models.ProjectWithTasksAndBuckets, err error) {
var pseudoParentID int64 = 1
parent := &models.ProjectWithTasksAndBuckets{ parent := &models.ProjectWithTasksAndBuckets{
Project: models.Project{ Project: models.Project{
ID: pseudoParentID,
Title: "Migrated from todoist", Title: "Migrated from todoist",
}, },
} }
fullVikunjaHierachie = append(fullVikunjaHierachie, parent)
// A map for all vikunja lists with the project id they're coming from as key // 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)) 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) sections := make(map[string]int64)
for _, p := range sync.Projects { for index, p := range sync.Projects {
project := &models.ProjectWithTasksAndBuckets{ project := &models.ProjectWithTasksAndBuckets{
Project: models.Project{ Project: models.Project{
Title: p.Name, ID: int64(index+1) + pseudoParentID,
HexColor: todoistColors[p.Color], ParentProjectID: pseudoParentID,
IsArchived: p.IsArchived, Title: p.Name,
HexColor: todoistColors[p.Color],
IsArchived: p.IsArchived,
}, },
} }
lists[p.ID] = project lists[p.ID] = project
parent.ChildProjects = append(parent.ChildProjects, project) fullVikunjaHierachie = append(fullVikunjaHierachie, project)
} }
sort.Slice(sync.Sections, func(i, j int) bool { 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) { func getAccessTokenFromAuthToken(authToken string) (accessToken string, err error) {

View File

@ -366,256 +366,261 @@ func TestConvertTodoistToVikunja(t *testing.T) {
expectedHierachie := []*models.ProjectWithTasksAndBuckets{ expectedHierachie := []*models.ProjectWithTasksAndBuckets{
{ {
Project: models.Project{ Project: models.Project{
ID: 1,
Title: "Migrated from todoist", 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{ ID: 1,
Title: "Project1", Title: "Some Bucket",
Description: "Lorem Ipsum dolor sit amet\nLorem Ipsum dolor sit amet 2\nLorem Ipsum dolor sit amet 3", },
HexColor: todoistColors["berry_red"], },
}, Tasks: []*models.TaskWithComments{
Buckets: []*models.Bucket{ {
{ Task: models.Task{
ID: 1, Title: "Task400000000",
Title: "Some Bucket", 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{ Task: models.Task{
Title: "Task400000000", Title: "Task400000001",
Description: "Lorem Ipsum dolor sit amet", Description: "Lorem Ipsum dolor sit amet",
Done: false, Done: false,
Created: time1, 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: "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{ Task: models.Task{
Title: "Project2", Title: "Task400000106",
Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5", Done: true,
HexColor: todoistColors["mint_green"], DueDate: dueTimeWithTime,
Created: time1,
DoneAt: time3,
Labels: vikunjaLabels,
}, },
Tasks: []*models.TaskWithComments{ },
{ {
Task: models.Task{ Task: models.Task{
Title: "Task400000007", Title: "Task400000107",
Done: false, Done: true,
DueDate: dueTime, Created: time1,
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, Task: models.Task{
DueDate: dueTime, Title: "Task400000010",
Created: time1, Description: "Lorem Ipsum dolor sit amet",
}, Done: true,
}, Created: time1,
{ DoneAt: time3,
Task: models.Task{ },
Title: "Task400000009", },
Done: false, {
Created: time1, Task: models.Task{
Reminders: []*models.TaskReminder{ Title: "Task400000101",
{Reminder: time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone())}, 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, 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{ Task: models.Task{
Title: "Project3 - Archived", Title: "Task400000102",
HexColor: todoistColors["mint_green"], Done: false,
IsArchived: true, DueDate: dueTime,
Created: time1,
Labels: vikunjaLabels,
}, },
Tasks: []*models.TaskWithComments{ },
{ {
Task: models.Task{ Task: models.Task{
Title: "Task400000111", Title: "Task400000103",
Done: true, Done: false,
Created: time1, Created: time1,
DoneAt: time3, 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,
}, },
}, },
}, },

View File

@ -166,12 +166,13 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullV
log.Debugf("[Trello Migration] ") log.Debugf("[Trello Migration] ")
var pseudoParentID int64 = 1
fullVikunjaHierachie = []*models.ProjectWithTasksAndBuckets{ fullVikunjaHierachie = []*models.ProjectWithTasksAndBuckets{
{ {
Project: models.Project{ Project: models.Project{
ID: pseudoParentID,
Title: "Imported from Trello", 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)) 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.ProjectWithTasksAndBuckets{
Project: models.Project{ Project: models.Project{
Title: board.Name, ID: int64(index+1) + pseudoParentID,
Description: board.Desc, ParentProjectID: pseudoParentID,
IsArchived: board.Closed, 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) 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 return

View File

@ -190,59 +190,62 @@ func TestConvertTrelloToVikunja(t *testing.T) {
expectedHierachie := []*models.ProjectWithTasksAndBuckets{ expectedHierachie := []*models.ProjectWithTasksAndBuckets{
{ {
Project: models.Project{ Project: models.Project{
ID: 1,
Title: "Imported from Trello", 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{ ID: 1,
Title: "TestBoard", Title: "Test Project 1",
Description: "This is a description", },
BackgroundInformation: bytes.NewBuffer(exampleFile), {
}, ID: 2,
Buckets: []*models.Bucket{ Title: "Test Project 2",
{ },
ID: 1, },
Title: "Test Project 1", 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{
ID: 2, {
Title: "Test Project 2", File: &files.File{
}, Name: "Testimage.jpg",
}, Mime: "image/jpg",
Tasks: []*models.TaskWithComments{ Size: uint64(len(exampleFile)),
{ FileContent: exampleFile,
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,
},
},
}, },
}, },
}, },
{ },
Task: models.Task{ },
Title: "Test Card 2", {
Description: ` Task: models.Task{
Title: "Test Card 2",
Description: `
## Checkproject 1 ## Checkproject 1
@ -253,106 +256,108 @@ func TestConvertTrelloToVikunja(t *testing.T) {
* [ ] Pending Task * [ ] Pending Task
* [ ] Another Pending Task`, * [ ] Another Pending Task`,
BucketID: 1, BucketID: 1,
KanbanPosition: 124, KanbanPosition: 124,
}, },
}, },
{ {
Task: models.Task{ Task: models.Task{
Title: "Test Card 3", Title: "Test Card 3",
BucketID: 1, BucketID: 1,
KanbanPosition: 126, KanbanPosition: 126,
}, },
}, },
{ {
Task: models.Task{ Task: models.Task{
Title: "Test Card 4", Title: "Test Card 4",
BucketID: 1, BucketID: 1,
KanbanPosition: 127, KanbanPosition: 127,
Labels: []*models.Label{ Labels: []*models.Label{
{ {
Title: "Label 2", Title: "Label 2",
HexColor: trelloColorMap["orange"], 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,
}, },
}, },
}, },
}, },
{ {
Project: models.Project{ Task: models.Task{
Title: "TestBoard 2", Title: "Test Card 5",
}, BucketID: 2,
Buckets: []*models.Bucket{ KanbanPosition: 111,
{ Labels: []*models.Label{
ID: 3, {
Title: "Test Project 4", Title: "Label 3",
}, HexColor: trelloColorMap["blue"],
},
Tasks: []*models.TaskWithComments{
{
Task: models.Task{
Title: "Test Card 634",
BucketID: 3,
KanbanPosition: 123,
}, },
}, },
}, },
}, },
{ {
Project: models.Project{ Task: models.Task{
Title: "TestBoard Archived", Title: "Test Card 6",
IsArchived: true, BucketID: 2,
KanbanPosition: 222,
DueDate: time1,
}, },
Buckets: []*models.Bucket{ },
{ {
ID: 4, Task: models.Task{
Title: "Test Project 5", Title: "Test Card 7",
}, BucketID: 2,
KanbanPosition: 333,
}, },
Tasks: []*models.TaskWithComments{ },
{ {
Task: models.Task{ Task: models.Task{
Title: "Test Card 63423", Title: "Test Card 8",
BucketID: 4, BucketID: 2,
KanbanPosition: 123, 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,
}, },
}, },
}, },