
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/1346
643 lines
15 KiB
Go
643 lines
15 KiB
Go
// Vikunja is a to-do list application to facilitate your life.
|
|
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public Licensee as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public Licensee for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public Licensee
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package todoist
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"code.vikunja.io/api/pkg/config"
|
|
"code.vikunja.io/api/pkg/files"
|
|
"code.vikunja.io/api/pkg/models"
|
|
"github.com/stretchr/testify/assert"
|
|
"gopkg.in/d4l3k/messagediff.v1"
|
|
)
|
|
|
|
func TestConvertTodoistToVikunja(t *testing.T) {
|
|
|
|
config.InitConfig()
|
|
|
|
time1, err := time.Parse(time.RFC3339Nano, "2014-09-26T08:25:05Z")
|
|
assert.NoError(t, err)
|
|
time1 = time1.In(config.GetTimeZone())
|
|
time3, err := time.Parse(time.RFC3339Nano, "2014-10-21T08:25:05Z")
|
|
assert.NoError(t, err)
|
|
time3 = time3.In(config.GetTimeZone())
|
|
dueTime, err := time.Parse(time.RFC3339Nano, "2020-05-31T23:59:00Z")
|
|
assert.NoError(t, err)
|
|
dueTime = dueTime.In(config.GetTimeZone())
|
|
dueTimeWithTime, err := time.Parse(time.RFC3339Nano, "2021-01-31T19:00:00Z")
|
|
assert.NoError(t, err)
|
|
dueTimeWithTime = dueTimeWithTime.In(config.GetTimeZone())
|
|
nilTime, err := time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00Z")
|
|
assert.NoError(t, err)
|
|
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/testimage.jpg")
|
|
assert.NoError(t, err)
|
|
|
|
makeTestItem := func(id, projectId string, hasDueDate, hasLabels, done bool) *item {
|
|
item := &item{
|
|
ID: id,
|
|
UserID: "1855589",
|
|
ProjectID: projectId,
|
|
Content: "Task" + id,
|
|
Priority: 1,
|
|
ChildOrder: 1,
|
|
DateAdded: time1,
|
|
DateCompleted: nilTime,
|
|
}
|
|
|
|
if done {
|
|
item.Checked = true
|
|
item.DateCompleted = time3
|
|
}
|
|
|
|
if hasLabels {
|
|
item.Labels = []string{
|
|
"Label1",
|
|
"Label2",
|
|
"Label3",
|
|
"Label4",
|
|
}
|
|
}
|
|
|
|
if hasDueDate {
|
|
item.Due = &dueDate{
|
|
Date: "2020-05-31",
|
|
Timezone: nil,
|
|
IsRecurring: false,
|
|
}
|
|
}
|
|
|
|
return item
|
|
}
|
|
|
|
testSync := &sync{
|
|
Projects: []*project{
|
|
{
|
|
ID: "396936926",
|
|
Name: "Project1",
|
|
Color: "berry_red",
|
|
ChildOrder: 1,
|
|
Collapsed: false,
|
|
Shared: false,
|
|
IsDeleted: false,
|
|
IsArchived: false,
|
|
IsFavorite: false,
|
|
},
|
|
{
|
|
ID: "396936927",
|
|
Name: "Project2",
|
|
Color: "mint_green",
|
|
ChildOrder: 1,
|
|
Collapsed: false,
|
|
Shared: false,
|
|
IsDeleted: false,
|
|
IsArchived: false,
|
|
IsFavorite: false,
|
|
},
|
|
{
|
|
ID: "396936928",
|
|
Name: "Project3 - Archived",
|
|
Color: "mint_green",
|
|
ChildOrder: 1,
|
|
Collapsed: false,
|
|
Shared: false,
|
|
IsDeleted: false,
|
|
IsArchived: true,
|
|
IsFavorite: false,
|
|
},
|
|
},
|
|
Items: []*item{
|
|
makeTestItem("400000000", "396936926", false, false, false),
|
|
makeTestItem("400000001", "396936926", false, false, false),
|
|
makeTestItem("400000002", "396936926", false, false, false),
|
|
makeTestItem("400000003", "396936926", true, true, true),
|
|
makeTestItem("400000004", "396936926", false, true, false),
|
|
makeTestItem("400000005", "396936926", true, false, true),
|
|
makeTestItem("400000006", "396936926", true, false, true),
|
|
{
|
|
ID: "400000110",
|
|
UserID: "1855589",
|
|
ProjectID: "396936926",
|
|
Content: "Task with parent",
|
|
Priority: 2,
|
|
ParentID: "400000006",
|
|
ChildOrder: 1,
|
|
Checked: false,
|
|
DateAdded: time1,
|
|
},
|
|
{
|
|
ID: "400000106",
|
|
UserID: "1855589",
|
|
ProjectID: "396936926",
|
|
Content: "Task400000106",
|
|
Priority: 1,
|
|
ParentID: "",
|
|
ChildOrder: 1,
|
|
DateAdded: time1,
|
|
Checked: true,
|
|
DateCompleted: time3,
|
|
Due: &dueDate{
|
|
Date: "2021-01-31T19:00:00Z",
|
|
Timezone: nil,
|
|
IsRecurring: false,
|
|
},
|
|
Labels: []string{
|
|
"Label1",
|
|
"Label2",
|
|
"Label3",
|
|
"Label4",
|
|
},
|
|
},
|
|
makeTestItem("400000107", "396936926", false, false, true),
|
|
makeTestItem("400000108", "396936926", false, false, true),
|
|
{
|
|
ID: "400000109",
|
|
UserID: "1855589",
|
|
ProjectID: "396936926",
|
|
Content: "Task400000109",
|
|
Priority: 1,
|
|
ChildOrder: 1,
|
|
Checked: true,
|
|
DateAdded: time1,
|
|
DateCompleted: time3,
|
|
SectionID: "1234",
|
|
},
|
|
|
|
makeTestItem("400000007", "396936927", true, false, false),
|
|
makeTestItem("400000008", "396936927", true, false, false),
|
|
makeTestItem("400000009", "396936927", false, false, false),
|
|
makeTestItem("400000010", "396936927", false, false, true),
|
|
makeTestItem("400000101", "396936927", false, false, false),
|
|
makeTestItem("400000102", "396936927", true, true, false),
|
|
makeTestItem("400000103", "396936927", false, true, false),
|
|
makeTestItem("400000104", "396936927", false, true, false),
|
|
makeTestItem("400000105", "396936927", true, true, false),
|
|
|
|
makeTestItem("400000111", "396936928", false, false, true),
|
|
},
|
|
Labels: []*label{
|
|
{
|
|
ID: "80000",
|
|
Name: "Label1",
|
|
Color: "berry_red",
|
|
},
|
|
{
|
|
ID: "80001",
|
|
Name: "Label2",
|
|
Color: "red",
|
|
},
|
|
{
|
|
ID: "80002",
|
|
Name: "Label3",
|
|
Color: "orange",
|
|
},
|
|
{
|
|
ID: "80003",
|
|
Name: "Label4",
|
|
Color: "yellow",
|
|
},
|
|
},
|
|
Notes: []*note{
|
|
{
|
|
ID: "101476",
|
|
PostedUID: 1855589,
|
|
ItemID: "400000000",
|
|
Content: "Lorem Ipsum dolor sit amet",
|
|
Posted: time1,
|
|
},
|
|
{
|
|
ID: "101477",
|
|
PostedUID: 1855589,
|
|
ItemID: "400000001",
|
|
Content: "Lorem Ipsum dolor sit amet",
|
|
Posted: time1,
|
|
},
|
|
{
|
|
ID: "101478",
|
|
PostedUID: 1855589,
|
|
ItemID: "400000003",
|
|
Content: "Lorem Ipsum dolor sit amet",
|
|
Posted: time1,
|
|
},
|
|
{
|
|
ID: "101479",
|
|
PostedUID: 1855589,
|
|
ItemID: "400000010",
|
|
Content: "Lorem Ipsum dolor sit amet",
|
|
Posted: time1,
|
|
},
|
|
{
|
|
ID: "101480",
|
|
PostedUID: 1855589,
|
|
ItemID: "400000101",
|
|
Content: "Lorem Ipsum dolor sit amet",
|
|
FileAttachment: &fileAttachment{
|
|
FileName: "file.md",
|
|
FileType: "text/plain",
|
|
FileSize: 12345,
|
|
FileURL: "https://vikunja.io/testimage.jpg", // Using an image which we are hosting, so it'll still be up
|
|
UploadState: "completed",
|
|
},
|
|
Posted: time1,
|
|
},
|
|
},
|
|
ProjectNotes: []*projectNote{
|
|
{
|
|
ID: 102000,
|
|
Content: "Lorem Ipsum dolor sit amet",
|
|
ProjectID: "396936926",
|
|
Posted: time3,
|
|
PostedUID: 1855589,
|
|
},
|
|
{
|
|
ID: 102001,
|
|
Content: "Lorem Ipsum dolor sit amet 2",
|
|
ProjectID: "396936926",
|
|
Posted: time3,
|
|
PostedUID: 1855589,
|
|
},
|
|
{
|
|
ID: 102002,
|
|
Content: "Lorem Ipsum dolor sit amet 3",
|
|
ProjectID: "396936926",
|
|
Posted: time3,
|
|
PostedUID: 1855589,
|
|
},
|
|
{
|
|
ID: 102003,
|
|
Content: "Lorem Ipsum dolor sit amet 4",
|
|
ProjectID: "396936927",
|
|
Posted: time3,
|
|
PostedUID: 1855589,
|
|
},
|
|
{
|
|
ID: 102004,
|
|
Content: "Lorem Ipsum dolor sit amet 5",
|
|
ProjectID: "396936927",
|
|
Posted: time3,
|
|
PostedUID: 1855589,
|
|
},
|
|
},
|
|
Reminders: []*reminder{
|
|
{
|
|
ID: "103000",
|
|
ItemID: "400000000",
|
|
Due: &dueDate{
|
|
Date: "2020-06-15",
|
|
IsRecurring: false,
|
|
},
|
|
MmOffset: 180,
|
|
},
|
|
{
|
|
ID: "103001",
|
|
ItemID: "400000000",
|
|
Due: &dueDate{
|
|
Date: "2020-06-16T07:00:00",
|
|
IsRecurring: false,
|
|
},
|
|
},
|
|
{
|
|
ID: "103002",
|
|
ItemID: "400000002",
|
|
Due: &dueDate{
|
|
Date: "2020-07-15T07:00:00Z",
|
|
IsRecurring: true,
|
|
},
|
|
},
|
|
{
|
|
ID: "103003",
|
|
ItemID: "400000003",
|
|
Due: &dueDate{
|
|
Date: "2020-06-15T07:00:00",
|
|
IsRecurring: false,
|
|
},
|
|
},
|
|
{
|
|
ID: "103004",
|
|
ItemID: "400000005",
|
|
Due: &dueDate{
|
|
Date: "2020-06-15T07:00:00",
|
|
IsRecurring: false,
|
|
},
|
|
},
|
|
{
|
|
ID: "103006",
|
|
ItemID: "400000009",
|
|
Due: &dueDate{
|
|
Date: "2020-06-15T07:00:00",
|
|
IsRecurring: false,
|
|
},
|
|
},
|
|
},
|
|
Sections: []*section{
|
|
{
|
|
ID: "1234",
|
|
Name: "Some Bucket",
|
|
ProjectID: "396936926",
|
|
},
|
|
},
|
|
}
|
|
|
|
vikunjaLabels := []*models.Label{
|
|
{
|
|
Title: "Label1",
|
|
HexColor: todoistColors["berry_red"],
|
|
},
|
|
{
|
|
Title: "Label2",
|
|
HexColor: todoistColors["red"],
|
|
},
|
|
{
|
|
Title: "Label3",
|
|
HexColor: todoistColors["orange"],
|
|
},
|
|
{
|
|
Title: "Label4",
|
|
HexColor: todoistColors["yellow"],
|
|
},
|
|
}
|
|
|
|
expectedHierachie := []*models.NamespaceWithListsAndTasks{
|
|
{
|
|
Namespace: models.Namespace{
|
|
Title: "Migrated from todoist",
|
|
},
|
|
Lists: []*models.ListWithTasksAndBuckets{
|
|
{
|
|
List: models.List{
|
|
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",
|
|
},
|
|
},
|
|
Tasks: []*models.TaskWithComments{
|
|
{
|
|
Task: models.Task{
|
|
Title: "Task400000000",
|
|
Description: "Lorem Ipsum dolor sit amet",
|
|
Done: false,
|
|
Created: time1,
|
|
Reminders: []time.Time{
|
|
time.Date(2020, time.June, 15, 23, 59, 0, 0, time.UTC).In(config.GetTimeZone()),
|
|
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: []time.Time{
|
|
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: []time.Time{
|
|
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: []time.Time{
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
List: models.List{
|
|
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: []time.Time{
|
|
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,
|
|
},
|
|
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,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
List: models.List{
|
|
Title: "Project3 - Archived",
|
|
HexColor: todoistColors["mint_green"],
|
|
IsArchived: true,
|
|
},
|
|
Tasks: []*models.TaskWithComments{
|
|
{
|
|
Task: models.Task{
|
|
Title: "Task400000111",
|
|
Done: true,
|
|
Created: time1,
|
|
DoneAt: time3,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
doneItems := make(map[string]*doneItem)
|
|
hierachie, err := convertTodoistToVikunja(testSync, doneItems)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, hierachie)
|
|
if diff, equal := messagediff.PrettyDiff(hierachie, expectedHierachie); !equal {
|
|
t.Errorf("converted todoist data = %v, want %v, diff: %v", hierachie, expectedHierachie, diff)
|
|
}
|
|
}
|