c5bd09702a
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/1228 Co-authored-by: renovate <renovatebot@kolaente.de> Co-committed-by: renovate <renovatebot@kolaente.de>
644 lines
15 KiB
Go
644 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"
|
|
"strconv"
|
|
"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/wunderlist/testimage.jpg")
|
|
assert.NoError(t, err)
|
|
|
|
makeTestItem := func(id, projectId int64, hasDueDate, hasLabels, done bool) *item {
|
|
item := &item{
|
|
ID: id,
|
|
UserID: 1855589,
|
|
ProjectID: projectId,
|
|
Content: "Task" + strconv.FormatInt(id, 10),
|
|
Priority: 1,
|
|
ParentID: 0,
|
|
ChildOrder: 1,
|
|
DateAdded: time1,
|
|
DateCompleted: nilTime,
|
|
}
|
|
|
|
if done {
|
|
item.Checked = 1
|
|
item.DateCompleted = time3
|
|
}
|
|
|
|
if hasLabels {
|
|
item.Labels = []int64{
|
|
80000,
|
|
80001,
|
|
80002,
|
|
80003,
|
|
}
|
|
}
|
|
|
|
if hasDueDate {
|
|
item.Due = &dueDate{
|
|
Date: "2020-05-31",
|
|
Timezone: nil,
|
|
IsRecurring: false,
|
|
}
|
|
}
|
|
|
|
return item
|
|
}
|
|
|
|
testSync := &sync{
|
|
Projects: []*project{
|
|
{
|
|
ID: 396936926,
|
|
Name: "Project1",
|
|
Color: 30,
|
|
ChildOrder: 1,
|
|
Collapsed: 0,
|
|
Shared: false,
|
|
IsDeleted: 0,
|
|
IsArchived: 0,
|
|
IsFavorite: 0,
|
|
},
|
|
{
|
|
ID: 396936927,
|
|
Name: "Project2",
|
|
Color: 37,
|
|
ChildOrder: 1,
|
|
Collapsed: 0,
|
|
Shared: false,
|
|
IsDeleted: 0,
|
|
IsArchived: 0,
|
|
IsFavorite: 0,
|
|
},
|
|
{
|
|
ID: 396936928,
|
|
Name: "Project3 - Archived",
|
|
Color: 37,
|
|
ChildOrder: 1,
|
|
Collapsed: 0,
|
|
Shared: false,
|
|
IsDeleted: 0,
|
|
IsArchived: 1,
|
|
IsFavorite: 0,
|
|
},
|
|
},
|
|
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: 0,
|
|
DateAdded: time1,
|
|
},
|
|
{
|
|
ID: 400000106,
|
|
UserID: 1855589,
|
|
ProjectID: 396936926,
|
|
Content: "Task400000106",
|
|
Priority: 1,
|
|
ParentID: 0,
|
|
ChildOrder: 1,
|
|
DateAdded: time1,
|
|
Checked: 1,
|
|
DateCompleted: time3,
|
|
Due: &dueDate{
|
|
Date: "2021-01-31T19:00:00Z",
|
|
Timezone: nil,
|
|
IsRecurring: false,
|
|
},
|
|
Labels: []int64{
|
|
80000,
|
|
80001,
|
|
80002,
|
|
80003,
|
|
},
|
|
},
|
|
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: 1,
|
|
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: 30,
|
|
},
|
|
{
|
|
ID: 80001,
|
|
Name: "Label2",
|
|
Color: 31,
|
|
},
|
|
{
|
|
ID: 80002,
|
|
Name: "Label3",
|
|
Color: 32,
|
|
},
|
|
{
|
|
ID: 80003,
|
|
Name: "Label4",
|
|
Color: 33,
|
|
},
|
|
},
|
|
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[30],
|
|
},
|
|
{
|
|
Title: "Label2",
|
|
HexColor: todoistColors[31],
|
|
},
|
|
{
|
|
Title: "Label3",
|
|
HexColor: todoistColors[32],
|
|
},
|
|
{
|
|
Title: "Label4",
|
|
HexColor: todoistColors[33],
|
|
},
|
|
}
|
|
|
|
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[30],
|
|
},
|
|
Buckets: []*models.Bucket{
|
|
{
|
|
ID: 1234,
|
|
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: 1234,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
List: models.List{
|
|
Title: "Project2",
|
|
Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5",
|
|
HexColor: todoistColors[37],
|
|
},
|
|
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[37],
|
|
IsArchived: true,
|
|
},
|
|
Tasks: []*models.TaskWithComments{
|
|
{
|
|
Task: models.Task{
|
|
Title: "Task400000111",
|
|
Done: true,
|
|
Created: time1,
|
|
DoneAt: time3,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
doneItems := make(map[int64]*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)
|
|
}
|
|
}
|