diff --git a/docs/content/doc/development/migration.md b/docs/content/doc/development/migration.md index 4da0412b0..8aa6fc99b 100644 --- a/docs/content/doc/development/migration.md +++ b/docs/content/doc/development/migration.md @@ -18,7 +18,7 @@ The interface makes it possible to use helper methods which handle http and focu There are two ways of migrating data from another service: -1. Through the auth-based flow where the user gives you access to their data at the third-party service through an oauth flow. You can then call the service's api on behalf of your user to get all the data. The Todoist, Trello and Microsoft To-Do Migrators use this pattern. +1. Through the auth-based flow where the user gives you access to their data at the third-party service through an oauth flow. You can then call the service's api on behalf of your user to get all the data. The Todoist, Kanboard, Trello and Microsoft To-Do Migrators use this pattern. 2. A file migration where the user uploads a file obtained from some third-party service. In your migrator, you need to parse the file and create the projects, tasks etc. The Vikunja File Import uses this pattern. To differentiate the two, there are two different interfaces you must implement. diff --git a/docs/content/doc/setup/config.md b/docs/content/doc/setup/config.md index e25f31126..e68c5bff6 100644 --- a/docs/content/doc/setup/config.md +++ b/docs/content/doc/setup/config.md @@ -1022,6 +1022,15 @@ Full path: `migration.trello` Environment path: `VIKUNJA_MIGRATION_TRELLO` +### kanboard + +Default: `` + +Full path: `migration.kanboard` + +Environment path: `VIKUNJA_MIGRATION_KANBOARD` + + ### microsofttodo Default: `` diff --git a/go.mod b/go.mod index aa1b526b3..01432dec1 100644 --- a/go.mod +++ b/go.mod @@ -164,6 +164,7 @@ require ( github.com/urfave/cli/v2 v2.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/ybbus/jsonrpc/v2 v2.1.7 // indirect github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 // indirect go.opentelemetry.io/otel v1.15.0 // indirect go.opentelemetry.io/otel/trace v1.15.0 // indirect diff --git a/go.sum b/go.sum index b2f6a6310..bcf348c07 100644 --- a/go.sum +++ b/go.sum @@ -595,6 +595,7 @@ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108 github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c= @@ -769,6 +770,8 @@ github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/ybbus/jsonrpc/v2 v2.1.7 h1:QjoXuZhkXZ3oLBkrONBe2avzFkYeYLorpeA+d8175XQ= +github.com/ybbus/jsonrpc/v2 v2.1.7/go.mod h1:rIuG1+ORoiqocf9xs/v+ecaAVeo3zcZHQgInyKFMeg0= github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4 h1:0sw0nJM544SpsihWx1bkXdYLQDlzRflMgFJQ4Yih9ts= github.com/yosssi/gohtml v0.0.0-20201013000340-ee4748c638f4/go.mod h1:+ccdNT0xMY1dtc5XBxumbYfOUhmduiGudqaDgD2rVRE= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= diff --git a/pkg/config/config.go b/pkg/config/config.go index c8ad843ac..f63bcbd8a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -142,6 +142,9 @@ const ( MigrationMicrosoftTodoClientID Key = `migration.microsofttodo.clientid` MigrationMicrosoftTodoClientSecret Key = `migration.microsofttodo.clientsecret` MigrationMicrosoftTodoRedirectURL Key = `migration.microsofttodo.redirecturl` + MigrationKanboardEnable Key = `migration.kanboard.enable` + MigrationKanboardApiToken Key = `migration.kanboard.token` + MigrationKanboardApiEndpoint Key = `migration.kanboard.endpoint` CorsEnable Key = `cors.enable` CorsOrigins Key = `cors.origins` diff --git a/pkg/modules/migration/kanboard/kanboard.go b/pkg/modules/migration/kanboard/kanboard.go new file mode 100644 index 000000000..8317abac1 --- /dev/null +++ b/pkg/modules/migration/kanboard/kanboard.go @@ -0,0 +1,135 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present 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 . + +package kanboard + +import ( + "github.com/ybbus/jsonrpc/v2" + + "code.vikunja.io/api/pkg/config" + "code.vikunja.io/api/pkg/log" + "code.vikunja.io/api/pkg/models" + "code.vikunja.io/api/pkg/modules/migration" + "code.vikunja.io/api/pkg/user" +) + +// Migration represents the trello migration struct +type Migration struct { + Token string `json:"code"` +} + +type kanboardBoard struct { +} + +func init() { +} + +// Name is used to get the name of the trello migration - we're using the docs here to annotate the status route. +// @Summary Get migration status +// @Description Returns if the current user already did the migation or not. This is useful to show a confirmation message in the frontend if the user is trying to do the same migration again. +// @tags migration +// @Produce json +// @Security JWTKeyAuth +// @Success 200 {object} migration.Status "The migration status" +// @Failure 500 {object} models.Message "Internal server error" +// @Router /migration/trello/status [get] +func (m *Migration) Name() string { + return "kanboard" +} + +// AuthURL returns the url users need to authenticate against +// @Summary Get the auth url from trello +// @Description Returns the auth url where the user needs to get its auth code. This code can then be used to migrate everything from trello to Vikunja. +// @tags migration +// @Produce json +// @Security JWTKeyAuth +// @Success 200 {object} handler.AuthURL "The auth url." +// @Failure 500 {object} models.Message "Internal server error" +// @Router /migration/trello/auth [get] +func (m *Migration) AuthURL() string { + return "" +} + +func getKanboardData(endpoint string, token string) (kanboardData []kanboardBoard, err error) { + + rpcClient := jsonrpc.NewClient(endpoint) + + err = rpcClient.CallFor(&kanboardData, "getAllProjects") + + return +} + +// Converts all previously obtained data from trello into the vikunja format. +// `trelloData` should contain all boards with their projects and cards respectively. +func convertKanboardDataToVikunja(kanboardData []kanboardBoard, token string) (fullVikunjaHierachie []*models.ProjectWithTasksAndBuckets, err error) { + + log.Debugf("[Kanboard Migration] ") + + fullVikunjaHierachie = []*models.ProjectWithTasksAndBuckets{ + { + Project: models.Project{ + Title: "Imported from Kanboard", + }, + ChildProjects: []*models.ProjectWithTasksAndBuckets{}, + }, + } + + log.Debugf("[Kanboard Migration] Converting %d boards to vikunja projects", len(kanboardData)) + + return +} + +// Migrate gets all tasks from trello for a user and puts them into vikunja +// @Summary Migrate all projects, tasks etc. from trello +// @Description Migrates all projects, tasks, notes, reminders, subtasks and files from trello to vikunja. +// @tags migration +// @Accept json +// @Produce json +// @Security JWTKeyAuth +// @Param migrationCode body kanboard.Migration true "The auth token previously obtained from the auth url. See the docs for /migration/kanboard/auth." +// @Success 200 {object} models.Message "A message telling you everything was migrated successfully." +// @Failure 500 {object} models.Message "Internal server error" +// @Router /migration/kanboard/migrate [post] +func (m *Migration) Migrate(u *user.User) (err error) { + log.Debugf("[Kanboard Migration] Starting migration for user %d", u.ID) + log.Debugf("[Kanboard Migration] Getting all kanboard data for user %d", u.ID) + + trelloData, err := getKanboardData(config.MigrationKanboardApiEndpoint.GetString(), config.MigrationKanboardApiToken.GetString()) + if err != nil { + return + } + + log.Debugf("[Kanboard Migration] Got all kanboard data for user %d", u.ID) + log.Debugf("[Kanboard Migration] Start converting kanboard data for user %d", u.ID) + + fullVikunjaHierachie, err := convertKanboardDataToVikunja(trelloData, m.Token) + if err != nil { + return + } + + log.Debugf("[Kanboard Migration] Done migrating kanboard data for user %d", u.ID) + log.Debugf("[Kanboard Migration] Start inserting kanboard data for user %d", u.ID) + + err = migration.InsertFromStructure(fullVikunjaHierachie, u) + if err != nil { + return + } + + log.Debugf("[Kanboard Migration] Done inserting kanboard data for user %d", u.ID) + log.Debugf("[Kanboard Migration] Migration done for user %d", u.ID) + + return nil +} diff --git a/pkg/routes/api/v1/info.go b/pkg/routes/api/v1/info.go index d2be79da8..64a682ae4 100644 --- a/pkg/routes/api/v1/info.go +++ b/pkg/routes/api/v1/info.go @@ -22,6 +22,7 @@ import ( "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/modules/auth/openid" + "code.vikunja.io/api/pkg/modules/migration/kanboard" microsofttodo "code.vikunja.io/api/pkg/modules/migration/microsoft-todo" "code.vikunja.io/api/pkg/modules/migration/ticktick" "code.vikunja.io/api/pkg/modules/migration/todoist" @@ -134,7 +135,10 @@ func Info(c echo.Context) error { m := µsofttodo.Migration{} info.AvailableMigrators = append(info.AvailableMigrators, m.Name()) } - + if config.MigrationKanboardEnable.GetBool() { + m := &kanboard.Migration{} + info.AvailableMigrators = append(info.AvailableMigrators, m.Name()) + } if config.BackgroundsEnabled.GetBool() { if config.BackgroundsUploadEnabled.GetBool() { info.EnabledBackgroundProviders = append(info.EnabledBackgroundProviders, "upload") diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index bb1e280ec..9c4f566f8 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -69,6 +69,7 @@ import ( "code.vikunja.io/api/pkg/modules/background/upload" "code.vikunja.io/api/pkg/modules/migration" migrationHandler "code.vikunja.io/api/pkg/modules/migration/handler" + "code.vikunja.io/api/pkg/modules/migration/kanboard" microsofttodo "code.vikunja.io/api/pkg/modules/migration/microsoft-todo" "code.vikunja.io/api/pkg/modules/migration/ticktick" "code.vikunja.io/api/pkg/modules/migration/todoist" @@ -597,6 +598,16 @@ func registerMigrations(m *echo.Group) { trelloMigrationHandler.RegisterRoutes(m) } + // Kanboard + if config.MigrationKanboardEnable.GetBool() { + kanboardMigrationHandler := &migrationHandler.MigrationWeb{ + MigrationStruct: func() migration.Migrator { + return &kanboard.Migration{} + }, + } + kanboardMigrationHandler.RegisterRoutes(m) + } + // Microsoft Todo if config.MigrationMicrosoftTodoEnable.GetBool() { microsoftTodoMigrationHandler := &migrationHandler.MigrationWeb{