2019-10-19 21:13:50 +00:00
|
|
|
package main
|
|
|
|
|
2019-10-19 21:44:51 +00:00
|
|
|
import (
|
2019-10-20 12:20:01 +00:00
|
|
|
"bufio"
|
2019-10-19 21:44:51 +00:00
|
|
|
sdk "code.vikunja.io/go-sdk"
|
|
|
|
"context"
|
|
|
|
"log"
|
|
|
|
"os"
|
2019-10-20 12:20:01 +00:00
|
|
|
"strings"
|
2019-10-20 16:09:11 +00:00
|
|
|
"time"
|
2019-10-19 21:44:51 +00:00
|
|
|
)
|
2019-10-19 21:13:50 +00:00
|
|
|
|
|
|
|
func main() {
|
2019-10-20 12:20:01 +00:00
|
|
|
|
|
|
|
const listID = 19
|
2019-10-20 16:11:29 +00:00
|
|
|
const basePath = `http://localhost:8080/api/v1`
|
|
|
|
const filepath = `../api/Featurecreep.md`
|
2019-10-20 12:20:01 +00:00
|
|
|
|
2019-10-20 16:09:11 +00:00
|
|
|
now := time.Now()
|
|
|
|
|
2019-10-19 21:44:51 +00:00
|
|
|
client := sdk.NewAPIClient(&sdk.Configuration{
|
2019-10-20 16:11:29 +00:00
|
|
|
BasePath: basePath,
|
2019-10-19 21:44:51 +00:00
|
|
|
DefaultHeader: make(map[string]string),
|
2019-10-20 16:11:29 +00:00
|
|
|
UserAgent: "Go migration client",
|
2019-10-19 21:44:51 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
token, _, err := client.UserApi.LoginPost(context.Background(), sdk.ModelsUserLogin{
|
|
|
|
Username: os.Getenv("VIKUNJA_USERNAME"),
|
|
|
|
Password: os.Getenv("VIKUNJA_PASSWORD"),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error auth", err)
|
|
|
|
}
|
|
|
|
log.Println("Auth succeeded, token is ", token.Token)
|
|
|
|
|
|
|
|
auth := context.WithValue(context.Background(), sdk.ContextAPIKey, sdk.APIKey{
|
|
|
|
Key: token.Token,
|
|
|
|
Prefix: "Bearer",
|
|
|
|
})
|
|
|
|
|
2019-10-20 12:20:01 +00:00
|
|
|
// Read the md file
|
2019-10-20 16:11:29 +00:00
|
|
|
lines, err := scanLines(filepath)
|
2019-10-19 21:44:51 +00:00
|
|
|
if err != nil {
|
2019-10-20 12:20:01 +00:00
|
|
|
log.Fatal("Error reading file: ", err)
|
2019-10-19 21:44:51 +00:00
|
|
|
}
|
2019-10-20 12:20:01 +00:00
|
|
|
|
|
|
|
tasks := make([]*sdk.ModelsTask, 0, len(lines))
|
|
|
|
|
|
|
|
var lastHeadline string
|
|
|
|
var notApplicable []string
|
|
|
|
var lastTask *sdk.ModelsTask
|
|
|
|
var taskRelations []*sdk.ModelsTaskRelation
|
2019-10-20 15:53:45 +00:00
|
|
|
labels := make(map[string]*sdk.ModelsLabel)
|
2019-10-20 12:20:01 +00:00
|
|
|
for in, l := range lines {
|
|
|
|
|
|
|
|
if l == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasPrefix(l, "#") {
|
|
|
|
lastHeadline = strings.TrimSpace(strings.ReplaceAll(l, "#", ""))
|
2019-10-20 15:53:45 +00:00
|
|
|
labels[lastHeadline] = &sdk.ModelsLabel{Title: lastHeadline}
|
2019-10-20 12:20:01 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only add tasks to the list
|
|
|
|
if strings.HasPrefix(l, "* [") {
|
|
|
|
t := &sdk.ModelsTask{
|
|
|
|
Text: l[5:],
|
|
|
|
Done: strings.HasPrefix(l, "* [x]"),
|
|
|
|
Labels: []sdk.ModelsLabel{
|
|
|
|
{
|
|
|
|
Title: lastHeadline,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
*t, _, err = client.TaskApi.ListsIdPut(auth, listID, *t)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error creating task: ", err)
|
|
|
|
}
|
2019-10-20 14:07:17 +00:00
|
|
|
log.Printf("Created task %d of %d with ID %d", in, len(lines), t.Id)
|
2019-10-20 12:20:01 +00:00
|
|
|
|
|
|
|
// Subtask handling
|
|
|
|
lastTask = t
|
|
|
|
|
|
|
|
tasks = append(tasks, t)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Subtask handling
|
|
|
|
// If we have a line starting with two spaces and then task, we have a subtask of the last task
|
|
|
|
if strings.HasPrefix(l, " * [") {
|
|
|
|
subtask := &sdk.ModelsTask{
|
|
|
|
Text: l[7:],
|
|
|
|
Done: strings.HasPrefix(l, " * [x]"),
|
|
|
|
Labels: []sdk.ModelsLabel{
|
|
|
|
{
|
|
|
|
Title: lastHeadline,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
*subtask, _, err = client.TaskApi.ListsIdPut(auth, listID, *subtask)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error creating task: ", err)
|
|
|
|
}
|
2019-10-20 14:07:17 +00:00
|
|
|
log.Printf("Created task %d of %d with ID %d", in, len(lines), subtask.Id)
|
2019-10-20 12:20:01 +00:00
|
|
|
|
|
|
|
tasks = append(tasks, subtask)
|
|
|
|
taskRelations = append(taskRelations, &sdk.ModelsTaskRelation{
|
|
|
|
TaskId: lastTask.Id,
|
|
|
|
OtherTaskId: subtask.Id,
|
|
|
|
RelationKind: "subtask",
|
|
|
|
})
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:07:17 +00:00
|
|
|
// If we had a last task, every line which follows now is not a subtask but additional description, so we put it in as description
|
|
|
|
if lastTask != nil {
|
|
|
|
lastTask.Description = lastTask.Description + l + "\n"
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-10-20 12:20:01 +00:00
|
|
|
notApplicable = append(notApplicable, l)
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:07:17 +00:00
|
|
|
log.Println("Done migrating tasks.")
|
|
|
|
|
2019-10-20 15:53:45 +00:00
|
|
|
// Make sure all labels exist
|
|
|
|
outer:
|
|
|
|
for _, l := range labels {
|
|
|
|
// Check if it exists
|
|
|
|
lls, _, err := client.LabelsApi.LabelsGet(auth, map[string]interface{}{"s": l.Title})
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error getting label: ", err)
|
|
|
|
}
|
|
|
|
// If the result is empty, we need to create the label
|
|
|
|
if len(lls) == 0 {
|
|
|
|
newLabel, _, err := client.LabelsApi.LabelsPut(auth, *l)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error creating new label: ", err)
|
|
|
|
}
|
|
|
|
labels[l.Title] = &newLabel
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go through the results of the search and put the right label in our label map
|
|
|
|
for _, ll := range lls {
|
|
|
|
if l.Title == ll.Title {
|
|
|
|
labels[ll.Title] = &ll
|
|
|
|
continue outer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this point, we have a map with existing labels
|
|
|
|
|
2019-10-20 14:07:17 +00:00
|
|
|
// Update all tasks which have a description
|
2019-10-20 15:53:45 +00:00
|
|
|
// Update all labels on tasks
|
2019-10-20 14:07:17 +00:00
|
|
|
for _, t := range tasks {
|
2019-10-20 15:53:45 +00:00
|
|
|
|
|
|
|
label, _ := labels[t.Labels[0].Title]
|
|
|
|
_, _, err := client.LabelsApi.TasksTaskLabelsPut(auth, t.Id, sdk.ModelsLabelTask{LabelId: label.Id})
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error adding label %s to task %d: %v", label.Title, t.Id, err)
|
|
|
|
}
|
|
|
|
log.Printf("Added label %s to task %d", label.Title, t.Id)
|
|
|
|
|
2019-10-20 14:07:17 +00:00
|
|
|
if t.Description == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
*t, _, err = client.TaskApi.TasksIdPost(auth, t.Id, *t)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error updating task description: ", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("Updated description of task %d", t.Id)
|
|
|
|
}
|
|
|
|
|
2019-10-20 15:53:54 +00:00
|
|
|
// Create all task relations
|
|
|
|
for _, tr := range taskRelations {
|
|
|
|
_, _, err := client.TaskApi.TasksTaskIDRelationsPut(auth, *tr, tr.TaskId)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error creating task relation between tasks %d and %d: %v", tr.TaskId, tr.OtherTaskId, err)
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 12:20:01 +00:00
|
|
|
|
2019-10-20 16:09:11 +00:00
|
|
|
log.Printf("Done in %v", time.Since(now))
|
2019-10-20 12:20:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func scanLines(path string) ([]string, error) {
|
|
|
|
|
|
|
|
file, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer file.Close()
|
|
|
|
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
scanner.Split(bufio.ScanLines)
|
|
|
|
|
|
|
|
var lines []string
|
|
|
|
for scanner.Scan() {
|
|
|
|
lines = append(lines, scanner.Text())
|
|
|
|
}
|
|
|
|
|
|
|
|
return lines, nil
|
2019-10-19 21:13:50 +00:00
|
|
|
}
|