fix(migration): use Todoist v9 api to migrate tasks from them
Discussion: https://community.vikunja.io/t/importing-tasks-from-todoist/322/7
This commit is contained in:
parent
a79b1de2d0
commit
6a97a214a3
@ -45,28 +45,25 @@ type apiTokenResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type label struct {
|
type label struct {
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Color int64 `json:"color"`
|
Color string `json:"color"`
|
||||||
ItemOrder int64 `json:"item_order"`
|
ItemOrder int64 `json:"item_order"`
|
||||||
IsDeleted int64 `json:"is_deleted"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
IsFavorite int64 `json:"is_favorite"`
|
IsFavorite bool `json:"is_favorite"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type project struct {
|
type project struct {
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
LegacyID int64 `json:"legacy_id"`
|
Name string `json:"name"`
|
||||||
Name string `json:"name"`
|
Color string `json:"color"`
|
||||||
Color int64 `json:"color"`
|
ParentID string `json:"parent_id"`
|
||||||
ParentID int64 `json:"parent_id"`
|
ChildOrder int64 `json:"child_order"`
|
||||||
ChildOrder int64 `json:"child_order"`
|
Collapsed bool `json:"collapsed"`
|
||||||
Collapsed int64 `json:"collapsed"`
|
Shared bool `json:"shared"`
|
||||||
Shared bool `json:"shared"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
LegacyParentID int64 `json:"legacy_parent_id"`
|
IsArchived bool `json:"is_archived"`
|
||||||
SyncID int64 `json:"sync_id"`
|
IsFavorite bool `json:"is_favorite"`
|
||||||
IsDeleted int64 `json:"is_deleted"`
|
|
||||||
IsArchived int64 `json:"is_archived"`
|
|
||||||
IsFavorite int64 `json:"is_favorite"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type dueDate struct {
|
type dueDate struct {
|
||||||
@ -78,31 +75,26 @@ type dueDate struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type item struct {
|
type item struct {
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
LegacyID int64 `json:"legacy_id"`
|
LegacyID string `json:"legacy_id"`
|
||||||
UserID int64 `json:"user_id"`
|
UserID string `json:"user_id"`
|
||||||
ProjectID int64 `json:"project_id"`
|
ProjectID string `json:"project_id"`
|
||||||
LegacyProjectID int64 `json:"legacy_project_id"`
|
Content string `json:"content"`
|
||||||
Content string `json:"content"`
|
Priority int64 `json:"priority"`
|
||||||
Priority int64 `json:"priority"`
|
Due *dueDate `json:"due"`
|
||||||
Due *dueDate `json:"due"`
|
ParentID string `json:"parent_id"`
|
||||||
ParentID int64 `json:"parent_id"`
|
ChildOrder int64 `json:"child_order"`
|
||||||
LegacyParentID int64 `json:"legacy_parent_id"`
|
SectionID string `json:"section_id"`
|
||||||
ChildOrder int64 `json:"child_order"`
|
Children interface{} `json:"children"`
|
||||||
SectionID int64 `json:"section_id"`
|
Labels []string `json:"labels"`
|
||||||
DayOrder int64 `json:"day_order"`
|
AddedByUID string `json:"added_by_uid"`
|
||||||
Collapsed int64 `json:"collapsed"`
|
AssignedByUID string `json:"assigned_by_uid"`
|
||||||
Children interface{} `json:"children"`
|
ResponsibleUID string `json:"responsible_uid"`
|
||||||
Labels []int64 `json:"labels"`
|
Checked bool `json:"checked"`
|
||||||
AddedByUID int64 `json:"added_by_uid"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
AssignedByUID int64 `json:"assigned_by_uid"`
|
DateAdded time.Time `json:"added_at"`
|
||||||
ResponsibleUID int64 `json:"responsible_uid"`
|
HasMoreNotes bool `json:"has_more_notes"`
|
||||||
Checked int64 `json:"checked"`
|
DateCompleted time.Time `json:"completed_at"`
|
||||||
InHistory int64 `json:"in_history"`
|
|
||||||
IsDeleted int64 `json:"is_deleted"`
|
|
||||||
DateAdded time.Time `json:"date_added"`
|
|
||||||
HasMoreNotes bool `json:"has_more_notes"`
|
|
||||||
DateCompleted time.Time `json:"date_completed"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type itemWrapper struct {
|
type itemWrapper struct {
|
||||||
@ -110,12 +102,11 @@ type itemWrapper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type doneItem struct {
|
type doneItem struct {
|
||||||
CompletedDate time.Time `json:"completed_date"`
|
CompletedDate time.Time `json:"completed_at"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
ProjectID int64 `json:"project_id"`
|
ProjectID string `json:"project_id"`
|
||||||
TaskID int64 `json:"task_id"`
|
TaskID string `json:"task_id"`
|
||||||
UserID int `json:"user_id"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type doneItemSync struct {
|
type doneItemSync struct {
|
||||||
@ -132,18 +123,14 @@ type fileAttachment struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type note struct {
|
type note struct {
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
LegacyID int64 `json:"legacy_id"`
|
PostedUID int64 `json:"posted_uid"`
|
||||||
PostedUID int64 `json:"posted_uid"`
|
ProjectID string `json:"project_id"`
|
||||||
ProjectID int64 `json:"project_id"`
|
ItemID string `json:"item_id"`
|
||||||
LegacyProjectID int64 `json:"legacy_project_id"`
|
Content string `json:"content"`
|
||||||
ItemID int64 `json:"item_id"`
|
FileAttachment *fileAttachment `json:"file_attachment"`
|
||||||
LegacyItemID int64 `json:"legacy_item_id"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
Content string `json:"content"`
|
Posted time.Time `json:"posted_at"`
|
||||||
FileAttachment *fileAttachment `json:"file_attachment"`
|
|
||||||
UidsToNotify []int64 `json:"uids_to_notify"`
|
|
||||||
IsDeleted int64 `json:"is_deleted"`
|
|
||||||
Posted time.Time `json:"posted"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type projectNote struct {
|
type projectNote struct {
|
||||||
@ -153,15 +140,13 @@ type projectNote struct {
|
|||||||
IsDeleted int64 `json:"is_deleted"`
|
IsDeleted int64 `json:"is_deleted"`
|
||||||
Posted time.Time `json:"posted"`
|
Posted time.Time `json:"posted"`
|
||||||
PostedUID int64 `json:"posted_uid"`
|
PostedUID int64 `json:"posted_uid"`
|
||||||
ProjectID int64 `json:"project_id"`
|
ProjectID string `json:"project_id"`
|
||||||
UidsToNotify []int64 `json:"uids_to_notify"`
|
UidsToNotify []int64 `json:"uids_to_notify"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type reminder struct {
|
type reminder struct {
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
NotifyUID int64 `json:"notify_uid"`
|
ItemID string `json:"item_id"`
|
||||||
ItemID int64 `json:"item_id"`
|
|
||||||
Service string `json:"service"`
|
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Due *dueDate `json:"due"`
|
Due *dueDate `json:"due"`
|
||||||
MmOffset int64 `json:"mm_offset"`
|
MmOffset int64 `json:"mm_offset"`
|
||||||
@ -169,11 +154,11 @@ type reminder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type section struct {
|
type section struct {
|
||||||
ID int64 `json:"id"`
|
ID string `json:"id"`
|
||||||
DateAdded time.Time `json:"date_added"`
|
DateAdded time.Time `json:"added_at"`
|
||||||
IsDeleted bool `json:"is_deleted"`
|
IsDeleted bool `json:"is_deleted"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ProjectID int64 `json:"project_id"`
|
ProjectID string `json:"project_id"`
|
||||||
SectionOrder int64 `json:"section_order"`
|
SectionOrder int64 `json:"section_order"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,32 +172,32 @@ type sync struct {
|
|||||||
Sections []*section `json:"sections"`
|
Sections []*section `json:"sections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var todoistColors = map[int64]string{}
|
var todoistColors = map[string]string{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
todoistColors = make(map[int64]string, 19)
|
todoistColors = make(map[string]string, 19)
|
||||||
// The todoists colors are static, taken from https://developer.todoist.com/sync/v8/#colors
|
// The todoists colors are static, taken from https://developer.todoist.com/guides/#colors
|
||||||
todoistColors = map[int64]string{
|
todoistColors = map[string]string{
|
||||||
30: "b8256f",
|
"berry_red": "b8256f",
|
||||||
31: "db4035",
|
"red": "db4035",
|
||||||
32: "ff9933",
|
"orange": "ff9933",
|
||||||
33: "fad000",
|
"yellow": "fad000",
|
||||||
34: "afb83b",
|
"olive_green": "afb83b",
|
||||||
35: "7ecc49",
|
"lime_green": "7ecc49",
|
||||||
36: "299438",
|
"green": "299438",
|
||||||
37: "6accbc",
|
"mint_green": "6accbc",
|
||||||
38: "158fad",
|
"teal": "158fad",
|
||||||
39: "14aaf5",
|
"sky_blue": "14aaf5",
|
||||||
40: "96c3eb",
|
"light_blue": "96c3eb",
|
||||||
41: "4073ff",
|
"blue": "4073ff",
|
||||||
42: "884dff",
|
"grape": "884dff",
|
||||||
43: "af38eb",
|
"violet": "af38eb",
|
||||||
44: "eb96eb",
|
"lavender": "eb96eb",
|
||||||
45: "e05194",
|
"magenta": "e05194",
|
||||||
46: "ff8d85",
|
"salmon": "ff8d85",
|
||||||
47: "808080",
|
"charcoal": "808080",
|
||||||
48: "b8b8b8",
|
"grey": "b8b8b8",
|
||||||
49: "ccac93",
|
"taupe": "ccac93",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +251,7 @@ func parseDate(dateString string) (date time.Time, err error) {
|
|||||||
return date, err
|
return date, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVikunjaHierachie []*models.NamespaceWithListsAndTasks, err error) {
|
func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVikunjaHierachie []*models.NamespaceWithListsAndTasks, err error) {
|
||||||
|
|
||||||
newNamespace := &models.NamespaceWithListsAndTasks{
|
newNamespace := &models.NamespaceWithListsAndTasks{
|
||||||
Namespace: models.Namespace{
|
Namespace: models.Namespace{
|
||||||
@ -275,20 +260,22 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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[int64]*models.ListWithTasksAndBuckets, len(sync.Projects))
|
lists := make(map[string]*models.ListWithTasksAndBuckets, len(sync.Projects))
|
||||||
|
|
||||||
// A map for all vikunja tasks with the todoist task id as key to find them easily and add more data
|
// A map for all vikunja tasks with the todoist task id as key to find them easily and add more data
|
||||||
tasks := make(map[int64]*models.TaskWithComments, len(sync.Items))
|
tasks := make(map[string]*models.TaskWithComments, len(sync.Items))
|
||||||
|
|
||||||
// A map for all vikunja labels with the todoist id as key to find them easier
|
// A map for all vikunja labels with the todoist id as key to find them easier
|
||||||
labels := make(map[int64]*models.Label, len(sync.Labels))
|
labels := make(map[string]*models.Label, len(sync.Labels))
|
||||||
|
|
||||||
|
sections := make(map[string]int64)
|
||||||
|
|
||||||
for _, p := range sync.Projects {
|
for _, p := range sync.Projects {
|
||||||
list := &models.ListWithTasksAndBuckets{
|
list := &models.ListWithTasksAndBuckets{
|
||||||
List: models.List{
|
List: models.List{
|
||||||
Title: p.Name,
|
Title: p.Name,
|
||||||
HexColor: todoistColors[p.Color],
|
HexColor: todoistColors[p.Color],
|
||||||
IsArchived: p.IsArchived == 1,
|
IsArchived: p.IsArchived,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,20 +288,22 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||||||
return sync.Sections[i].SectionOrder < sync.Sections[j].SectionOrder
|
return sync.Sections[i].SectionOrder < sync.Sections[j].SectionOrder
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var fabricatedSectionID int64 = 1
|
||||||
for _, section := range sync.Sections {
|
for _, section := range sync.Sections {
|
||||||
if section.IsDeleted || section.ProjectID == 0 {
|
if section.IsDeleted || section.ProjectID == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lists[section.ProjectID].Buckets = append(lists[section.ProjectID].Buckets, &models.Bucket{
|
lists[section.ProjectID].Buckets = append(lists[section.ProjectID].Buckets, &models.Bucket{
|
||||||
ID: section.ID,
|
ID: fabricatedSectionID,
|
||||||
Title: section.Name,
|
Title: section.Name,
|
||||||
Created: section.DateAdded,
|
Created: section.DateAdded,
|
||||||
})
|
})
|
||||||
|
sections[section.ID] = fabricatedSectionID
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, label := range sync.Labels {
|
for _, label := range sync.Labels {
|
||||||
labels[label.ID] = &models.Label{
|
labels[label.Name] = &models.Label{
|
||||||
Title: label.Name,
|
Title: label.Name,
|
||||||
HexColor: todoistColors[label.Color],
|
HexColor: todoistColors[label.Color],
|
||||||
}
|
}
|
||||||
@ -325,8 +314,8 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||||||
Task: models.Task{
|
Task: models.Task{
|
||||||
Title: i.Content,
|
Title: i.Content,
|
||||||
Created: i.DateAdded.In(config.GetTimeZone()),
|
Created: i.DateAdded.In(config.GetTimeZone()),
|
||||||
Done: i.Checked == 1,
|
Done: i.Checked,
|
||||||
BucketID: i.SectionID,
|
BucketID: sections[i.SectionID],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,29 +346,31 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Put all labels together from earlier
|
// Put all labels together from earlier
|
||||||
for _, lID := range i.Labels {
|
for _, lName := range i.Labels {
|
||||||
task.Labels = append(task.Labels, labels[lID])
|
task.Labels = append(task.Labels, labels[lName])
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks[i.ID] = task
|
tasks[i.ID] = task
|
||||||
|
|
||||||
if _, exists := lists[i.ProjectID]; !exists {
|
if _, exists := lists[i.ProjectID]; !exists {
|
||||||
log.Debugf("[Todoist Migration] Tried to put item %d in project %d but the project does not exist", i.ID, i.ProjectID)
|
log.Debugf("[Todoist Migration] Tried to put item %s in project %s but the project does not exist", i.ID, i.ProjectID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lists[i.ProjectID].Tasks = append(lists[i.ProjectID].Tasks, task)
|
lists[i.ProjectID].Tasks = append(lists[i.ProjectID].Tasks, task)
|
||||||
|
|
||||||
|
fabricatedSectionID++
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the parenId of a task is not 0, create a task relation
|
// If the parenId of a task is not 0, create a task relation
|
||||||
// We're looping again here to make sure we have seem all tasks before and have them in our map
|
// We're looping again here to make sure we have seem all tasks before and have them in our map
|
||||||
for _, i := range sync.Items {
|
for _, i := range sync.Items {
|
||||||
if i.ParentID == 0 {
|
if i.ParentID == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := tasks[i.ParentID]; !exists {
|
if _, exists := tasks[i.ParentID]; !exists {
|
||||||
log.Debugf("[Todoist Migration] Could not find task %d in tasks map while trying to get resolve subtasks for task %d", i.ParentID, i.ID)
|
log.Debugf("[Todoist Migration] Could not find task %s in tasks map while trying to get resolve subtasks for task %s", i.ParentID, i.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +398,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||||||
// FIXME: Should be comments
|
// FIXME: Should be comments
|
||||||
for _, n := range sync.Notes {
|
for _, n := range sync.Notes {
|
||||||
if _, exists := tasks[n.ItemID]; !exists {
|
if _, exists := tasks[n.ItemID]; !exists {
|
||||||
log.Debugf("[Todoist Migration] Could not find task %d for note %d", n.ItemID, n.ID)
|
log.Debugf("[Todoist Migration] Could not find task %s for note %s", n.ItemID, n.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +451,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, exists := tasks[r.ItemID]; !exists {
|
if _, exists := tasks[r.ItemID]; !exists {
|
||||||
log.Debugf("Could not find task %d for reminder %d while trying to resolve reminders", r.ItemID, r.ID)
|
log.Debugf("Could not find task %s for reminder %s while trying to resolve reminders", r.ItemID, r.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,7 +528,7 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||||||
"sync_token": []string{"*"},
|
"sync_token": []string{"*"},
|
||||||
"resource_types": []string{"[\"all\"]"},
|
"resource_types": []string{"[\"all\"]"},
|
||||||
}
|
}
|
||||||
resp, err := migration.DoPost("https://api.todoist.com/sync/v8/sync", form)
|
resp, err := migration.DoPost("https://api.todoist.com/sync/v9/sync", form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -553,10 +544,10 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||||||
|
|
||||||
// Get all done tasks and projects
|
// Get all done tasks and projects
|
||||||
offset := 0
|
offset := 0
|
||||||
doneItems := make(map[int64]*doneItem)
|
doneItems := make(map[string]*doneItem)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
resp, err = migration.DoPost("https://api.todoist.com/sync/v8/completed/get_all?limit=200&offset="+strconv.Itoa(offset), form)
|
resp, err = migration.DoPost("https://api.todoist.com/sync/v9/completed/get_all?limit=200&offset="+strconv.Itoa(offset), form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -580,9 +571,9 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||||||
doneItems[i.TaskID] = i
|
doneItems[i.TaskID] = i
|
||||||
|
|
||||||
// need to get done item data
|
// need to get done item data
|
||||||
resp, err = migration.DoPost("https://api.todoist.com/sync/v8/items/get", url.Values{
|
resp, err = migration.DoPost("https://api.todoist.com/sync/v9/items/get", url.Values{
|
||||||
"token": []string{token},
|
"token": []string{token},
|
||||||
"item_id": []string{strconv.FormatInt(i.TaskID, 10)},
|
"item_id": []string{i.TaskID},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -594,7 +585,7 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("[Todoist Migration] Retrieved full task data for done task %d", i.TaskID)
|
log.Debugf("[Todoist Migration] Retrieved full task data for done task %s", i.TaskID)
|
||||||
syncResponse.Items = append(syncResponse.Items, doneI.Item)
|
syncResponse.Items = append(syncResponse.Items, doneI.Item)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,7 +600,7 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||||||
log.Debugf("[Todoist Migration] Getting archived projects for user %d", u.ID)
|
log.Debugf("[Todoist Migration] Getting archived projects for user %d", u.ID)
|
||||||
|
|
||||||
// Get all archived projects
|
// Get all archived projects
|
||||||
resp, err = migration.DoPost("https://api.todoist.com/sync/v8/projects/get_archived", form)
|
resp, err = migration.DoPost("https://api.todoist.com/sync/v9/projects/get_archived", form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -626,9 +617,8 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||||||
log.Debugf("[Todoist Migration] Getting data for archived projects for user %d", u.ID)
|
log.Debugf("[Todoist Migration] Getting data for archived projects for user %d", u.ID)
|
||||||
|
|
||||||
// Project data is not included in the regular sync for archived projects so we need to get all of those by hand
|
// Project data is not included in the regular sync for archived projects so we need to get all of those by hand
|
||||||
//https://api.todoist.com/sync/v8/projects/get_data\?project_id\=2269005399
|
|
||||||
for _, p := range archivedProjects {
|
for _, p := range archivedProjects {
|
||||||
resp, err = migration.DoPost("https://api.todoist.com/sync/v8/projects/get_data?project_id="+strconv.FormatInt(p.ID, 10), form)
|
resp, err = migration.DoPost("https://api.todoist.com/sync/v9/projects/get_data?project_id="+p.ID, form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ package todoist
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -50,30 +49,29 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg")
|
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
makeTestItem := func(id, projectId int64, hasDueDate, hasLabels, done bool) *item {
|
makeTestItem := func(id, projectId string, hasDueDate, hasLabels, done bool) *item {
|
||||||
item := &item{
|
item := &item{
|
||||||
ID: id,
|
ID: id,
|
||||||
UserID: 1855589,
|
UserID: "1855589",
|
||||||
ProjectID: projectId,
|
ProjectID: projectId,
|
||||||
Content: "Task" + strconv.FormatInt(id, 10),
|
Content: "Task" + id,
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
ParentID: 0,
|
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
DateAdded: time1,
|
DateAdded: time1,
|
||||||
DateCompleted: nilTime,
|
DateCompleted: nilTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
if done {
|
if done {
|
||||||
item.Checked = 1
|
item.Checked = true
|
||||||
item.DateCompleted = time3
|
item.DateCompleted = time3
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasLabels {
|
if hasLabels {
|
||||||
item.Labels = []int64{
|
item.Labels = []string{
|
||||||
80000,
|
"Label1",
|
||||||
80001,
|
"Label2",
|
||||||
80002,
|
"Label3",
|
||||||
80003,
|
"Label4",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,163 +89,163 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
testSync := &sync{
|
testSync := &sync{
|
||||||
Projects: []*project{
|
Projects: []*project{
|
||||||
{
|
{
|
||||||
ID: 396936926,
|
ID: "396936926",
|
||||||
Name: "Project1",
|
Name: "Project1",
|
||||||
Color: 30,
|
Color: "berry_red",
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
Collapsed: 0,
|
Collapsed: false,
|
||||||
Shared: false,
|
Shared: false,
|
||||||
IsDeleted: 0,
|
IsDeleted: false,
|
||||||
IsArchived: 0,
|
IsArchived: false,
|
||||||
IsFavorite: 0,
|
IsFavorite: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 396936927,
|
ID: "396936927",
|
||||||
Name: "Project2",
|
Name: "Project2",
|
||||||
Color: 37,
|
Color: "mint_green",
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
Collapsed: 0,
|
Collapsed: false,
|
||||||
Shared: false,
|
Shared: false,
|
||||||
IsDeleted: 0,
|
IsDeleted: false,
|
||||||
IsArchived: 0,
|
IsArchived: false,
|
||||||
IsFavorite: 0,
|
IsFavorite: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 396936928,
|
ID: "396936928",
|
||||||
Name: "Project3 - Archived",
|
Name: "Project3 - Archived",
|
||||||
Color: 37,
|
Color: "mint_green",
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
Collapsed: 0,
|
Collapsed: false,
|
||||||
Shared: false,
|
Shared: false,
|
||||||
IsDeleted: 0,
|
IsDeleted: false,
|
||||||
IsArchived: 1,
|
IsArchived: true,
|
||||||
IsFavorite: 0,
|
IsFavorite: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Items: []*item{
|
Items: []*item{
|
||||||
makeTestItem(400000000, 396936926, false, false, false),
|
makeTestItem("400000000", "396936926", false, false, false),
|
||||||
makeTestItem(400000001, 396936926, false, false, false),
|
makeTestItem("400000001", "396936926", false, false, false),
|
||||||
makeTestItem(400000002, 396936926, false, false, false),
|
makeTestItem("400000002", "396936926", false, false, false),
|
||||||
makeTestItem(400000003, 396936926, true, true, true),
|
makeTestItem("400000003", "396936926", true, true, true),
|
||||||
makeTestItem(400000004, 396936926, false, true, false),
|
makeTestItem("400000004", "396936926", false, true, false),
|
||||||
makeTestItem(400000005, 396936926, true, false, true),
|
makeTestItem("400000005", "396936926", true, false, true),
|
||||||
makeTestItem(400000006, 396936926, true, false, true),
|
makeTestItem("400000006", "396936926", true, false, true),
|
||||||
{
|
{
|
||||||
ID: 400000110,
|
ID: "400000110",
|
||||||
UserID: 1855589,
|
UserID: "1855589",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
Content: "Task with parent",
|
Content: "Task with parent",
|
||||||
Priority: 2,
|
Priority: 2,
|
||||||
ParentID: 400000006,
|
ParentID: "400000006",
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
Checked: 0,
|
Checked: false,
|
||||||
DateAdded: time1,
|
DateAdded: time1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 400000106,
|
ID: "400000106",
|
||||||
UserID: 1855589,
|
UserID: "1855589",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
Content: "Task400000106",
|
Content: "Task400000106",
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
ParentID: 0,
|
ParentID: "",
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
DateAdded: time1,
|
DateAdded: time1,
|
||||||
Checked: 1,
|
Checked: true,
|
||||||
DateCompleted: time3,
|
DateCompleted: time3,
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2021-01-31T19:00:00Z",
|
Date: "2021-01-31T19:00:00Z",
|
||||||
Timezone: nil,
|
Timezone: nil,
|
||||||
IsRecurring: false,
|
IsRecurring: false,
|
||||||
},
|
},
|
||||||
Labels: []int64{
|
Labels: []string{
|
||||||
80000,
|
"Label1",
|
||||||
80001,
|
"Label2",
|
||||||
80002,
|
"Label3",
|
||||||
80003,
|
"Label4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
makeTestItem(400000107, 396936926, false, false, true),
|
makeTestItem("400000107", "396936926", false, false, true),
|
||||||
makeTestItem(400000108, 396936926, false, false, true),
|
makeTestItem("400000108", "396936926", false, false, true),
|
||||||
{
|
{
|
||||||
ID: 400000109,
|
ID: "400000109",
|
||||||
UserID: 1855589,
|
UserID: "1855589",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
Content: "Task400000109",
|
Content: "Task400000109",
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
ChildOrder: 1,
|
ChildOrder: 1,
|
||||||
Checked: 1,
|
Checked: true,
|
||||||
DateAdded: time1,
|
DateAdded: time1,
|
||||||
DateCompleted: time3,
|
DateCompleted: time3,
|
||||||
SectionID: 1234,
|
SectionID: "1234",
|
||||||
},
|
},
|
||||||
|
|
||||||
makeTestItem(400000007, 396936927, true, false, false),
|
makeTestItem("400000007", "396936927", true, false, false),
|
||||||
makeTestItem(400000008, 396936927, true, false, false),
|
makeTestItem("400000008", "396936927", true, false, false),
|
||||||
makeTestItem(400000009, 396936927, false, false, false),
|
makeTestItem("400000009", "396936927", false, false, false),
|
||||||
makeTestItem(400000010, 396936927, false, false, true),
|
makeTestItem("400000010", "396936927", false, false, true),
|
||||||
makeTestItem(400000101, 396936927, false, false, false),
|
makeTestItem("400000101", "396936927", false, false, false),
|
||||||
makeTestItem(400000102, 396936927, true, true, false),
|
makeTestItem("400000102", "396936927", true, true, false),
|
||||||
makeTestItem(400000103, 396936927, false, true, false),
|
makeTestItem("400000103", "396936927", false, true, false),
|
||||||
makeTestItem(400000104, 396936927, false, true, false),
|
makeTestItem("400000104", "396936927", false, true, false),
|
||||||
makeTestItem(400000105, 396936927, true, true, false),
|
makeTestItem("400000105", "396936927", true, true, false),
|
||||||
|
|
||||||
makeTestItem(400000111, 396936928, false, false, true),
|
makeTestItem("400000111", "396936928", false, false, true),
|
||||||
},
|
},
|
||||||
Labels: []*label{
|
Labels: []*label{
|
||||||
{
|
{
|
||||||
ID: 80000,
|
ID: "80000",
|
||||||
Name: "Label1",
|
Name: "Label1",
|
||||||
Color: 30,
|
Color: "berry_red",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 80001,
|
ID: "80001",
|
||||||
Name: "Label2",
|
Name: "Label2",
|
||||||
Color: 31,
|
Color: "red",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 80002,
|
ID: "80002",
|
||||||
Name: "Label3",
|
Name: "Label3",
|
||||||
Color: 32,
|
Color: "orange",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 80003,
|
ID: "80003",
|
||||||
Name: "Label4",
|
Name: "Label4",
|
||||||
Color: 33,
|
Color: "yellow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Notes: []*note{
|
Notes: []*note{
|
||||||
{
|
{
|
||||||
ID: 101476,
|
ID: "101476",
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
ItemID: 400000000,
|
ItemID: "400000000",
|
||||||
Content: "Lorem Ipsum dolor sit amet",
|
Content: "Lorem Ipsum dolor sit amet",
|
||||||
Posted: time1,
|
Posted: time1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 101477,
|
ID: "101477",
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
ItemID: 400000001,
|
ItemID: "400000001",
|
||||||
Content: "Lorem Ipsum dolor sit amet",
|
Content: "Lorem Ipsum dolor sit amet",
|
||||||
Posted: time1,
|
Posted: time1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 101478,
|
ID: "101478",
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
ItemID: 400000003,
|
ItemID: "400000003",
|
||||||
Content: "Lorem Ipsum dolor sit amet",
|
Content: "Lorem Ipsum dolor sit amet",
|
||||||
Posted: time1,
|
Posted: time1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 101479,
|
ID: "101479",
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
ItemID: 400000010,
|
ItemID: "400000010",
|
||||||
Content: "Lorem Ipsum dolor sit amet",
|
Content: "Lorem Ipsum dolor sit amet",
|
||||||
Posted: time1,
|
Posted: time1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 101480,
|
ID: "101480",
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
ItemID: 400000101,
|
ItemID: "400000101",
|
||||||
Content: "Lorem Ipsum dolor sit amet",
|
Content: "Lorem Ipsum dolor sit amet",
|
||||||
FileAttachment: &fileAttachment{
|
FileAttachment: &fileAttachment{
|
||||||
FileName: "file.md",
|
FileName: "file.md",
|
||||||
@ -263,43 +261,43 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ID: 102000,
|
ID: 102000,
|
||||||
Content: "Lorem Ipsum dolor sit amet",
|
Content: "Lorem Ipsum dolor sit amet",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
Posted: time3,
|
Posted: time3,
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 102001,
|
ID: 102001,
|
||||||
Content: "Lorem Ipsum dolor sit amet 2",
|
Content: "Lorem Ipsum dolor sit amet 2",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
Posted: time3,
|
Posted: time3,
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 102002,
|
ID: 102002,
|
||||||
Content: "Lorem Ipsum dolor sit amet 3",
|
Content: "Lorem Ipsum dolor sit amet 3",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
Posted: time3,
|
Posted: time3,
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 102003,
|
ID: 102003,
|
||||||
Content: "Lorem Ipsum dolor sit amet 4",
|
Content: "Lorem Ipsum dolor sit amet 4",
|
||||||
ProjectID: 396936927,
|
ProjectID: "396936927",
|
||||||
Posted: time3,
|
Posted: time3,
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 102004,
|
ID: 102004,
|
||||||
Content: "Lorem Ipsum dolor sit amet 5",
|
Content: "Lorem Ipsum dolor sit amet 5",
|
||||||
ProjectID: 396936927,
|
ProjectID: "396936927",
|
||||||
Posted: time3,
|
Posted: time3,
|
||||||
PostedUID: 1855589,
|
PostedUID: 1855589,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Reminders: []*reminder{
|
Reminders: []*reminder{
|
||||||
{
|
{
|
||||||
ID: 103000,
|
ID: "103000",
|
||||||
ItemID: 400000000,
|
ItemID: "400000000",
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2020-06-15",
|
Date: "2020-06-15",
|
||||||
IsRecurring: false,
|
IsRecurring: false,
|
||||||
@ -307,40 +305,40 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
MmOffset: 180,
|
MmOffset: 180,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 103001,
|
ID: "103001",
|
||||||
ItemID: 400000000,
|
ItemID: "400000000",
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2020-06-16T07:00:00",
|
Date: "2020-06-16T07:00:00",
|
||||||
IsRecurring: false,
|
IsRecurring: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 103002,
|
ID: "103002",
|
||||||
ItemID: 400000002,
|
ItemID: "400000002",
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2020-07-15T07:00:00Z",
|
Date: "2020-07-15T07:00:00Z",
|
||||||
IsRecurring: true,
|
IsRecurring: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 103003,
|
ID: "103003",
|
||||||
ItemID: 400000003,
|
ItemID: "400000003",
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2020-06-15T07:00:00",
|
Date: "2020-06-15T07:00:00",
|
||||||
IsRecurring: false,
|
IsRecurring: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 103004,
|
ID: "103004",
|
||||||
ItemID: 400000005,
|
ItemID: "400000005",
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2020-06-15T07:00:00",
|
Date: "2020-06-15T07:00:00",
|
||||||
IsRecurring: false,
|
IsRecurring: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: 103006,
|
ID: "103006",
|
||||||
ItemID: 400000009,
|
ItemID: "400000009",
|
||||||
Due: &dueDate{
|
Due: &dueDate{
|
||||||
Date: "2020-06-15T07:00:00",
|
Date: "2020-06-15T07:00:00",
|
||||||
IsRecurring: false,
|
IsRecurring: false,
|
||||||
@ -349,9 +347,9 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Sections: []*section{
|
Sections: []*section{
|
||||||
{
|
{
|
||||||
ID: 1234,
|
ID: "1234",
|
||||||
Name: "Some Bucket",
|
Name: "Some Bucket",
|
||||||
ProjectID: 396936926,
|
ProjectID: "396936926",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -359,19 +357,19 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
vikunjaLabels := []*models.Label{
|
vikunjaLabels := []*models.Label{
|
||||||
{
|
{
|
||||||
Title: "Label1",
|
Title: "Label1",
|
||||||
HexColor: todoistColors[30],
|
HexColor: todoistColors["berry_red"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Label2",
|
Title: "Label2",
|
||||||
HexColor: todoistColors[31],
|
HexColor: todoistColors["red"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Label3",
|
Title: "Label3",
|
||||||
HexColor: todoistColors[32],
|
HexColor: todoistColors["orange"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Label4",
|
Title: "Label4",
|
||||||
HexColor: todoistColors[33],
|
HexColor: todoistColors["yellow"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,11 +383,11 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
List: models.List{
|
List: models.List{
|
||||||
Title: "Project1",
|
Title: "Project1",
|
||||||
Description: "Lorem Ipsum dolor sit amet\nLorem Ipsum dolor sit amet 2\nLorem Ipsum dolor sit amet 3",
|
Description: "Lorem Ipsum dolor sit amet\nLorem Ipsum dolor sit amet 2\nLorem Ipsum dolor sit amet 3",
|
||||||
HexColor: todoistColors[30],
|
HexColor: todoistColors["berry_red"],
|
||||||
},
|
},
|
||||||
Buckets: []*models.Bucket{
|
Buckets: []*models.Bucket{
|
||||||
{
|
{
|
||||||
ID: 1234,
|
ID: 1,
|
||||||
Title: "Some Bucket",
|
Title: "Some Bucket",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -510,7 +508,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
Done: true,
|
Done: true,
|
||||||
Created: time1,
|
Created: time1,
|
||||||
DoneAt: time3,
|
DoneAt: time3,
|
||||||
BucketID: 1234,
|
BucketID: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -519,7 +517,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
List: models.List{
|
List: models.List{
|
||||||
Title: "Project2",
|
Title: "Project2",
|
||||||
Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5",
|
Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5",
|
||||||
HexColor: todoistColors[37],
|
HexColor: todoistColors["mint_green"],
|
||||||
},
|
},
|
||||||
Tasks: []*models.TaskWithComments{
|
Tasks: []*models.TaskWithComments{
|
||||||
{
|
{
|
||||||
@ -616,7 +614,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
{
|
{
|
||||||
List: models.List{
|
List: models.List{
|
||||||
Title: "Project3 - Archived",
|
Title: "Project3 - Archived",
|
||||||
HexColor: todoistColors[37],
|
HexColor: todoistColors["mint_green"],
|
||||||
IsArchived: true,
|
IsArchived: true,
|
||||||
},
|
},
|
||||||
Tasks: []*models.TaskWithComments{
|
Tasks: []*models.TaskWithComments{
|
||||||
@ -634,7 +632,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
doneItems := make(map[int64]*doneItem)
|
doneItems := make(map[string]*doneItem)
|
||||||
hierachie, err := convertTodoistToVikunja(testSync, doneItems)
|
hierachie, err := convertTodoistToVikunja(testSync, doneItems)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, hierachie)
|
assert.NotNil(t, hierachie)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user