Compare commits

..

42 Commits

Author SHA1 Message Date
f54fdd7f6d chore(deps): update klakegg/hugo docker tag to v0.107.0
Some checks are pending
continuous-integration/drone/pr Build is pending
2023-01-06 10:01:03 +00:00
Dominik Pschenitschni
508a3157e2 fix(drone): add type, fix pull, remove group (#1355)
Some checks failed
continuous-integration/drone/push Build is failing
Co-authored-by: Dominik Pschenitschni <mail@celement.de>
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1355
Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
2023-01-06 09:46:52 +00:00
TheDubliner
321a8f7e2b
fix(docs): fix a few minor typos (#59)
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-06 10:33:43 +01:00
dd7dcdd0cc fix(deps): update module golang.org/x/crypto to v0.5.0 (#1353)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1353
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-01-04 18:37:35 +00:00
cb6368036c fix(deps): update module golang.org/x/term to v0.4.0 (#1352)
Some checks reported errors
continuous-integration/drone/push Build encountered an error
Reviewed-on: vikunja/api#1352
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-01-04 18:23:30 +00:00
36dfcb8ddb fix(deps): update module golang.org/x/image to v0.3.0 (#1350)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1350
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-01-04 16:16:04 +00:00
7f8c85118e fix(deps): update module golang.org/x/sys to v0.4.0 (#1351)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1351
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-01-04 16:15:58 +00:00
f3476bec6c fix(deps): update module github.com/coreos/go-oidc/v3 to v3.5.0 (#1349)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: vikunja/api#1349
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-01-04 11:03:19 +00:00
392bdd1b94
fix(ci): set release path to /source
Some checks failed
continuous-integration/drone/push Build is failing
Should fix https://github.com/techknowlogick/xgo/issues/187
2023-01-03 16:02:17 +01:00
80634d43c1 fix(deps): update module github.com/wneessen/go-mail to v0.3.7 (#1348)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1348
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2023-01-03 14:48:48 +00:00
4fa45bf9dc
chore: remove custom gitea bug template in favor of githubs
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-30 11:57:03 +01:00
ef1d1e2b20 feat(migrators): remove wunderlist (#1346)
Some checks failed
continuous-integration/drone/push Build is failing
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1346
2022-12-29 17:12:39 +00:00
Dominik Pschenitschni
ca3580766e fix(docs): old helm charts url (#1344)
All checks were successful
continuous-integration/drone/push Build is passing
Co-authored-by: Dominik Pschenitschni <mail@celement.de>
Reviewed-on: vikunja/api#1344
Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
2022-12-28 16:06:55 +00:00
c6429c8b13 fix(deps): update module github.com/labstack/echo/v4 to v4.10.0 (#1343)
Some checks failed
continuous-integration/drone/push Build is failing
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1343
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-28 10:32:12 +00:00
304481cf28 fix(deps): update module github.com/wneessen/go-mail to v0.3.6 (#1342)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1342
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-26 17:29:28 +00:00
897a6e5d5c
fix(caldav): use const for repeat modes
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-24 14:34:59 +01:00
194b88e2eb
fix(tasks): don't reset the kanban bucket when updating a task and not providing one
Resolves https://github.com/go-vikunja/api/issues/56
2022-12-24 14:30:34 +01:00
c5327845ee
feat(caldav): add support for repeating tasks
Some checks failed
continuous-integration/drone/push Build is failing
Resolves https://github.com/go-vikunja/api/issues/57#issuecomment-1364373103
2022-12-24 12:19:51 +01:00
ea1d06bda6
fix(list): return lists for a namespace id even if that namespace is deleted
All checks were successful
continuous-integration/drone/push Build is passing
This fixes a problem where a namespace was deleted and its list were not.
Forum discussion: https://community.vikunja.io/t/list-deleted-but-tasks-showing-up-as-archived-and-overdue/1025
2022-12-23 17:48:21 +01:00
0104aa504b
fix(ci): pin nfpm container version and binary location
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-19 15:37:01 +01:00
6a97a214a3
fix(migration): use Todoist v9 api to migrate tasks from them
Some checks failed
continuous-integration/drone/push Build is failing
Discussion: https://community.vikunja.io/t/importing-tasks-from-todoist/322/7
2022-12-18 20:38:58 +01:00
a79b1de2d0 feat: provide logout url for openid providers (#1340)
Some checks failed
continuous-integration/drone/push Build is failing
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1340
Co-authored-by: viehlieb <pf@pragma-shift.net>
Co-committed-by: viehlieb <pf@pragma-shift.net>
2022-12-18 18:26:28 +00:00
e9ce930230 fix(deps): update module github.com/swaggo/swag to v1.8.9 (#1327)
Some checks failed
continuous-integration/drone/push Build is failing
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1327
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-18 16:43:30 +00:00
6cb48e430e fix(deps): update module github.com/pquerna/otp to v1.4.0 (#1341)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1341
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-14 07:21:11 +00:00
a2c8426d02 fix(deps): update module golang.org/x/crypto to v0.4.0 (#1339)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: vikunja/api#1339
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-07 13:16:10 +00:00
3be10ca4a2 fix(deps): update module github.com/getsentry/sentry-go to v0.16.0 (#1338)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: vikunja/api#1338
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-07 12:15:16 +00:00
ec297009d3 fix(deps): update module golang.org/x/oauth2 to v0.3.0 (#1337)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: vikunja/api#1337
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 16:25:24 +00:00
dbc30284f3 fix(deps): update module golang.org/x/oauth2 to v0.2.0 (#1316)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: vikunja/api#1316
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 08:14:40 +00:00
879324dcd0 fix(deps): update module golang.org/x/image to v0.2.0 (#1335)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1335
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 07:58:51 +00:00
3be6e93a05 fix(deps): update module golang.org/x/term to v0.3.0 (#1336)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1336
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 07:58:21 +00:00
f93317bf5d
fix(caldav): add Z suffix to dates make it clear dates are in UTC
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-04 21:01:04 +01:00
1cfdb085e5 fix(deps): update module golang.org/x/sys to v0.3.0 (#1333)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: vikunja/api#1333
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-04 16:56:44 +00:00
51cf8beaed
feat(release): use compressed binaries for package releases
All checks were successful
continuous-integration/drone/push Build is passing
vikunja/api#1330
2022-12-02 16:31:06 +01:00
b8c3b570a4
fix(restore): check if we're really dealing with a string
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-02 14:49:32 +01:00
8ae062a095 fix(deps): update module github.com/go-sql-driver/mysql to v1.7.0 (#1332)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1332
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-02 13:39:25 +00:00
941d1e06c5
fix(build): downgrade xgo to 1.19.2 so that builds work again
All checks were successful
continuous-integration/drone/push Build is passing
See https://github.com/techknowlogick/xgo/issues/187
2022-12-01 19:00:48 +01:00
1f2eb57602
fix(reminders): make sure an overdue reminder is sent when there is only one overdue task
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-01 18:41:24 +01:00
51911a8868
fix(reminders): overdue tasks join condition
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-01 18:30:05 +01:00
47aae115df
fix(tasks): don't include undone overdue tasks from archived lists or namespaces in notification mails
Some checks failed
continuous-integration/drone/push Build is failing
Resolves vikunja/api#1324
2022-12-01 18:07:30 +01:00
fbc4b91e0f
fix(dump): make sure null dates are properly set when restoring from a dump
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-01 17:53:02 +01:00
8c67be558f
fix: restore notifications table from dump when it already had the correct format
Some checks failed
continuous-integration/drone/push Build is failing
2022-12-01 17:33:00 +01:00
e27cd9b336 fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.4.3 (#1328)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: vikunja/api#1328
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-29 15:14:04 +00:00
33 changed files with 1208 additions and 2243 deletions

View File

@ -1,5 +1,6 @@
--- ---
kind: pipeline kind: pipeline
type: docker
name: testing name: testing
workspace: workspace:
@ -111,7 +112,7 @@ steps:
# compiling the same magefile at the same time. It's also faster if each step does not need to compile it first. # compiling the same magefile at the same time. It's also faster if each step does not need to compile it first.
- name: mage - name: mage
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
commands: commands:
@ -122,7 +123,7 @@ steps:
- name: build - name: build
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
depends_on: [ mage ] depends_on: [ mage ]
@ -133,7 +134,7 @@ steps:
- name: lint - name: lint
image: golang:1.19-alpine image: golang:1.19-alpine
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
depends_on: [ build ] depends_on: [ build ]
@ -147,7 +148,7 @@ steps:
- name: test-migration-prepare - name: test-migration-prepare
image: kolaente/toolbox:latest image: kolaente/toolbox:latest
pull: true pull: always
commands: commands:
# Get the latest version # Get the latest version
- wget https://dl.vikunja.io/api/unstable/vikunja-unstable-linux-amd64-full.zip -q -O vikunja-latest.zip - wget https://dl.vikunja.io/api/unstable/vikunja-unstable-linux-amd64-full.zip -q -O vikunja-latest.zip
@ -155,7 +156,7 @@ steps:
- name: test-migration-sqlite - name: test-migration-sqlite
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
depends_on: [ test-migration-prepare, build ] depends_on: [ test-migration-prepare, build ]
environment: environment:
VIKUNJA_DATABASE_TYPE: sqlite VIKUNJA_DATABASE_TYPE: sqlite
@ -174,7 +175,7 @@ steps:
- name: test-migration-mysql - name: test-migration-mysql
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
depends_on: [ test-migration-prepare, build ] depends_on: [ test-migration-prepare, build ]
environment: environment:
VIKUNJA_DATABASE_TYPE: mysql VIKUNJA_DATABASE_TYPE: mysql
@ -193,7 +194,7 @@ steps:
- name: test-migration-psql - name: test-migration-psql
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
depends_on: [ test-migration-prepare, build ] depends_on: [ test-migration-prepare, build ]
environment: environment:
VIKUNJA_DATABASE_TYPE: postgres VIKUNJA_DATABASE_TYPE: postgres
@ -213,7 +214,7 @@ steps:
- name: test - name: test
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
commands: commands:
@ -224,7 +225,7 @@ steps:
- name: test-sqlite - name: test-sqlite
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_TESTS_USE_CONFIG: 1
@ -241,7 +242,7 @@ steps:
- name: test-mysql - name: test-mysql
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_TESTS_USE_CONFIG: 1
@ -258,7 +259,7 @@ steps:
- name: test-postgres - name: test-postgres
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_TESTS_USE_CONFIG: 1
@ -276,7 +277,7 @@ steps:
- name: integration-test - name: integration-test
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
commands: commands:
@ -287,7 +288,7 @@ steps:
- name: integration-test-sqlite - name: integration-test-sqlite
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_TESTS_USE_CONFIG: 1
@ -304,7 +305,7 @@ steps:
- name: integration-test-mysql - name: integration-test-mysql
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_TESTS_USE_CONFIG: 1
@ -321,7 +322,7 @@ steps:
- name: integration-test-postgres - name: integration-test-postgres
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
VIKUNJA_TESTS_USE_CONFIG: 1 VIKUNJA_TESTS_USE_CONFIG: 1
@ -343,14 +344,15 @@ steps:
######## ########
kind: pipeline kind: pipeline
type: docker
name: release name: release
depends_on: depends_on:
- testing - testing
workspace: workspace:
base: /go base: /source
path: src/code.vikunja.io/api path: /
trigger: trigger:
ref: ref:
@ -368,7 +370,7 @@ steps:
# compiling the same magefile at the same time. It's also faster if each step does not need to compile it first. # compiling the same magefile at the same time. It's also faster if each step does not need to compile it first.
- name: mage - name: mage
image: vikunja/golang-build:latest image: vikunja/golang-build:latest
pull: true pull: always
environment: environment:
GOPROXY: 'https://goproxy.kolaente.de' GOPROXY: 'https://goproxy.kolaente.de'
commands: commands:
@ -378,7 +380,7 @@ steps:
- name: before-static-build - name: before-static-build
image: techknowlogick/xgo:latest image: techknowlogick/xgo:latest
pull: true pull: always
commands: commands:
- export PATH=$PATH:$GOPATH/bin - export PATH=$PATH:$GOPATH/bin
- go install github.com/magefile/mage - go install github.com/magefile/mage
@ -387,7 +389,7 @@ steps:
- name: static-build-windows - name: static-build-windows
image: techknowlogick/xgo:latest image: techknowlogick/xgo:latest
pull: true pull: always
environment: environment:
# This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why. # This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why.
# Leaving this here until we know how to resolve this properly. # Leaving this here until we know how to resolve this properly.
@ -400,7 +402,7 @@ steps:
- name: static-build-linux - name: static-build-linux
image: techknowlogick/xgo:latest image: techknowlogick/xgo:latest
pull: true pull: always
environment: environment:
# This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why. # This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why.
# Leaving this here until we know how to resolve this properly. # Leaving this here until we know how to resolve this properly.
@ -413,7 +415,7 @@ steps:
- name: static-build-darwin - name: static-build-darwin
image: techknowlogick/xgo:latest image: techknowlogick/xgo:latest
pull: true pull: always
environment: environment:
# This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why. # This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why.
# Leaving this here until we know how to resolve this properly. # Leaving this here until we know how to resolve this properly.
@ -426,7 +428,7 @@ steps:
- name: after-build-compress - name: after-build-compress
image: kolaente/upx image: kolaente/upx
pull: true pull: always
depends_on: depends_on:
- static-build-windows - static-build-windows
- static-build-linux - static-build-linux
@ -436,7 +438,7 @@ steps:
- name: after-build-static - name: after-build-static
image: techknowlogick/xgo:latest image: techknowlogick/xgo:latest
pull: true pull: always
depends_on: depends_on:
- after-build-compress - after-build-compress
commands: commands:
@ -448,7 +450,7 @@ steps:
- name: sign-release - name: sign-release
image: plugins/gpgsign:1 image: plugins/gpgsign:1
pull: true pull: always
depends_on: [ after-build-static ] depends_on: [ after-build-static ]
settings: settings:
key: key:
@ -462,7 +464,7 @@ steps:
# Push the releases to our pseudo-s3-bucket # Push the releases to our pseudo-s3-bucket
- name: release-latest - name: release-latest
image: plugins/s3 image: plugins/s3
pull: true pull: always
settings: settings:
bucket: vikunja-releases bucket: vikunja-releases
access_key: access_key:
@ -484,7 +486,7 @@ steps:
- name: release-version - name: release-version
image: plugins/s3 image: plugins/s3
pull: true pull: always
settings: settings:
bucket: vikunja-releases bucket: vikunja-releases
access_key: access_key:
@ -504,8 +506,8 @@ steps:
# Build os packages and push it to our bucket # Build os packages and push it to our bucket
- name: build-os-packages-unstable - name: build-os-packages-unstable
image: goreleaser/nfpm image: goreleaser/nfpm:v2.22.2
pull: true pull: always
commands: commands:
- apk add git go - apk add git go
- ./mage-static release:packages - ./mage-static release:packages
@ -517,11 +519,11 @@ steps:
- main - main
event: event:
- push - push
depends_on: [ static-build-linux ] depends_on: [ after-build-compress ]
- name: build-os-packages-version - name: build-os-packages-version
image: goreleaser/nfpm image: goreleaser/nfpm:v2.22.2
pull: true pull: always
commands: commands:
- apk add git go - apk add git go
- ./mage-static release:packages - ./mage-static release:packages
@ -531,12 +533,12 @@ steps:
when: when:
event: event:
- tag - tag
depends_on: [ static-build-linux ] depends_on: [ after-build-compress ]
# Push the os releases to our pseudo-s3-bucket # Push the os releases to our pseudo-s3-bucket
- name: release-os-latest - name: release-os-latest
image: plugins/s3 image: plugins/s3
pull: true pull: always
settings: settings:
bucket: vikunja-releases bucket: vikunja-releases
access_key: access_key:
@ -558,7 +560,7 @@ steps:
- name: release-os-version - name: release-os-version
image: plugins/s3 image: plugins/s3
pull: true pull: always
settings: settings:
bucket: vikunja-releases bucket: vikunja-releases
access_key: access_key:
@ -578,6 +580,7 @@ steps:
--- ---
kind: pipeline kind: pipeline
type: docker
name: deploy-docs name: deploy-docs
workspace: workspace:
@ -596,8 +599,7 @@ trigger:
steps: steps:
- name: theme - name: theme
image: kolaente/toolbox image: kolaente/toolbox
pull: true pull: always
group: build-static
commands: commands:
- mkdir docs/themes/vikunja -p - mkdir docs/themes/vikunja -p
- cd docs/themes/vikunja - cd docs/themes/vikunja
@ -606,7 +608,7 @@ steps:
- name: build - name: build
image: klakegg/hugo:0.107.0 image: klakegg/hugo:0.107.0
pull: true pull: always
commands: commands:
- cd docs - cd docs
- hugo - hugo
@ -614,7 +616,7 @@ steps:
- name: docker - name: docker
image: plugins/docker image: plugins/docker
pull: true pull: always
settings: settings:
username: username:
from_secret: docker_username from_secret: docker_username
@ -646,7 +648,7 @@ steps:
- name: docker-unstable - name: docker-unstable
image: thegeeklab/drone-docker-buildx image: thegeeklab/drone-docker-buildx
privileged: true privileged: true
pull: true pull: always
settings: settings:
username: username:
from_secret: docker_username from_secret: docker_username
@ -668,7 +670,7 @@ steps:
- name: docker-release - name: docker-release
image: thegeeklab/drone-docker-buildx image: thegeeklab/drone-docker-buildx
privileged: true privileged: true
pull: true pull: always
settings: settings:
username: username:
from_secret: docker_username from_secret: docker_username
@ -719,6 +721,6 @@ steps:
- failure - failure
--- ---
kind: signature kind: signature
hmac: 768d54fc8433705fb63f754adf19536a16152a4046a040afdbcbb7df60614056 hmac: 2c7e3250304826cb62d54db4e6d2638bc8f182097306fb93772d07d7bc3cf7e8
... ...

View File

@ -1,58 +0,0 @@
name: Bug Report
description: Found something you weren't expecting? Report it here!
labels: kind/bug
body:
- type: markdown
attributes:
value: |
NOTE: If your issue is a security concern, please send an email to security@vikunja.io instead of opening a public issue.
- type: markdown
attributes:
value: |
Please fill out this issue template to report a bug.
1. If you want to propose a new feature, please open a discussion thread in the forum: https://community.vikunja.io
2. Please ask questions or configuration/deploy problems on our [Matrix Room](https://matrix.to/#/#vikunja:matrix.org) or forum (https://community.vikunja.io).
3. Make sure you are using the latest release and
take a moment to check that your issue hasn't been reported before.
4. Please give all relevant information below for bug reports, because
incomplete details will be handled as an invalid report and closed.
- type: textarea
id: description
attributes:
label: Description
description: |
Please provide a description of your issue here, with a URL if you were able to reproduce the issue (see below).
- type: input
id: frontend-version
attributes:
label: Vikunja Frontend Version
description: Vikunja frontend version (or commit reference) of your instance
validations:
required: true
- type: input
id: api-version
attributes:
label: Vikunja API Version
description: Vikunja API version (or commit reference) of your instance
validations:
required: true
- type: input
id: browser-version
attributes:
label: Browser and version
description: If your issue is related to a frontend problem, please provide the browser and version you used to reproduce it.
- type: dropdown
id: can-reproduce
attributes:
label: Can you reproduce the bug on the Vikunja demo site?
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If this issue involves the Web Interface, please provide one or more screenshots

View File

@ -1,7 +1,7 @@
############## ##############
# Build stage # Build stage
FROM --platform=$BUILDPLATFORM techknowlogick/xgo:latest AS build-env FROM --platform=$BUILDPLATFORM techknowlogick/xgo:go-1.19.2 AS build-env
RUN \ RUN \
go install github.com/magefile/mage@latest && \ go install github.com/magefile/mage@latest && \

View File

@ -191,21 +191,6 @@ files:
maxsize: 20MB maxsize: 20MB
migration: migration:
# These are the settings for the wunderlist migrator
wunderlist:
# Wheter to enable the wunderlist migrator or not
enable: false
# The client id, required for making requests to the wunderlist api
# You need to register your vikunja instance at https://developer.wunderlist.com/apps/new to get this
clientid:
# The client secret, also required for making requests to the wunderlist api
clientsecret:
# The url where clients are redirected after they authorized Vikunja to access their wunderlist stuff.
# This needs to match the url you entered when registering your Vikunja instance at wunderlist.
# This is usually the frontend url where the frontend then makes a request to /migration/wunderlist/migrate
# with the code obtained from the wunderlist api.
# Note that the vikunja frontend expects this to be /migrate/wunderlist
redirecturl:
todoist: todoist:
# Wheter to enable the todoist migrator or not # Wheter to enable the todoist migrator or not
enable: false enable: false
@ -311,6 +296,9 @@ auth:
- name: - name:
# The auth url to send users to if they want to authenticate using OpenID Connect. # The auth url to send users to if they want to authenticate using OpenID Connect.
authurl: authurl:
# The oidc logouturl that users will be redirected to on logout.
# Leave empty or delete key, if you do not want to be redirected.
logouturl:
# The client ID used to authenticate Vikunja at the OpenID Connect provider. # The client ID used to authenticate Vikunja at the OpenID Connect provider.
clientid: clientid:
# The client secret used to authenticate Vikunja at the OpenID Connect provider. # The client secret used to authenticate Vikunja at the OpenID Connect provider.

View File

@ -969,17 +969,6 @@ Environment path: `VIKUNJA_FILES_MAXSIZE`
### wunderlist
These are the settings for the wunderlist migrator
Default: `<empty>`
Full path: `migration.wunderlist`
Environment path: `VIKUNJA_MIGRATION_WUNDERLIST`
### todoist ### todoist
Default: `<empty>` Default: `<empty>`

View File

@ -10,7 +10,7 @@ menu:
# Full docker example # Full docker example
This docker compose configuration will run Vikunja with backend and frontend with a mariadb as database. This docker compose configuration will run Vikunja with backend and frontend with a mariadb database.
It uses an nginx container or traefik on the host to proxy backend and frontend into a single port. It uses an nginx container or traefik on the host to proxy backend and frontend into a single port.
For all available configuration options, see [configuration]({{< ref "config.md">}}). For all available configuration options, see [configuration]({{< ref "config.md">}}).
@ -76,7 +76,7 @@ This example lets you host Vikunja without any reverse proxy in front of it. Thi
you need to get something up and running. If you want to host Vikunja on one single port instead of two different ones you need to get something up and running. If you want to host Vikunja on one single port instead of two different ones
or need tls termination, check out one of the other examples. or need tls termination, check out one of the other examples.
Not that you need to change the `VIKUNJA_API_URL` environment variable to the ip (the docker host you're running this on) Note that you need to change the `VIKUNJA_API_URL` environment variable to the ip (the docker host you're running this on)
is reachable at. Because the browser you'll use to access the Vikunja frontend uses that url to make the requests, it is reachable at. Because the browser you'll use to access the Vikunja frontend uses that url to make the requests, it
has to be able to reach that ip + port from the outside. Putting everything in a private network won't work. has to be able to reach that ip + port from the outside. Putting everything in a private network won't work.
@ -125,7 +125,7 @@ services:
This example assumes [traefik](https://traefik.io) version 2 installed and configured to [use docker as a configuration provider](https://docs.traefik.io/providers/docker/). This example assumes [traefik](https://traefik.io) version 2 installed and configured to [use docker as a configuration provider](https://docs.traefik.io/providers/docker/).
We also make a few assumtions here which you'll most likely need to adjust for your traefik setup: We also make a few assumptions here which you'll most likely need to adjust for your traefik setup:
* Your domain is `vikunja.example.com` * Your domain is `vikunja.example.com`
* The entrypoint you want to make vikunja available from is called `https` * The entrypoint you want to make vikunja available from is called `https`
@ -398,7 +398,7 @@ docker main folders:
* vikunja * vikunja
* mariadb * mariadb
Synology has it's own GUI for managing Docker containers... But it's easier via docker compose. Synology has its own GUI for managing Docker containers... But it's easier via docker compose.
To do that, you can To do that, you can
@ -407,7 +407,7 @@ To do that, you can
* without activating SSH, by using Portainer (you have to install first, check out [this tutorial](https://www.portainer.io/blog/how-to-install-portainer-on-a-synology-nas) for exmple): * without activating SSH, by using Portainer (you have to install first, check out [this tutorial](https://www.portainer.io/blog/how-to-install-portainer-on-a-synology-nas) for exmple):
1. Go to **Dashboard / Stacks** click the button **"Add Stack"** 1. Go to **Dashboard / Stacks** click the button **"Add Stack"**
2. Give it the name Vikunja and paste the adapted docker compose file 2. Give it the name Vikunja and paste the adapted docker compose file
3. Deploy the Stack with the "Delpoy Stack" button: 3. Deploy the Stack with the "Deploy Stack" button:
![Portainer Stack deploy](/docs/synology-proxy-2.png) ![Portainer Stack deploy](/docs/synology-proxy-2.png)

View File

@ -10,6 +10,6 @@ menu:
There are two third-party Helm-Charts which can be used to host Vikunja with k8s: There are two third-party Helm-Charts which can be used to host Vikunja with k8s:
* [Truecharts](https://truecharts.org/docs/charts/stable/vikunja/) * [Truecharts](https://truecharts.org/charts/stable/vikunja/)
* [k8s at Home](https://github.com/k8s-at-home/charts) * [k8s at Home](https://github.com/k8s-at-home/charts)

36
go.mod
View File

@ -25,30 +25,31 @@ require (
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
github.com/bbrks/go-blurhash v1.1.1 github.com/bbrks/go-blurhash v1.1.1
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
github.com/coreos/go-oidc/v3 v3.4.0 github.com/coreos/go-oidc/v3 v3.5.0
github.com/cweill/gotests v1.6.0 github.com/cweill/gotests v1.6.0
github.com/d4l3k/messagediff v1.2.1 github.com/d4l3k/messagediff v1.2.1
github.com/disintegration/imaging v1.6.2 github.com/disintegration/imaging v1.6.2
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0 github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
github.com/gabriel-vasile/mimetype v1.4.1 github.com/gabriel-vasile/mimetype v1.4.1
github.com/getsentry/sentry-go v0.15.0 github.com/getsentry/sentry-go v0.16.0
github.com/go-redis/redis/v8 v8.11.5 github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.6.0 github.com/go-sql-driver/mysql v1.7.0
github.com/go-testfixtures/testfixtures/v3 v3.8.1 github.com/go-testfixtures/testfixtures/v3 v3.8.1
github.com/golang-jwt/jwt/v4 v4.4.2 github.com/golang-jwt/jwt/v4 v4.4.3
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/uuid v1.3.0 github.com/google/uuid v1.3.0
github.com/iancoleman/strcase v0.2.0 github.com/iancoleman/strcase v0.2.0
github.com/imdario/mergo v0.3.13 github.com/imdario/mergo v0.3.13
github.com/jinzhu/copier v0.3.5 github.com/jinzhu/copier v0.3.5
github.com/labstack/echo/v4 v4.9.1 github.com/labstack/echo-jwt/v4 v4.0.0
github.com/labstack/echo/v4 v4.10.0
github.com/labstack/gommon v0.4.0 github.com/labstack/gommon v0.4.0
github.com/lib/pq v1.10.7 github.com/lib/pq v1.10.7
github.com/magefile/mage v1.14.0 github.com/magefile/mage v1.14.0
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16
github.com/olekukonko/tablewriter v0.0.5 github.com/olekukonko/tablewriter v0.0.5
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pquerna/otp v1.3.0 github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.14.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/samedi/caldav-go v3.0.0+incompatible github.com/samedi/caldav-go v3.0.0+incompatible
@ -56,18 +57,18 @@ require (
github.com/spf13/cobra v1.6.1 github.com/spf13/cobra v1.6.1
github.com/spf13/viper v1.14.0 github.com/spf13/viper v1.14.0
github.com/stretchr/testify v1.8.1 github.com/stretchr/testify v1.8.1
github.com/swaggo/swag v1.8.7 github.com/swaggo/swag v1.8.9
github.com/tkuchiki/go-timezone v0.2.2 github.com/tkuchiki/go-timezone v0.2.2
github.com/ulule/limiter/v3 v3.10.0 github.com/ulule/limiter/v3 v3.10.0
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93 github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93
github.com/wneessen/go-mail v0.3.5 github.com/wneessen/go-mail v0.3.7
github.com/yuin/goldmark v1.5.3 github.com/yuin/goldmark v1.5.3
golang.org/x/crypto v0.3.0 golang.org/x/crypto v0.5.0
golang.org/x/image v0.1.0 golang.org/x/image v0.3.0
golang.org/x/oauth2 v0.1.0 golang.org/x/oauth2 v0.3.0
golang.org/x/sync v0.1.0 golang.org/x/sync v0.1.0
golang.org/x/sys v0.2.0 golang.org/x/sys v0.4.0
golang.org/x/term v0.2.0 golang.org/x/term v0.4.0
gopkg.in/d4l3k/messagediff.v1 v1.2.1 gopkg.in/d4l3k/messagediff.v1 v1.2.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
src.techknowlogick.com/xgo v1.5.1-0.20220906164532-735bfdfb90d9 src.techknowlogick.com/xgo v1.5.1-0.20220906164532-735bfdfb90d9
@ -92,6 +93,7 @@ require (
github.com/garyburd/redigo v1.6.0 // indirect github.com/garyburd/redigo v1.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-chi/chi v4.0.2+incompatible // indirect github.com/go-chi/chi v4.0.2+incompatible // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect github.com/go-openapi/spec v0.20.4 // indirect
@ -133,11 +135,11 @@ require (
github.com/syndtr/goleveldb v1.0.0 // indirect github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/urfave/cli/v2 v2.3.0 // indirect github.com/urfave/cli/v2 v2.3.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.2.0 // indirect golang.org/x/net v0.5.0 // indirect
golang.org/x/text v0.4.0 // indirect golang.org/x/text v0.6.0 // indirect
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.1.12 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect

126
go.sum
View File

@ -43,6 +43,7 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
@ -99,10 +100,6 @@ github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/arran4/golang-ical v0.0.0-20220517104411-fd89fefb0182 h1:mUsKridvWp4dgfkO/QWtgGwuLtZYpjKgsm15JRRik3o=
github.com/arran4/golang-ical v0.0.0-20220517104411-fd89fefb0182/go.mod h1:BSTTrYHuM12oAL8jDdcmPdw02SBThKYWNFHQlvEG6b0=
github.com/arran4/golang-ical v0.0.0-20221118224027-a67735377457 h1:92BQ/SqY/2cFSA0Nq0O2Ei7WIdjLg9Jz7pyBDX4qKRI=
github.com/arran4/golang-ical v0.0.0-20221118224027-a67735377457/go.mod h1:BSTTrYHuM12oAL8jDdcmPdw02SBThKYWNFHQlvEG6b0=
github.com/arran4/golang-ical v0.0.0-20221122102835-109346913e54 h1:HfAA5Vxbo64UTckj+EW/hfBjvvcUcbcwWCASvypy8JU= github.com/arran4/golang-ical v0.0.0-20221122102835-109346913e54 h1:HfAA5Vxbo64UTckj+EW/hfBjvvcUcbcwWCASvypy8JU=
github.com/arran4/golang-ical v0.0.0-20221122102835-109346913e54/go.mod h1:BSTTrYHuM12oAL8jDdcmPdw02SBThKYWNFHQlvEG6b0= github.com/arran4/golang-ical v0.0.0-20221122102835-109346913e54/go.mod h1:BSTTrYHuM12oAL8jDdcmPdw02SBThKYWNFHQlvEG6b0=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
@ -152,6 +149,8 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g= github.com/coreos/go-oidc/v3 v3.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g=
github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw=
github.com/coreos/go-oidc/v3 v3.5.0 h1:VxKtbccHZxs8juq7RdJntSqtXFtde9YpNpGn0yqgEHw=
github.com/coreos/go-oidc/v3 v3.5.0/go.mod h1:ecXRtV4romGPeO6ieExAsUK9cb/3fp9hXNz1tlv8PIM=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -202,18 +201,14 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M= github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/getsentry/sentry-go v0.14.0 h1:rlOBkuFZRKKdUnKO+0U3JclRDQKlRu5vVQtkWSQvC70= github.com/getsentry/sentry-go v0.16.0 h1:owk+S+5XcgJLlGR/3+3s6N4d+uKwqYvh/eS0AIMjPWo=
github.com/getsentry/sentry-go v0.14.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I= github.com/getsentry/sentry-go v0.16.0/go.mod h1:ZXCloQLj0pG7mja5NK6NPf2V4A88YJ4pNlc2mOHwh6Y=
github.com/getsentry/sentry-go v0.15.0 h1:CP9bmA7pralrVUedYZsmIHWpq/pBtXTSew7xvVpfLaA=
github.com/getsentry/sentry-go v0.15.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
@ -222,6 +217,8 @@ github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxI
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
@ -246,8 +243,9 @@ github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-testfixtures/testfixtures/v3 v3.8.1 h1:uonwvepqRvSgddcrReZQhojTlWlmOlHkYAb9ZaOMWgU= github.com/go-testfixtures/testfixtures/v3 v3.8.1 h1:uonwvepqRvSgddcrReZQhojTlWlmOlHkYAb9ZaOMWgU=
github.com/go-testfixtures/testfixtures/v3 v3.8.1/go.mod h1:Kdu7YeMC0KRXVHdaQ91Vmx3pcjoTF63h4f1qTJDdXLA= github.com/go-testfixtures/testfixtures/v3 v3.8.1/go.mod h1:Kdu7YeMC0KRXVHdaQ91Vmx3pcjoTF63h4f1qTJDdXLA=
@ -262,8 +260,8 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@ -505,9 +503,11 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo-jwt/v4 v4.0.0 h1:MFdURJRtBNWzADUdXYlj++71UZ5MmjUtce7nSsCH8NY=
github.com/labstack/echo-jwt/v4 v4.0.0/go.mod h1:DHSSaL6cTgczdPXjf8qrTHRbrau2flcddV7CPMs2U/Y=
github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI= github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
github.com/labstack/echo/v4 v4.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y= github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA=
github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo= github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
@ -562,8 +562,6 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
@ -639,8 +637,8 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@ -648,10 +646,6 @@ github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeD
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.13.1 h1:3gMjIY2+/hzmqhtUC/aQNYldJA6DtH3CgQvwS+02K1c=
github.com/prometheus/client_golang v1.13.1/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@ -659,7 +653,6 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
@ -713,15 +706,11 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw=
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
@ -729,8 +718,6 @@ github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU=
github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw=
github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU=
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@ -748,14 +735,13 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU= github.com/swaggo/swag v1.8.9 h1:kHtaBe/Ob9AZzAANfcn5c6RyCke9gG9QpH0jky0I/sA=
github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= github.com/swaggo/swag v1.8.9/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tkuchiki/go-timezone v0.2.2 h1:MdHR65KwgVTwWFQrota4SKzc4L5EfuH5SdZZGtk/P2Q= github.com/tkuchiki/go-timezone v0.2.2 h1:MdHR65KwgVTwWFQrota4SKzc4L5EfuH5SdZZGtk/P2Q=
@ -772,20 +758,15 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/valyala/fasttemplate v1.2.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93 h1:bT0ZMfsMi2Xh8dopgxhFT+OJH88QITHpdppdkG1rXJQ= github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93 h1:bT0ZMfsMi2Xh8dopgxhFT+OJH88QITHpdppdkG1rXJQ=
github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ= github.com/vectordotdev/go-datemath v0.1.1-0.20211214182920-0a4ac8742b93/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ=
github.com/wneessen/go-mail v0.3.1 h1:9hSthi8T57gDHMI0fgl58O667OQJm9wZ1EHyuy3hclA= github.com/wneessen/go-mail v0.3.6 h1:hT8PMIBdcTkoiDwoUGJssPYOe1Gg1/cUcp2o9+ls63o=
github.com/wneessen/go-mail v0.3.1/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E= github.com/wneessen/go-mail v0.3.6/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
github.com/wneessen/go-mail v0.3.2 h1:nTjAF4Ek2+JG7qunyk6oImf5YKrAE5a7A3uIazYsdM0= github.com/wneessen/go-mail v0.3.7 h1:loEAGLvsDZLSiE6c+keBfg0gpias/R3ocFU8Eoh3Pq4=
github.com/wneessen/go-mail v0.3.2/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E= github.com/wneessen/go-mail v0.3.7/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
github.com/wneessen/go-mail v0.3.3 h1:mhqM18uWiBFA3TdfO2IyFfQ6dEj4kGKW1KQJJNSKLME=
github.com/wneessen/go-mail v0.3.3/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
github.com/wneessen/go-mail v0.3.4 h1:75G6lojt3CxwSq73csMduxF7DJ3hLF2s2KJXJVDOr0k=
github.com/wneessen/go-mail v0.3.4/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
github.com/wneessen/go-mail v0.3.5 h1:5fl4O1SnBpA072WFD+q1KBX6L3ltiIsKQDYjs7sY7GM=
github.com/wneessen/go-mail v0.3.5/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -793,8 +774,6 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.2 h1:ALmeCk/px5FSm1MAcFBAsVKZjDuMVj8Tm7FFIlMJnqU=
github.com/yuin/goldmark v1.5.2/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M= github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M=
github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
@ -843,12 +822,10 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -862,8 +839,10 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk= golang.org/x/image v0.2.0 h1:/DcQ0w3VHKCC5p0/P2B0JpAZ9Z++V2KOo2fyU89CXBQ=
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c= golang.org/x/image v0.2.0/go.mod h1:la7oBXb9w3YFjBqaAwtynVioc1ZvOnNteUNrifGNmAI=
golang.org/x/image v0.3.0 h1:HTDXbdK9bjfSWkPzDJIw89W8CAtfFGduujWs33NLLsg=
golang.org/x/image v0.3.0/go.mod h1:fXd9211C/0VTlYuAcOhW8dY/RtEJqODXOWBDpmYBf+A=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -945,10 +924,11 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -970,8 +950,8 @@ golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
golang.org/x/oauth2 v0.1.0 h1:isLCZuhj4v+tYv7eskaN4v/TM+A1begWWgyVJDdl1+Y= golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1080,17 +1060,17 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1100,15 +1080,17 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -703,7 +703,7 @@ func (Release) Packages() error {
binpath := "nfpm" binpath := "nfpm"
err = exec.Command(binpath).Run() err = exec.Command(binpath).Run()
if err != nil && strings.Contains(err.Error(), "executable file not found") { if err != nil && strings.Contains(err.Error(), "executable file not found") {
binpath = "/nfpm" binpath = "/usr/bin/nfpm"
err = exec.Command(binpath).Run() err = exec.Command(binpath).Run()
} }
if err != nil && strings.Contains(err.Error(), "executable file not found") { if err != nil && strings.Contains(err.Error(), "executable file not found") {

View File

@ -22,7 +22,8 @@ import (
"strings" "strings"
"time" "time"
"code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user" "code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils" "code.vikunja.io/api/pkg/utils"
) )
@ -62,6 +63,8 @@ type Todo struct {
End time.Time End time.Time
DueDate time.Time DueDate time.Time
Duration time.Duration Duration time.Duration
RepeatAfter int64
RepeatMode models.TaskRepeatMode
Created time.Time Created time.Time
Updated time.Time // last-mod Updated time.Time // last-mod
@ -226,6 +229,16 @@ CREATED:` + makeCalDavTimeFromTimeStamp(t.Created)
PRIORITY:` + strconv.Itoa(mapPriorityToCaldav(t.Priority)) PRIORITY:` + strconv.Itoa(mapPriorityToCaldav(t.Priority))
} }
if t.RepeatAfter > 0 || t.RepeatMode == models.TaskRepeatModeMonth {
if t.RepeatMode == models.TaskRepeatModeMonth {
caldavtodos += `
RRULE:FREQ=MONTHLY;BYMONTHDAY=` + t.DueDate.Format("02") // Day of the month
} else {
caldavtodos += `
RRULE:FREQ=SECONDLY;INTERVAL=` + strconv.FormatInt(t.RepeatAfter, 10)
}
}
caldavtodos += ` caldavtodos += `
LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated) LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated)
@ -240,7 +253,7 @@ END:VCALENDAR` // Need a line break
} }
func makeCalDavTimeFromTimeStamp(ts time.Time) (caldavtime string) { func makeCalDavTimeFromTimeStamp(ts time.Time) (caldavtime string) {
return ts.In(config.GetTimeZone()).Format(DateFormat) return ts.In(time.UTC).Format(DateFormat) + "Z"
} }
func calcAlarmDateFromReminder(eventStart, reminder time.Time) (alarmTime string) { func calcAlarmDateFromReminder(eventStart, reminder time.Time) (alarmTime string) {

View File

@ -20,6 +20,8 @@ import (
"testing" "testing"
"time" "time"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/config"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -84,25 +86,25 @@ X-APPLE-CALENDAR-COLOR:#affffeFF
X-OUTLOOK-COLOR:#affffeFF X-OUTLOOK-COLOR:#affffeFF
X-FUNAMBOL-COLOR:#affffeFF X-FUNAMBOL-COLOR:#affffeFF
DESCRIPTION:Lorem Ipsum DESCRIPTION:Lorem Ipsum
DTSTAMP:20181201T011204 DTSTAMP:20181201T011204Z
DTSTART:20181201T011204 DTSTART:20181201T011204Z
DTEND:20181201T013024 DTEND:20181201T013024Z
END:VEVENT END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
UID:randommduidd UID:randommduidd
SUMMARY:Event #2 SUMMARY:Event #2
DESCRIPTION: DESCRIPTION:
DTSTAMP:20181202T045844 DTSTAMP:20181202T045844Z
DTSTART:20181202T045844 DTSTART:20181202T045844Z
DTEND:20181202T081844 DTEND:20181202T081844Z
END:VEVENT END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
UID:20181202T0600242aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83 UID:20181202T0600242aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83
SUMMARY:Event #3 with empty uid SUMMARY:Event #3 with empty uid
DESCRIPTION: DESCRIPTION:
DTSTAMP:20181202T050024 DTSTAMP:20181202T050024Z
DTSTART:20181202T050024 DTSTART:20181202T050024Z
DTEND:20181202T050320 DTEND:20181202T050320Z
END:VEVENT END:VEVENT
END:VCALENDAR`, END:VCALENDAR`,
}, },
@ -169,9 +171,9 @@ BEGIN:VEVENT
UID:randommduid UID:randommduid
SUMMARY:Event #1 SUMMARY:Event #1
DESCRIPTION:Lorem Ipsum DESCRIPTION:Lorem Ipsum
DTSTAMP:20181201T011204 DTSTAMP:20181201T011204Z
DTSTART:20181201T011204 DTSTART:20181201T011204Z
DTEND:20181201T013024 DTEND:20181201T013024Z
BEGIN:VALARM BEGIN:VALARM
TRIGGER:-PT3M20S TRIGGER:-PT3M20S
ACTION:DISPLAY ACTION:DISPLAY
@ -192,9 +194,9 @@ BEGIN:VEVENT
UID:randommduidd UID:randommduidd
SUMMARY:Event #2 SUMMARY:Event #2
DESCRIPTION: DESCRIPTION:
DTSTAMP:20181202T045844 DTSTAMP:20181202T045844Z
DTSTART:20181202T045844 DTSTART:20181202T045844Z
DTEND:20181202T081844 DTEND:20181202T081844Z
BEGIN:VALARM BEGIN:VALARM
TRIGGER:-PT27H50M0S TRIGGER:-PT27H50M0S
ACTION:DISPLAY ACTION:DISPLAY
@ -212,12 +214,12 @@ DESCRIPTION:Event #2
END:VALARM END:VALARM
END:VEVENT END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
UID:20181202T0500242aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83 UID:20181202T050024Z2aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83
SUMMARY:Event #3 with empty uid SUMMARY:Event #3 with empty uid
DESCRIPTION: DESCRIPTION:
DTSTAMP:20181202T050024 DTSTAMP:20181202T050024Z
DTSTART:20181202T050024 DTSTART:20181202T050024Z
DTEND:20181202T050320 DTEND:20181202T050320Z
BEGIN:VALARM BEGIN:VALARM
TRIGGER:-PT27H51M40S TRIGGER:-PT27H51M40S
ACTION:DISPLAY ACTION:DISPLAY
@ -240,12 +242,12 @@ DESCRIPTION:Event #3 with empty uid
END:VALARM END:VALARM
END:VEVENT END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
UID:20181202T050024ae7548ce9556df85038abe90dc674d4741a61ce74d1cf UID:20181202T050024Zae7548ce9556df85038abe90dc674d4741a61ce74d1cf
SUMMARY:Event #4 without any SUMMARY:Event #4 without any
DESCRIPTION: DESCRIPTION:
DTSTAMP:20181202T050024 DTSTAMP:20181202T050024Z
DTSTART:20181202T050024 DTSTART:20181202T050024Z
DTEND:20181202T050320 DTEND:20181202T050320Z
END:VEVENT END:VEVENT
END:VCALENDAR`, END:VCALENDAR`,
}, },
@ -278,9 +280,9 @@ BEGIN:VEVENT
UID:randommduid UID:randommduid
SUMMARY:Event #1 SUMMARY:Event #1
DESCRIPTION:Lorem Ipsum\nDolor sit amet DESCRIPTION:Lorem Ipsum\nDolor sit amet
DTSTAMP:20181201T011204 DTSTAMP:20181201T011204Z
DTSTART:20181201T011204 DTSTART:20181201T011204Z
DTEND:20181201T013024 DTEND:20181201T013024Z
END:VEVENT END:VEVENT
END:VCALENDAR`, END:VCALENDAR`,
}, },
@ -333,13 +335,13 @@ X-OUTLOOK-COLOR:#ffffffFF
X-FUNAMBOL-COLOR:#ffffffFF X-FUNAMBOL-COLOR:#ffffffFF
BEGIN:VTODO BEGIN:VTODO
UID:randommduid UID:randommduid
DTSTAMP:20181201T011204 DTSTAMP:20181201T011204Z
SUMMARY:Todo #1 SUMMARY:Todo #1
X-APPLE-CALENDAR-COLOR:#affffeFF X-APPLE-CALENDAR-COLOR:#affffeFF
X-OUTLOOK-COLOR:#affffeFF X-OUTLOOK-COLOR:#affffeFF
X-FUNAMBOL-COLOR:#affffeFF X-FUNAMBOL-COLOR:#affffeFF
DESCRIPTION:Lorem Ipsum\nDolor sit amet DESCRIPTION:Lorem Ipsum\nDolor sit amet
LAST-MODIFIED:00010101T000000 LAST-MODIFIED:00010101T000000Z
END:VTODO END:VTODO
END:VCALENDAR`, END:VCALENDAR`,
}, },
@ -368,12 +370,12 @@ X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN PRODID:-//RandomProdID which is not random//EN
BEGIN:VTODO BEGIN:VTODO
UID:randommduid UID:randommduid
DTSTAMP:20181201T011204 DTSTAMP:20181201T011204Z
SUMMARY:Todo #1 SUMMARY:Todo #1
DESCRIPTION:Lorem Ipsum DESCRIPTION:Lorem Ipsum
COMPLETED:20181201T013024 COMPLETED:20181201T013024Z
STATUS:COMPLETED STATUS:COMPLETED
LAST-MODIFIED:00010101T000000 LAST-MODIFIED:00010101T000000Z
END:VTODO END:VTODO
END:VCALENDAR`, END:VCALENDAR`,
}, },
@ -402,11 +404,82 @@ X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN PRODID:-//RandomProdID which is not random//EN
BEGIN:VTODO BEGIN:VTODO
UID:randommduid UID:randommduid
DTSTAMP:20181201T011204 DTSTAMP:20181201T011204Z
SUMMARY:Todo #1 SUMMARY:Todo #1
DESCRIPTION:Lorem Ipsum DESCRIPTION:Lorem Ipsum
PRIORITY:9 PRIORITY:9
LAST-MODIFIED:00010101T000000 LAST-MODIFIED:00010101T000000Z
END:VTODO
END:VCALENDAR`,
},
{
name: "with repeating monthly",
args: args{
config: &Config{
Name: "test",
ProdID: "RandomProdID which is not random",
},
todos: []*Todo{
{
Summary: "Todo #1",
Description: "Lorem Ipsum",
UID: "randommduid",
Timestamp: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RepeatMode: models.TaskRepeatModeMonth,
DueDate: time.Unix(1543626724, 0).In(config.GetTimeZone()),
},
},
},
wantCaldavtasks: `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN
BEGIN:VTODO
UID:randommduid
DTSTAMP:20181201T011204Z
SUMMARY:Todo #1
DESCRIPTION:Lorem Ipsum
DUE:20181201T011204Z
RRULE:FREQ=MONTHLY;BYMONTHDAY=01
LAST-MODIFIED:00010101T000000Z
END:VTODO
END:VCALENDAR`,
},
{
name: "with repeat mode default",
args: args{
config: &Config{
Name: "test",
ProdID: "RandomProdID which is not random",
},
todos: []*Todo{
{
Summary: "Todo #1",
Description: "Lorem Ipsum",
UID: "randommduid",
Timestamp: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RepeatMode: models.TaskRepeatModeDefault,
DueDate: time.Unix(1543626724, 0).In(config.GetTimeZone()),
RepeatAfter: 435,
},
},
},
wantCaldavtasks: `BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-PUBLISHED-TTL:PT4H
X-WR-CALNAME:test
PRODID:-//RandomProdID which is not random//EN
BEGIN:VTODO
UID:randommduid
DTSTAMP:20181201T011204Z
SUMMARY:Todo #1
DESCRIPTION:Lorem Ipsum
DUE:20181201T011204Z
RRULE:FREQ=SECONDLY;INTERVAL=435
LAST-MODIFIED:00010101T000000Z
END:VTODO END:VTODO
END:VCALENDAR`, END:VCALENDAR`,
}, },

View File

@ -49,6 +49,8 @@ func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*m
Updated: t.Updated, Updated: t.Updated,
DueDate: t.DueDate, DueDate: t.DueDate,
Duration: duration, Duration: duration,
RepeatAfter: t.RepeatAfter,
RepeatMode: t.RepeatMode,
}) })
} }

View File

@ -128,10 +128,6 @@ const (
FilesBasePath Key = `files.basepath` FilesBasePath Key = `files.basepath`
FilesMaxSize Key = `files.maxsize` FilesMaxSize Key = `files.maxsize`
MigrationWunderlistEnable Key = `migration.wunderlist.enable`
MigrationWunderlistClientID Key = `migration.wunderlist.clientid`
MigrationWunderlistClientSecret Key = `migration.wunderlist.clientsecret`
MigrationWunderlistRedirectURL Key = `migration.wunderlist.redirecturl`
MigrationTodoistEnable Key = `migration.todoist.enable` MigrationTodoistEnable Key = `migration.todoist.enable`
MigrationTodoistClientID Key = `migration.todoist.clientid` MigrationTodoistClientID Key = `migration.todoist.clientid`
MigrationTodoistClientSecret Key = `migration.todoist.clientsecret` MigrationTodoistClientSecret Key = `migration.todoist.clientsecret`
@ -369,7 +365,6 @@ func InitDefaultConfig() {
CorsOrigins.setDefault([]string{"*"}) CorsOrigins.setDefault([]string{"*"})
CorsMaxAge.setDefault(0) CorsMaxAge.setDefault(0)
// Migration // Migration
MigrationWunderlistEnable.setDefault(false)
MigrationTodoistEnable.setDefault(false) MigrationTodoistEnable.setDefault(false)
MigrationTrelloEnable.setDefault(false) MigrationTrelloEnable.setDefault(false)
MigrationMicrosoftTodoEnable.setDefault(false) MigrationMicrosoftTodoEnable.setDefault(false)

View File

@ -18,6 +18,7 @@ package db
import ( import (
"encoding/json" "encoding/json"
"strings"
"code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/log"
@ -53,7 +54,35 @@ func Restore(table string, contents []map[string]interface{}) (err error) {
return err return err
} }
meta, err := x.DBMetas()
if err != nil {
return err
}
var metaForCurrentTable *schemas.Table
for _, m := range meta {
if m.Name == table {
metaForCurrentTable = m
break
}
}
if metaForCurrentTable == nil {
log.Fatalf("Could not find table definition for table %s", table)
}
for _, content := range contents { for _, content := range contents {
for colName, value := range content {
// Date fields might get restored as 0001-01-01 from null dates. This can have unintended side-effects like
// users being scheduled for deletion after a restore.
// To avoid this, we set these dates to nil so that they'll end up as null in the db.
col := metaForCurrentTable.GetColumn(colName)
strVal, is := value.(string)
if is && col.SQLType.IsTime() && (strVal == "" || strings.HasPrefix(strVal, "0001-")) {
content[colName] = nil
}
}
if _, err := x.Table(table).Insert(content); err != nil { if _, err := x.Table(table).Insert(content); err != nil {
return err return err
} }

View File

@ -337,6 +337,7 @@
bucket_id: 20 bucket_id: 20
created: 2018-12-01 01:12:04 created: 2018-12-01 01:12:04
updated: 2018-12-01 01:12:04 updated: 2018-12-01 01:12:04
due_date: 2018-10-30 22:25:24
- id: 37 - id: 37
title: 'task #37' title: 'task #37'
done: false done: false

View File

@ -156,7 +156,7 @@ func GetListsByNamespaceID(s *xorm.Session, nID int64, doer *user.User) (lists [
Alias("l"). Alias("l").
Join("LEFT", []string{"namespaces", "n"}, "l.namespace_id = n.id"). Join("LEFT", []string{"namespaces", "n"}, "l.namespace_id = n.id").
Where("l.is_archived = false"). Where("l.is_archived = false").
Where("n.is_archived = false"). Where("n.is_archived = false OR n.is_archived IS NULL").
Where("namespace_id = ?", nID). Where("namespace_id = ?", nID).
Find(&lists) Find(&lists)
} }

View File

@ -37,7 +37,9 @@ func getUndoneOverdueTasks(s *xorm.Session, now time.Time) (usersWithTasks map[i
var tasks []*Task var tasks []*Task
err = s. err = s.
Where("due_date is not null and due_date < ?", nextMinute.Add(time.Hour*14).Format(dbTimeFormat)). Where("due_date is not null AND due_date < ? AND lists.is_archived = false AND namespaces.is_archived = false", nextMinute.Add(time.Hour*14).Format(dbTimeFormat)).
Join("LEFT", "lists", "lists.id = tasks.list_id").
Join("LEFT", "namespaces", "lists.namespace_id = namespaces.id").
And("done = false"). And("done = false").
Find(&tasks) Find(&tasks)
if err != nil { if err != nil {
@ -138,9 +140,13 @@ func RegisterOverdueReminderCron() {
} }
if len(ut.tasks) == 1 { if len(ut.tasks) == 1 {
// We know there's only one entry in the map so this is actually O(1) and we can use it to get the
// first entry without knowing the key of it.
for _, t := range ut.tasks {
n = &UndoneTaskOverdueNotification{ n = &UndoneTaskOverdueNotification{
User: ut.user, User: ut.user,
Task: ut.tasks[0], Task: t,
}
} }
} }

View File

@ -830,6 +830,11 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke
} }
} }
if task.BucketID == 0 && originalTask != nil && originalTask.BucketID != 0 {
task.BucketID = originalTask.BucketID
}
// Either no bucket was provided or the task was moved between lists
if task.BucketID == 0 || (originalTask != nil && task.ListID != 0 && originalTask.ListID != task.ListID) { if task.BucketID == 0 || (originalTask != nil && task.ListID != 0 && originalTask.ListID != task.ListID) {
bucket, err = getDefaultBucket(s, task.ListID) bucket, err = getDefaultBucket(s, task.ListID)
if err != nil { if err != nil {
@ -1026,7 +1031,7 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
// When a repeating task is marked as done, we update all deadlines and reminders and set it as undone // When a repeating task is marked as done, we update all deadlines and reminders and set it as undone
updateDone(&ot, t) updateDone(&ot, t)
if err := setTaskBucket(s, t, &ot, t.BucketID != ot.BucketID); err != nil { if err := setTaskBucket(s, t, &ot, t.BucketID != 0 && t.BucketID != ot.BucketID); err != nil {
return err return err
} }
@ -1369,7 +1374,7 @@ func setTaskDatesFromCurrentDateRepeat(oldTask, newTask *Task) {
// This helper function updates the reminders, doneAt, start and end dates of the *old* task // This helper function updates the reminders, doneAt, start and end dates of the *old* task
// and saves the new values in the newTask object. // and saves the new values in the newTask object.
// We make a few assumtions here: // We make a few assumptions here:
// 1. Everything in oldTask is the truth - we figure out if we update anything at all if oldTask.RepeatAfter has a value > 0 // 1. Everything in oldTask is the truth - we figure out if we update anything at all if oldTask.RepeatAfter has a value > 0
// 2. Because of 1., this functions should not be used to update values other than Done in the same go // 2. Because of 1., this functions should not be used to update values other than Done in the same go
func updateDone(oldTask *Task, newTask *Task) { func updateDone(oldTask *Task, newTask *Task) {

View File

@ -51,6 +51,7 @@ type Provider struct {
Key string `json:"key"` Key string `json:"key"`
OriginalAuthURL string `json:"-"` OriginalAuthURL string `json:"-"`
AuthURL string `json:"auth_url"` AuthURL string `json:"auth_url"`
LogoutURL string `json:"logout_url"`
ClientID string `json:"client_id"` ClientID string `json:"client_id"`
ClientSecret string `json:"-"` ClientSecret string `json:"-"`
openIDProvider *oidc.Provider openIDProvider *oidc.Provider

View File

@ -60,6 +60,7 @@ func GetAllProviders() (providers []*Provider, err error) {
} }
provider, err := getProviderFromMap(pi) provider, err := getProviderFromMap(pi)
if err != nil { if err != nil {
if provider != nil { if provider != nil {
log.Errorf("Error while getting openid provider %s: %s", provider.Name, err) log.Errorf("Error while getting openid provider %s: %s", provider.Name, err)
@ -119,12 +120,18 @@ func getProviderFromMap(pi map[string]interface{}) (provider *Provider, err erro
k := getKeyFromName(name) k := getKeyFromName(name)
logoutURL, ok := pi["logouturl"].(string)
if !ok {
logoutURL = ""
}
provider = &Provider{ provider = &Provider{
Name: pi["name"].(string), Name: pi["name"].(string),
Key: k, Key: k,
AuthURL: pi["authurl"].(string), AuthURL: pi["authurl"].(string),
OriginalAuthURL: pi["authurl"].(string), OriginalAuthURL: pi["authurl"].(string),
ClientSecret: pi["clientsecret"].(string), ClientSecret: pi["clientsecret"].(string),
LogoutURL: logoutURL,
} }
cl, is := pi["clientid"].(int) cl, is := pi["clientid"].(int)
@ -143,7 +150,6 @@ func getProviderFromMap(pi map[string]interface{}) (provider *Provider, err erro
ClientID: provider.ClientID, ClientID: provider.ClientID,
ClientSecret: provider.ClientSecret, ClientSecret: provider.ClientSecret,
RedirectURL: config.AuthOpenIDRedirectURL.GetString() + k, RedirectURL: config.AuthOpenIDRedirectURL.GetString() + k,
// Discovery returns the OAuth2 endpoints. // Discovery returns the OAuth2 endpoints.
Endpoint: provider.openIDProvider.Endpoint(), Endpoint: provider.openIDProvider.Endpoint(),

View File

@ -22,6 +22,7 @@ import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -144,11 +145,16 @@ func Restore(filename string) error {
// FIXME: There has to be a general way to do this but this works for now. // FIXME: There has to be a general way to do this but this works for now.
if table == "notifications" { if table == "notifications" {
for i := range content { for i := range content {
decoded, err := base64.StdEncoding.DecodeString(content[i]["notification"].(string)) var decoded []byte
if err != nil { decoded, err = base64.StdEncoding.DecodeString(content[i]["notification"].(string))
if err != nil && !errors.Is(err, base64.CorruptInputError(0)) {
return fmt.Errorf("could not decode notification %s: %w", content[i]["notification"], err) return fmt.Errorf("could not decode notification %s: %w", content[i]["notification"], err)
} }
if err != nil && errors.Is(err, base64.CorruptInputError(0)) {
decoded = []byte(content[i]["notification"].(string))
}
content[i]["notification"] = string(decoded) content[i]["notification"] = string(decoded)
} }
} }

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -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 int64 `json:"color"` Color string `json:"color"`
ParentID int64 `json:"parent_id"` ParentID string `json:"parent_id"`
ChildOrder int64 `json:"child_order"` ChildOrder int64 `json:"child_order"`
Collapsed int64 `json:"collapsed"` Collapsed bool `json:"collapsed"`
Shared bool `json:"shared"` Shared bool `json:"shared"`
LegacyParentID int64 `json:"legacy_parent_id"` IsDeleted bool `json:"is_deleted"`
SyncID int64 `json:"sync_id"` IsArchived bool `json:"is_archived"`
IsDeleted int64 `json:"is_deleted"` IsFavorite bool `json:"is_favorite"`
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 int64 `json:"parent_id"` ParentID string `json:"parent_id"`
LegacyParentID int64 `json:"legacy_parent_id"`
ChildOrder int64 `json:"child_order"` ChildOrder int64 `json:"child_order"`
SectionID int64 `json:"section_id"` SectionID string `json:"section_id"`
DayOrder int64 `json:"day_order"`
Collapsed int64 `json:"collapsed"`
Children interface{} `json:"children"` Children interface{} `json:"children"`
Labels []int64 `json:"labels"` Labels []string `json:"labels"`
AddedByUID int64 `json:"added_by_uid"` AddedByUID string `json:"added_by_uid"`
AssignedByUID int64 `json:"assigned_by_uid"` AssignedByUID string `json:"assigned_by_uid"`
ResponsibleUID int64 `json:"responsible_uid"` ResponsibleUID string `json:"responsible_uid"`
Checked int64 `json:"checked"` Checked bool `json:"checked"`
InHistory int64 `json:"in_history"` IsDeleted bool `json:"is_deleted"`
IsDeleted int64 `json:"is_deleted"` DateAdded time.Time `json:"added_at"`
DateAdded time.Time `json:"date_added"`
HasMoreNotes bool `json:"has_more_notes"` HasMoreNotes bool `json:"has_more_notes"`
DateCompleted time.Time `json:"date_completed"` DateCompleted time.Time `json:"completed_at"`
} }
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 int64 `json:"project_id"` ProjectID string `json:"project_id"`
LegacyProjectID int64 `json:"legacy_project_id"` ItemID string `json:"item_id"`
ItemID int64 `json:"item_id"`
LegacyItemID int64 `json:"legacy_item_id"`
Content string `json:"content"` Content string `json:"content"`
FileAttachment *fileAttachment `json:"file_attachment"` FileAttachment *fileAttachment `json:"file_attachment"`
UidsToNotify []int64 `json:"uids_to_notify"` IsDeleted bool `json:"is_deleted"`
IsDeleted int64 `json:"is_deleted"` Posted time.Time `json:"posted_at"`
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
} }

View File

@ -18,7 +18,6 @@ package todoist
import ( import (
"os" "os"
"strconv"
"testing" "testing"
"time" "time"
@ -47,33 +46,32 @@ func TestConvertTodoistToVikunja(t *testing.T) {
dueTimeWithTime = dueTimeWithTime.In(config.GetTimeZone()) dueTimeWithTime = dueTimeWithTime.In(config.GetTimeZone())
nilTime, err := time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00Z") nilTime, err := time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00Z")
assert.NoError(t, err) assert.NoError(t, err)
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg") exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/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)

View File

@ -36,7 +36,7 @@ func TestConvertTrelloToVikunja(t *testing.T) {
time1, err := time.Parse(time.RFC3339Nano, "2014-09-26T08:25:05Z") time1, err := time.Parse(time.RFC3339Nano, "2014-09-26T08:25:05Z")
assert.NoError(t, err) assert.NoError(t, err)
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg") exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/testimage.jpg")
assert.NoError(t, err) assert.NoError(t, err)
trelloData := []*trello.Board{ trelloData := []*trello.Board{

View File

@ -1,512 +0,0 @@
// 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 wunderlist
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/files"
"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"
"code.vikunja.io/api/pkg/utils"
)
// Migration represents the implementation of the migration for wunderlist
type Migration struct {
// Code is the code used to get a user api token
Code string `query:"code" json:"code"`
}
// This represents all necessary fields for getting an api token for the wunderlist api from a code
type wunderlistAuthRequest struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
Code string `json:"code"`
}
type wunderlistAuthToken struct {
AccessToken string `json:"access_token"`
}
type task struct {
AssigneeID int `json:"assignee_id"`
CreatedAt time.Time `json:"created_at"`
CreatedByID int `json:"created_by_id"`
Completed bool `json:"completed"`
CompletedAt time.Time `json:"completed_at"`
DueDate string `json:"due_date"`
ID int `json:"id"`
ListID int `json:"list_id"`
Revision int `json:"revision"`
Starred bool `json:"starred"`
Title string `json:"title"`
}
type list struct {
ID int `json:"id"`
CreatedAt time.Time `json:"created_at"`
Title string `json:"title"`
ListType string `json:"list_type"`
Type string `json:"type"`
Revision int `json:"revision"`
Migrated bool `json:"-"`
}
type folder struct {
ID int `json:"id"`
Title string `json:"title"`
ListIds []int `json:"list_ids"`
CreatedAt time.Time `json:"created_at"`
CreatedByRequestID string `json:"created_by_request_id"`
UpdatedAt time.Time `json:"updated_at"`
Type string `json:"type"`
Revision int `json:"revision"`
}
type note struct {
ID int `json:"id"`
TaskID int `json:"task_id"`
Content string `json:"content"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Revision int `json:"revision"`
}
type file struct {
ID int `json:"id"`
URL string `json:"url"`
TaskID int `json:"task_id"`
ListID int `json:"list_id"`
UserID int `json:"user_id"`
FileName string `json:"file_name"`
ContentType string `json:"content_type"`
FileSize int `json:"file_size"`
LocalCreatedAt time.Time `json:"local_created_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Type string `json:"type"`
Revision int `json:"revision"`
}
type reminder struct {
ID int `json:"id"`
Date time.Time `json:"date"`
TaskID int `json:"task_id"`
Revision int `json:"revision"`
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type subtask struct {
ID int `json:"id"`
TaskID int `json:"task_id"`
CreatedAt time.Time `json:"created_at"`
CreatedByID int `json:"created_by_id"`
Revision int `json:"revision"`
Title string `json:"title"`
}
type wunderlistContents struct {
tasks []*task
lists []*list
folders []*folder
notes []*note
files []*file
reminders []*reminder
subtasks []*subtask
}
func convertListForFolder(listID int, list *list, content *wunderlistContents) (*models.ListWithTasksAndBuckets, error) {
l := &models.ListWithTasksAndBuckets{
List: models.List{
Title: list.Title,
Created: list.CreatedAt,
},
}
// Find all tasks belonging to this list and put them in
for _, t := range content.tasks {
if t.ListID == listID {
newTask := &models.Task{
Title: t.Title,
Created: t.CreatedAt,
Done: t.Completed,
}
// Set Done At
if newTask.Done {
newTask.DoneAt = t.CompletedAt.In(config.GetTimeZone())
}
// Parse the due date
if t.DueDate != "" {
dueDate, err := time.Parse("2006-01-02", t.DueDate)
if err != nil {
return nil, err
}
newTask.DueDate = dueDate.In(config.GetTimeZone())
}
// Find related notes
for _, n := range content.notes {
if n.TaskID == t.ID {
newTask.Description = n.Content
}
}
// Attachments
for _, f := range content.files {
if f.TaskID == t.ID {
// Download the attachment and put it in the file
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, f.URL, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
buf := &bytes.Buffer{}
_, err = buf.ReadFrom(resp.Body)
if err != nil {
return nil, err
}
newTask.Attachments = append(newTask.Attachments, &models.TaskAttachment{
File: &files.File{
Name: f.FileName,
Mime: f.ContentType,
Size: uint64(f.FileSize),
Created: f.CreatedAt,
// We directly pass the file contents here to have a way to link the attachment to the file later.
// Because we don't have an ID for our task at this point of the migration, we cannot just throw all
// attachments in a slice and do the work of downloading and properly storing them later.
FileContent: buf.Bytes(),
},
Created: f.CreatedAt,
})
}
}
// Subtasks
for _, s := range content.subtasks {
if s.TaskID == t.ID {
if newTask.RelatedTasks[models.RelationKindSubtask] == nil {
newTask.RelatedTasks = make(models.RelatedTaskMap)
}
newTask.RelatedTasks[models.RelationKindSubtask] = append(newTask.RelatedTasks[models.RelationKindSubtask], &models.Task{
Title: s.Title,
})
}
}
// Reminders
for _, r := range content.reminders {
if r.TaskID == t.ID {
newTask.Reminders = append(newTask.Reminders, r.Date.In(config.GetTimeZone()))
}
}
l.Tasks = append(l.Tasks, &models.TaskWithComments{Task: *newTask})
}
}
return l, nil
}
func convertWunderlistToVikunja(content *wunderlistContents) (fullVikunjaHierachie []*models.NamespaceWithListsAndTasks, err error) {
// Make a map from the list with the key being list id for easier handling
listMap := make(map[int]*list, len(content.lists))
for _, l := range content.lists {
listMap[l.ID] = l
}
// First, we look through all folders and create namespaces for them.
for _, folder := range content.folders {
namespace := &models.NamespaceWithListsAndTasks{
Namespace: models.Namespace{
Title: folder.Title,
Created: folder.CreatedAt,
Updated: folder.UpdatedAt,
},
}
// Then find all lists for that folder
for _, listID := range folder.ListIds {
if list, exists := listMap[listID]; exists {
l, err := convertListForFolder(listID, list, content)
if err != nil {
return nil, err
}
namespace.Lists = append(namespace.Lists, l)
// And mark the list as migrated so we don't iterate over it again
list.Migrated = true
}
}
// And then finally put the namespace (which now has all the details) back in the full array.
fullVikunjaHierachie = append(fullVikunjaHierachie, namespace)
}
// At the end, loop over all lists which don't belong to a namespace and put them in a default namespace
if len(listMap) > 0 {
newNamespace := &models.NamespaceWithListsAndTasks{
Namespace: models.Namespace{
Title: "Migrated from wunderlist",
},
}
for _, list := range listMap {
if list.Migrated {
continue
}
l, err := convertListForFolder(list.ID, list, content)
if err != nil {
return nil, err
}
newNamespace.Lists = append(newNamespace.Lists, l)
}
fullVikunjaHierachie = append(fullVikunjaHierachie, newNamespace)
}
return
}
func makeAuthGetRequest(token *wunderlistAuthToken, urlPart string, v interface{}, urlParams url.Values) error {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://a.wunderlist.com/api/v1/"+urlPart, nil)
if err != nil {
return err
}
req.Header.Set("X-Access-Token", token.AccessToken)
req.Header.Set("X-Client-ID", config.MigrationWunderlistClientID.GetString())
req.URL.RawQuery = urlParams.Encode()
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
buf := &bytes.Buffer{}
_, err = buf.ReadFrom(resp.Body)
if err != nil {
return err
}
if resp.StatusCode > 399 {
return fmt.Errorf("wunderlist API Error: Status Code: %d, Response was: %s", resp.StatusCode, buf.String())
}
// If the response is an empty json array, we need to exit here, otherwise this breaks the json parser since it
// expects a null for an empty slice
str := buf.String()
if str == "[]" {
return nil
}
return json.Unmarshal(buf.Bytes(), v)
}
// Migrate migrates a user's wunderlist lists, tasks, etc.
// @Summary Migrate all lists, tasks etc. from wunderlist
// @Description Migrates all folders, lists, tasks, notes, reminders, subtasks and files from wunderlist to vikunja.
// @tags migration
// @Accept json
// @Produce json
// @Security JWTKeyAuth
// @Param migrationCode body wunderlist.Migration true "The auth code previously obtained from the auth url. See the docs for /migration/wunderlist/auth."
// @Success 200 {object} models.Message "A message telling you everything was migrated successfully."
// @Failure 500 {object} models.Message "Internal server error"
// @Router /migration/wunderlist/migrate [post]
func (w *Migration) Migrate(user *user.User) (err error) {
log.Debugf("[Wunderlist migration] Starting wunderlist migration for user %d", user.ID)
// Struct init
wContent := &wunderlistContents{
tasks: []*task{},
lists: []*list{},
folders: []*folder{},
notes: []*note{},
files: []*file{},
reminders: []*reminder{},
subtasks: []*subtask{},
}
// 0. Get api token from oauth user token
authRequest := wunderlistAuthRequest{
ClientID: config.MigrationWunderlistClientID.GetString(),
ClientSecret: config.MigrationWunderlistClientSecret.GetString(),
Code: w.Code,
}
jsonAuth, err := json.Marshal(authRequest)
if err != nil {
return
}
req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, "https://www.wunderlist.com/oauth/access_token", bytes.NewBuffer(jsonAuth))
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
authToken := &wunderlistAuthToken{}
err = json.NewDecoder(resp.Body).Decode(authToken)
if err != nil {
return
}
log.Debugf("[Wunderlist migration] Start getting all data from wunderlist for user %d", user.ID)
// 1. Get all folders
err = makeAuthGetRequest(authToken, "folders", &wContent.folders, nil)
if err != nil {
return
}
// 2. Get all lists
err = makeAuthGetRequest(authToken, "lists", &wContent.lists, nil)
if err != nil {
return
}
for _, l := range wContent.lists {
listQueryParam := url.Values{"list_id": []string{strconv.Itoa(l.ID)}}
// 3. Get all tasks for each list
tasks := []*task{}
err = makeAuthGetRequest(authToken, "tasks", &tasks, listQueryParam)
if err != nil {
return
}
wContent.tasks = append(wContent.tasks, tasks...)
// 3. Get all done tasks for each list
doneTasks := []*task{}
err = makeAuthGetRequest(authToken, "tasks", &doneTasks, url.Values{"list_id": []string{strconv.Itoa(l.ID)}, "completed": []string{"true"}})
if err != nil {
return
}
wContent.tasks = append(wContent.tasks, doneTasks...)
// 4. Get all notes for all lists
notes := []*note{}
err = makeAuthGetRequest(authToken, "notes", &notes, listQueryParam)
if err != nil {
return
}
wContent.notes = append(wContent.notes, notes...)
// 5. Get all files for all lists
fils := []*file{}
err = makeAuthGetRequest(authToken, "files", &fils, listQueryParam)
if err != nil {
return
}
wContent.files = append(wContent.files, fils...)
// 6. Get all reminders for all lists
reminders := []*reminder{}
err = makeAuthGetRequest(authToken, "reminders", &reminders, listQueryParam)
if err != nil {
return
}
wContent.reminders = append(wContent.reminders, reminders...)
// 7. Get all subtasks for all lists
subtasks := []*subtask{}
err = makeAuthGetRequest(authToken, "subtasks", &subtasks, listQueryParam)
if err != nil {
return
}
wContent.subtasks = append(wContent.subtasks, subtasks...)
}
log.Debugf("[Wunderlist migration] Got all data from wunderlist for user %d", user.ID)
log.Debugf("[Wunderlist migration] Migrating data to vikunja format for user %d", user.ID)
// Convert + Insert everything
fullVikunjaHierachie, err := convertWunderlistToVikunja(wContent)
if err != nil {
return
}
log.Debugf("[Wunderlist migration] Done migrating data to vikunja format for user %d", user.ID)
log.Debugf("[Wunderlist migration] Insert data into db for user %d", user.ID)
err = migration.InsertFromStructure(fullVikunjaHierachie, user)
if err != nil {
return err
}
log.Debugf("[Wunderlist migration] Done inserting data into db for user %d", user.ID)
log.Debugf("[Wunderlist migration] Wunderlist migration for user %d done", user.ID)
return nil
}
// AuthURL returns the url users need to authenticate against
// @Summary Get the auth url from wunderlist
// @Description Returns the auth url where the user needs to get its auth code. This code can then be used to migrate everything from wunderlist 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/wunderlist/auth [get]
func (w *Migration) AuthURL() string {
return "https://www.wunderlist.com/oauth/authorize?client_id=" +
config.MigrationWunderlistClientID.GetString() +
"&redirect_uri=" +
config.MigrationWunderlistRedirectURL.GetString() +
"&state=" + utils.MakeRandomString(32)
}
// Name is used to get the name of the wunderlist migration
// @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/wunderlist/status [get]
func (w *Migration) Name() string {
return "wunderlist"
}

View File

@ -1,386 +0,0 @@
// 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 wunderlist
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 TestWunderlistParsing(t *testing.T) {
config.InitConfig()
time1, err := time.Parse(time.RFC3339Nano, "2013-08-30T08:29:46.203Z")
assert.NoError(t, err)
time1 = time1.In(config.GetTimeZone())
time2, err := time.Parse(time.RFC3339Nano, "2013-08-30T08:36:13.273Z")
assert.NoError(t, err)
time2 = time2.In(config.GetTimeZone())
time3, err := time.Parse(time.RFC3339Nano, "2013-09-05T08:36:13.273Z")
assert.NoError(t, err)
time3 = time3.In(config.GetTimeZone())
time4, err := time.Parse(time.RFC3339Nano, "2013-08-02T11:58:55Z")
assert.NoError(t, err)
time4 = time4.In(config.GetTimeZone())
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg")
assert.NoError(t, err)
createTestTask := func(id, listID int, done bool) *task {
completedAt, err := time.Parse(time.RFC3339Nano, "1970-01-01T00:00:00Z")
assert.NoError(t, err)
if done {
completedAt = time1
}
completedAt = completedAt.In(config.GetTimeZone())
return &task{
ID: id,
AssigneeID: 123,
CreatedAt: time1,
DueDate: "2013-09-05",
ListID: listID,
Title: "Ipsum" + strconv.Itoa(id),
Completed: done,
CompletedAt: completedAt,
}
}
createTestNote := func(id, taskID int) *note {
return &note{
ID: id,
TaskID: taskID,
Content: "Lorem Ipsum dolor sit amet",
CreatedAt: time3,
UpdatedAt: time2,
}
}
fixtures := &wunderlistContents{
folders: []*folder{
{
ID: 123,
Title: "Lorem Ipsum",
ListIds: []int{1, 2, 3, 4},
CreatedAt: time1,
UpdatedAt: time2,
},
},
lists: []*list{
{
ID: 1,
CreatedAt: time1,
Title: "Lorem1",
},
{
ID: 2,
CreatedAt: time1,
Title: "Lorem2",
},
{
ID: 3,
CreatedAt: time1,
Title: "Lorem3",
},
{
ID: 4,
CreatedAt: time1,
Title: "Lorem4",
},
{
ID: 5,
CreatedAt: time4,
Title: "List without a namespace",
},
},
tasks: []*task{
createTestTask(1, 1, false),
createTestTask(2, 1, false),
createTestTask(3, 2, true),
createTestTask(4, 2, false),
createTestTask(5, 3, false),
createTestTask(6, 3, true),
createTestTask(7, 3, true),
createTestTask(8, 3, false),
createTestTask(9, 4, true),
createTestTask(10, 4, true),
},
notes: []*note{
createTestNote(1, 1),
createTestNote(2, 2),
createTestNote(3, 3),
},
files: []*file{
{
ID: 1,
URL: "https://vikunja.io/testimage.jpg", // Using an image which we are hosting, so it'll still be up
TaskID: 1,
ListID: 1,
FileName: "file.md",
ContentType: "text/plain",
FileSize: 12345,
CreatedAt: time2,
UpdatedAt: time4,
},
{
ID: 2,
URL: "https://vikunja.io/testimage.jpg",
TaskID: 3,
ListID: 2,
FileName: "file2.md",
ContentType: "text/plain",
FileSize: 12345,
CreatedAt: time3,
UpdatedAt: time4,
},
},
reminders: []*reminder{
{
ID: 1,
Date: time4,
TaskID: 1,
CreatedAt: time4,
UpdatedAt: time4,
},
{
ID: 2,
Date: time3,
TaskID: 4,
CreatedAt: time3,
UpdatedAt: time3,
},
},
subtasks: []*subtask{
{
ID: 1,
TaskID: 2,
CreatedAt: time4,
Title: "LoremSub1",
},
{
ID: 2,
TaskID: 2,
CreatedAt: time4,
Title: "LoremSub2",
},
{
ID: 3,
TaskID: 4,
CreatedAt: time4,
Title: "LoremSub3",
},
},
}
expectedHierachie := []*models.NamespaceWithListsAndTasks{
{
Namespace: models.Namespace{
Title: "Lorem Ipsum",
Created: time1,
Updated: time2,
},
Lists: []*models.ListWithTasksAndBuckets{
{
List: models.List{
Created: time1,
Title: "Lorem1",
},
Tasks: []*models.TaskWithComments{
{
Task: models.Task{
Title: "Ipsum1",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Description: "Lorem Ipsum dolor sit amet",
Attachments: []*models.TaskAttachment{
{
File: &files.File{
Name: "file.md",
Mime: "text/plain",
Size: 12345,
Created: time2,
FileContent: exampleFile,
},
Created: time2,
},
},
Reminders: []time.Time{time4},
},
},
{
Task: models.Task{
Title: "Ipsum2",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Description: "Lorem Ipsum dolor sit amet",
RelatedTasks: map[models.RelationKind][]*models.Task{
models.RelationKindSubtask: {
{
Title: "LoremSub1",
},
{
Title: "LoremSub2",
},
},
},
},
},
},
},
{
List: models.List{
Created: time1,
Title: "Lorem2",
},
Tasks: []*models.TaskWithComments{
{
Task: models.Task{
Title: "Ipsum3",
Done: true,
DoneAt: time1,
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Description: "Lorem Ipsum dolor sit amet",
Attachments: []*models.TaskAttachment{
{
File: &files.File{
Name: "file2.md",
Mime: "text/plain",
Size: 12345,
Created: time3,
FileContent: exampleFile,
},
Created: time3,
},
},
},
},
{
Task: models.Task{
Title: "Ipsum4",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Reminders: []time.Time{time3},
RelatedTasks: map[models.RelationKind][]*models.Task{
models.RelationKindSubtask: {
{
Title: "LoremSub3",
},
},
},
},
},
},
},
{
List: models.List{
Created: time1,
Title: "Lorem3",
},
Tasks: []*models.TaskWithComments{
{
Task: models.Task{
Title: "Ipsum5",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
},
},
{
Task: models.Task{
Title: "Ipsum6",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Done: true,
DoneAt: time1,
},
},
{
Task: models.Task{
Title: "Ipsum7",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Done: true,
DoneAt: time1,
},
},
{
Task: models.Task{
Title: "Ipsum8",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
},
},
},
},
{
List: models.List{
Created: time1,
Title: "Lorem4",
},
Tasks: []*models.TaskWithComments{
{
Task: models.Task{
Title: "Ipsum9",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Done: true,
DoneAt: time1,
},
},
{
Task: models.Task{
Title: "Ipsum10",
DueDate: time.Unix(1378339200, 0).In(config.GetTimeZone()),
Created: time1,
Done: true,
DoneAt: time1,
},
},
},
},
},
},
{
Namespace: models.Namespace{
Title: "Migrated from wunderlist",
},
Lists: []*models.ListWithTasksAndBuckets{
{
List: models.List{
Created: time4,
Title: "List without a namespace",
},
},
},
},
}
hierachie, err := convertWunderlistToVikunja(fixtures)
assert.NoError(t, err)
assert.NotNil(t, hierachie)
if diff, equal := messagediff.PrettyDiff(hierachie, expectedHierachie); !equal {
t.Errorf("converted wunderlist data = %v, want %v, diff: %v", hierachie, expectedHierachie, diff)
}
}

View File

@ -27,7 +27,6 @@ import (
"code.vikunja.io/api/pkg/modules/migration/todoist" "code.vikunja.io/api/pkg/modules/migration/todoist"
"code.vikunja.io/api/pkg/modules/migration/trello" "code.vikunja.io/api/pkg/modules/migration/trello"
vikunja_file "code.vikunja.io/api/pkg/modules/migration/vikunja-file" vikunja_file "code.vikunja.io/api/pkg/modules/migration/vikunja-file"
"code.vikunja.io/api/pkg/modules/migration/wunderlist"
"code.vikunja.io/api/pkg/version" "code.vikunja.io/api/pkg/version"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
@ -121,10 +120,6 @@ func Info(c echo.Context) error {
info.AuthInfo.OpenIDConnect.Providers = providers info.AuthInfo.OpenIDConnect.Providers = providers
// Migrators // Migrators
if config.MigrationWunderlistEnable.GetBool() {
m := &wunderlist.Migration{}
info.AvailableMigrators = append(info.AvailableMigrators, m.Name())
}
if config.MigrationTodoistEnable.GetBool() { if config.MigrationTodoistEnable.GetBool() {
m := &todoist.Migration{} m := &todoist.Migration{}
info.AvailableMigrators = append(info.AvailableMigrators, m.Name()) info.AvailableMigrators = append(info.AvailableMigrators, m.Name())

View File

@ -48,7 +48,6 @@ package routes
import ( import (
"errors" "errors"
"fmt"
"net/url" "net/url"
"strings" "strings"
"time" "time"
@ -70,7 +69,6 @@ import (
"code.vikunja.io/api/pkg/modules/migration/todoist" "code.vikunja.io/api/pkg/modules/migration/todoist"
"code.vikunja.io/api/pkg/modules/migration/trello" "code.vikunja.io/api/pkg/modules/migration/trello"
vikunja_file "code.vikunja.io/api/pkg/modules/migration/vikunja-file" vikunja_file "code.vikunja.io/api/pkg/modules/migration/vikunja-file"
"code.vikunja.io/api/pkg/modules/migration/wunderlist"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1" apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/routes/caldav" "code.vikunja.io/api/pkg/routes/caldav"
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs _ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
@ -80,7 +78,7 @@ import (
"github.com/getsentry/sentry-go" "github.com/getsentry/sentry-go"
sentryecho "github.com/getsentry/sentry-go/echo" sentryecho "github.com/getsentry/sentry-go/echo"
"github.com/golang-jwt/jwt/v4" echojwt "github.com/labstack/echo-jwt/v4"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware" "github.com/labstack/echo/v4/middleware"
elog "github.com/labstack/gommon/log" elog "github.com/labstack/gommon/log"
@ -273,29 +271,8 @@ func registerAPIRoutes(a *echo.Group) {
ur.POST("/shares/:share/auth", apiv1.AuthenticateLinkShare) ur.POST("/shares/:share/auth", apiv1.AuthenticateLinkShare)
} }
// ===== Routes with Authetication ===== // ===== Routes with Authentication =====
// Authetification a.Use(echojwt.JWT([]byte(config.ServiceJWTSecret.GetString())))
a.Use(middleware.JWTWithConfig(middleware.JWTConfig{
// Custom parse function to make the middleware work with the github.com/golang-jwt/jwt/v4 package.
// See https://github.com/labstack/echo/pull/1916#issuecomment-878046299
ParseTokenFunc: func(auth string, c echo.Context) (interface{}, error) {
keyFunc := func(t *jwt.Token) (interface{}, error) {
if t.Method.Alg() != "HS256" {
return nil, fmt.Errorf("unexpected jwt signing method=%v", t.Header["alg"])
}
return []byte(config.ServiceJWTSecret.GetString()), nil
}
token, err := jwt.Parse(auth, keyFunc)
if err != nil {
return nil, err
}
if !token.Valid {
return nil, errors.New("invalid token")
}
return token, nil
},
}))
// Rate limit // Rate limit
setupRateLimit(a, config.RateLimitKind.GetString()) setupRateLimit(a, config.RateLimitKind.GetString())
@ -612,16 +589,6 @@ func registerAPIRoutes(a *echo.Group) {
} }
func registerMigrations(m *echo.Group) { func registerMigrations(m *echo.Group) {
// Wunderlist
if config.MigrationWunderlistEnable.GetBool() {
wunderlistMigrationHandler := &migrationHandler.MigrationWeb{
MigrationStruct: func() migration.Migrator {
return &wunderlist.Migration{}
},
}
wunderlistMigrationHandler.RegisterRoutes(m)
}
// Todoist // Todoist
if config.MigrationTodoistEnable.GetBool() { if config.MigrationTodoistEnable.GetBool() {
todoistMigrationHandler := &migrationHandler.MigrationWeb{ todoistMigrationHandler := &migrationHandler.MigrationWeb{

View File

@ -3061,113 +3061,6 @@ const docTemplate = `{
} }
} }
}, },
"/migration/wunderlist/auth": {
"get": {
"security": [
{
"JWTKeyAuth": []
}
],
"description": "Returns the auth url where the user needs to get its auth code. This code can then be used to migrate everything from wunderlist to Vikunja.",
"produces": [
"application/json"
],
"tags": [
"migration"
],
"summary": "Get the auth url from wunderlist",
"responses": {
"200": {
"description": "The auth url.",
"schema": {
"$ref": "#/definitions/handler.AuthURL"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/migration/wunderlist/migrate": {
"post": {
"security": [
{
"JWTKeyAuth": []
}
],
"description": "Migrates all folders, lists, tasks, notes, reminders, subtasks and files from wunderlist to vikunja.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"migration"
],
"summary": "Migrate all lists, tasks etc. from wunderlist",
"parameters": [
{
"description": "The auth code previously obtained from the auth url. See the docs for /migration/wunderlist/auth.",
"name": "migrationCode",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/wunderlist.Migration"
}
}
],
"responses": {
"200": {
"description": "A message telling you everything was migrated successfully.",
"schema": {
"$ref": "#/definitions/models.Message"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/migration/wunderlist/status": {
"get": {
"security": [
{
"JWTKeyAuth": []
}
],
"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.",
"produces": [
"application/json"
],
"tags": [
"migration"
],
"summary": "Get migration status",
"responses": {
"200": {
"description": "The migration status",
"schema": {
"$ref": "#/definitions/migration.Status"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/namespace/{id}": { "/namespace/{id}": {
"post": { "post": {
"security": [ "security": [
@ -7727,36 +7620,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who initially created the bucket.", "description": "The user who initially created the bucket.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
},
"filter_by": {
"description": "The field name of the field to filter by",
"type": "array",
"items": {
"type": "string"
}
},
"filter_comparator": {
"description": "The comparator for field and value",
"type": "array",
"items": {
"type": "string"
}
},
"filter_concat": {
"description": "The way all filter conditions are concatenated together, can be either \"and\" or \"or\".,",
"type": "string"
},
"filter_include_nulls": {
"description": "If set to true, the result will also include null values",
"type": "boolean"
},
"filter_value": {
"description": "The value of the field name to filter by",
"type": "array",
"items": {
"type": "string"
} }
]
}, },
"id": { "id": {
"description": "The unique, numeric id of this bucket.", "description": "The unique, numeric id of this bucket.",
@ -7775,24 +7643,10 @@ const docTemplate = `{
"description": "The list this bucket belongs to.", "description": "The list this bucket belongs to.",
"type": "integer" "type": "integer"
}, },
"order_by": {
"description": "The query parameter to order the items by. This can be either asc or desc, with asc being the default.",
"type": "array",
"items": {
"type": "string"
}
},
"position": { "position": {
"description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.", "description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.",
"type": "number" "type": "number"
}, },
"sort_by": {
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
"type": "array",
"items": {
"type": "string"
}
},
"tasks": { "tasks": {
"description": "All tasks which belong to this bucket.", "description": "All tasks which belong to this bucket.",
"type": "array", "type": "array",
@ -7808,9 +7662,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this bucket was last updated. You cannot change this value.", "description": "A timestamp when this bucket was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.BulkAssignees": { "models.BulkAssignees": {
@ -7822,9 +7674,7 @@ const docTemplate = `{
"items": { "items": {
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
} }
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.BulkTask": { "models.BulkTask": {
@ -7858,7 +7708,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who initially created the task.", "description": "The user who initially created the task.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The task description.", "description": "The task description.",
@ -7930,7 +7784,11 @@ const docTemplate = `{
}, },
"related_tasks": { "related_tasks": {
"description": "All related tasks, grouped by their relation kind", "description": "All related tasks, grouped by their relation kind",
"allOf": [
{
"$ref": "#/definitions/models.RelatedTaskMap" "$ref": "#/definitions/models.RelatedTaskMap"
}
]
}, },
"reminder_dates": { "reminder_dates": {
"description": "An array of datetimes when the user wants to be reminded of the task.", "description": "An array of datetimes when the user wants to be reminded of the task.",
@ -7945,7 +7803,11 @@ const docTemplate = `{
}, },
"repeat_mode": { "repeat_mode": {
"description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.", "description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.",
"type": "integer" "allOf": [
{
"$ref": "#/definitions/models.TaskRepeatMode"
}
]
}, },
"start_date": { "start_date": {
"description": "When this task starts.", "description": "When this task starts.",
@ -7953,7 +7815,11 @@ const docTemplate = `{
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.", "description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"task_ids": { "task_ids": {
"description": "A list of task ids to update", "description": "A list of task ids to update",
@ -7970,9 +7836,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this task was last updated. You cannot change this value.", "description": "A timestamp when this task was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.DatabaseNotifications": { "models.DatabaseNotifications": {
@ -8000,9 +7864,7 @@ const docTemplate = `{
"read_at": { "read_at": {
"description": "When this notification is marked as read, this will be updated with the current timestamp.", "description": "When this notification is marked as read, this will be updated with the current timestamp.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.Label": { "models.Label": {
@ -8014,7 +7876,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who created this label", "description": "The user who created this label",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The label description.", "description": "The label description.",
@ -8038,9 +7904,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this label was last updated. You cannot change this value.", "description": "A timestamp when this label was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.LabelTask": { "models.LabelTask": {
@ -8053,9 +7917,7 @@ const docTemplate = `{
"label_id": { "label_id": {
"description": "The label id you want to associate with a task.", "description": "The label id you want to associate with a task.",
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.LabelTaskBulk": { "models.LabelTaskBulk": {
@ -8067,9 +7929,7 @@ const docTemplate = `{
"items": { "items": {
"$ref": "#/definitions/models.Label" "$ref": "#/definitions/models.Label"
} }
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.LinkSharing": { "models.LinkSharing": {
@ -8097,26 +7957,36 @@ const docTemplate = `{
}, },
"right": { "right": {
"description": "The right this list is shared with. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this list is shared with. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"shared_by": { "shared_by": {
"description": "The user who shared this list", "description": "The user who shared this list",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"sharing_type": { "sharing_type": {
"description": "The kind of this link. 0 = undefined, 1 = without password, 2 = with password.", "description": "The kind of this link. 0 = undefined, 1 = without password, 2 = with password.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.SharingType"
}
]
}, },
"updated": { "updated": {
"description": "A timestamp when this share was last updated. You cannot change this value.", "description": "A timestamp when this share was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.List": { "models.List": {
@ -8165,7 +8035,11 @@ const docTemplate = `{
}, },
"owner": { "owner": {
"description": "The user who created this list.", "description": "The user who created this list.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"position": { "position": {
"description": "The position this list has when querying all lists. See the tasks.position property on how to use this.", "description": "The position this list has when querying all lists. See the tasks.position property on how to use this.",
@ -8173,7 +8047,11 @@ const docTemplate = `{
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.", "description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The title of the list. You'll see this in the namespace overview.", "description": "The title of the list. You'll see this in the namespace overview.",
@ -8184,9 +8062,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this list was last updated. You cannot change this value.", "description": "A timestamp when this list was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.ListDuplicate": { "models.ListDuplicate": {
@ -8194,14 +8070,16 @@ const docTemplate = `{
"properties": { "properties": {
"list": { "list": {
"description": "The copied list", "description": "The copied list",
"allOf": [
{
"$ref": "#/definitions/models.List" "$ref": "#/definitions/models.List"
}
]
}, },
"namespace_id": { "namespace_id": {
"description": "The target namespace ID", "description": "The target namespace ID",
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.ListUser": { "models.ListUser": {
@ -8217,9 +8095,13 @@ const docTemplate = `{
}, },
"right": { "right": {
"description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
@ -8228,9 +8110,7 @@ const docTemplate = `{
"user_id": { "user_id": {
"description": "The username.", "description": "The username.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.Message": { "models.Message": {
@ -8268,11 +8148,19 @@ const docTemplate = `{
}, },
"owner": { "owner": {
"description": "The user who owns this namespace", "description": "The user who owns this namespace",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.", "description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The name of this namespace.", "description": "The name of this namespace.",
@ -8283,9 +8171,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this namespace was last updated. You cannot change this value.", "description": "A timestamp when this namespace was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.NamespaceUser": { "models.NamespaceUser": {
@ -8301,9 +8187,13 @@ const docTemplate = `{
}, },
"right": { "right": {
"description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
@ -8312,9 +8202,7 @@ const docTemplate = `{
"user_id": { "user_id": {
"description": "The username.", "description": "The username.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.NamespaceWithLists": { "models.NamespaceWithLists": {
@ -8349,11 +8237,19 @@ const docTemplate = `{
}, },
"owner": { "owner": {
"description": "The user who owns this namespace", "description": "The user who owns this namespace",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.", "description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The name of this namespace.", "description": "The name of this namespace.",
@ -8364,9 +8260,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this namespace was last updated. You cannot change this value.", "description": "A timestamp when this namespace was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.RelatedTaskMap": { "models.RelatedTaskMap": {
@ -8378,6 +8272,50 @@ const docTemplate = `{
} }
} }
}, },
"models.RelationKind": {
"type": "string",
"enum": [
"unknown",
"subtask",
"parenttask",
"related",
"duplicateof",
"duplicates",
"blocking",
"blocked",
"precedes",
"follows",
"copiedfrom",
"copiedto"
],
"x-enum-varnames": [
"RelationKindUnknown",
"RelationKindSubtask",
"RelationKindParenttask",
"RelationKindRelated",
"RelationKindDuplicateOf",
"RelationKindDuplicates",
"RelationKindBlocking",
"RelationKindBlocked",
"RelationKindPreceeds",
"RelationKindFollows",
"RelationKindCopiedFrom",
"RelationKindCopiedTo"
]
},
"models.Right": {
"type": "integer",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"RightRead",
"RightWrite",
"RightAdmin"
]
},
"models.SavedFilter": { "models.SavedFilter": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -8391,7 +8329,11 @@ const docTemplate = `{
}, },
"filters": { "filters": {
"description": "The actual filters this filter contains", "description": "The actual filters this filter contains",
"allOf": [
{
"$ref": "#/definitions/models.TaskCollection" "$ref": "#/definitions/models.TaskCollection"
}
]
}, },
"id": { "id": {
"description": "The unique numeric id of this saved filter", "description": "The unique numeric id of this saved filter",
@ -8403,7 +8345,11 @@ const docTemplate = `{
}, },
"owner": { "owner": {
"description": "The user who owns this filter", "description": "The user who owns this filter",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"title": { "title": {
"description": "The title of the filter.", "description": "The title of the filter.",
@ -8414,10 +8360,21 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this filter was last updated. You cannot change this value.", "description": "A timestamp when this filter was last updated. You cannot change this value.",
"type": "string" "type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
} }
}
},
"models.SharingType": {
"type": "integer",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"SharingTypeUnknown",
"SharingTypeWithoutPassword",
"SharingTypeWithPassword"
]
}, },
"models.Subscription": { "models.Subscription": {
"type": "object", "type": "object",
@ -8439,10 +8396,12 @@ const docTemplate = `{
}, },
"user": { "user": {
"description": "The user who made this subscription", "description": "The user who made this subscription",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}, }
"web.CRUDable": {}, ]
"web.Rights": {} }
} }
}, },
"models.Task": { "models.Task": {
@ -8476,7 +8435,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who initially created the task.", "description": "The user who initially created the task.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The task description.", "description": "The task description.",
@ -8548,7 +8511,11 @@ const docTemplate = `{
}, },
"related_tasks": { "related_tasks": {
"description": "All related tasks, grouped by their relation kind", "description": "All related tasks, grouped by their relation kind",
"allOf": [
{
"$ref": "#/definitions/models.RelatedTaskMap" "$ref": "#/definitions/models.RelatedTaskMap"
}
]
}, },
"reminder_dates": { "reminder_dates": {
"description": "An array of datetimes when the user wants to be reminded of the task.", "description": "An array of datetimes when the user wants to be reminded of the task.",
@ -8563,7 +8530,11 @@ const docTemplate = `{
}, },
"repeat_mode": { "repeat_mode": {
"description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.", "description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.",
"type": "integer" "allOf": [
{
"$ref": "#/definitions/models.TaskRepeatMode"
}
]
}, },
"start_date": { "start_date": {
"description": "When this task starts.", "description": "When this task starts.",
@ -8571,7 +8542,11 @@ const docTemplate = `{
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.", "description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The task text. This is what you'll see in the list.", "description": "The task text. This is what you'll see in the list.",
@ -8581,9 +8556,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this task was last updated. You cannot change this value.", "description": "A timestamp when this task was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskAssginee": { "models.TaskAssginee": {
@ -8594,9 +8567,7 @@ const docTemplate = `{
}, },
"user_id": { "user_id": {
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskAttachment": { "models.TaskAttachment": {
@ -8616,9 +8587,7 @@ const docTemplate = `{
}, },
"task_id": { "task_id": {
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskCollection": { "models.TaskCollection": {
@ -8666,9 +8635,7 @@ const docTemplate = `{
"items": { "items": {
"type": "string" "type": "string"
} }
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskComment": { "models.TaskComment": {
@ -8688,9 +8655,7 @@ const docTemplate = `{
}, },
"updated": { "updated": {
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskRelation": { "models.TaskRelation": {
@ -8702,7 +8667,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who created this relation", "description": "The user who created this relation",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"other_task_id": { "other_task_id": {
"description": "The ID of the other task, the task which is being related.", "description": "The ID of the other task, the task which is being related.",
@ -8710,15 +8679,30 @@ const docTemplate = `{
}, },
"relation_kind": { "relation_kind": {
"description": "The kind of the relation.", "description": "The kind of the relation.",
"type": "string" "allOf": [
{
"$ref": "#/definitions/models.RelationKind"
}
]
}, },
"task_id": { "task_id": {
"description": "The ID of the \"base\" task, the task which has a relation to another.", "description": "The ID of the \"base\" task, the task which has a relation to another.",
"type": "integer" "type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
} }
}
},
"models.TaskRepeatMode": {
"type": "integer",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"TaskRepeatModeDefault",
"TaskRepeatModeMonth",
"TaskRepeatModeFromCurrentDate"
]
}, },
"models.Team": { "models.Team": {
"type": "object", "type": "object",
@ -8729,7 +8713,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who created this team.", "description": "The user who created this team.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The team's description.", "description": "The team's description.",
@ -8755,9 +8743,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamList": { "models.TeamList": {
@ -8773,9 +8759,13 @@ const docTemplate = `{
}, },
"right": { "right": {
"description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"team_id": { "team_id": {
"description": "The team id.", "description": "The team id.",
@ -8784,9 +8774,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamMember": { "models.TeamMember": {
@ -8807,9 +8795,7 @@ const docTemplate = `{
"username": { "username": {
"description": "The username of the member. We use this to prevent automated user id entering.", "description": "The username of the member. We use this to prevent automated user id entering.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamNamespace": { "models.TeamNamespace": {
@ -8825,9 +8811,13 @@ const docTemplate = `{
}, },
"right": { "right": {
"description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"team_id": { "team_id": {
"description": "The team id.", "description": "The team id.",
@ -8836,9 +8826,7 @@ const docTemplate = `{
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamUser": { "models.TeamUser": {
@ -8874,8 +8862,7 @@ const docTemplate = `{
"type": "string", "type": "string",
"maxLength": 250, "maxLength": 250,
"minLength": 1 "minLength": 1
}, }
"web.Auth": {}
} }
}, },
"models.TeamWithRight": { "models.TeamWithRight": {
@ -8887,7 +8874,11 @@ const docTemplate = `{
}, },
"created_by": { "created_by": {
"description": "The user who created this team.", "description": "The user who created this team.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The team's description.", "description": "The team's description.",
@ -8911,16 +8902,12 @@ const docTemplate = `{
"minLength": 1 "minLength": 1
}, },
"right": { "right": {
"description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "$ref": "#/definitions/models.Right"
"type": "integer",
"default": 0
}, },
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.UserWithRight": { "models.UserWithRight": {
@ -8944,9 +8931,7 @@ const docTemplate = `{
"type": "string" "type": "string"
}, },
"right": { "right": {
"description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "$ref": "#/definitions/models.Right"
"type": "integer",
"default": 0
}, },
"updated": { "updated": {
"description": "A timestamp when this task was last updated. You cannot change this value.", "description": "A timestamp when this task was last updated. You cannot change this value.",
@ -8957,8 +8942,7 @@ const docTemplate = `{
"type": "string", "type": "string",
"maxLength": 250, "maxLength": 250,
"minLength": 1 "minLength": 1
}, }
"web.Auth": {}
} }
}, },
"notifications.DatabaseNotification": { "notifications.DatabaseNotification": {
@ -9008,6 +8992,9 @@ const docTemplate = `{
"key": { "key": {
"type": "string" "type": "string"
}, },
"logout_url": {
"type": "string"
},
"name": { "name": {
"type": "string" "type": "string"
} }
@ -9187,8 +9174,7 @@ const docTemplate = `{
"type": "string", "type": "string",
"maxLength": 250, "maxLength": 250,
"minLength": 1 "minLength": 1
}, }
"web.Auth": {}
} }
}, },
"v1.LinkShareAuth": { "v1.LinkShareAuth": {
@ -9396,15 +9382,6 @@ const docTemplate = `{
"type": "string" "type": "string"
} }
} }
},
"wunderlist.Migration": {
"type": "object",
"properties": {
"code": {
"description": "Code is the code used to get a user api token",
"type": "string"
}
}
} }
}, },
"securityDefinitions": { "securityDefinitions": {

View File

@ -3052,113 +3052,6 @@
} }
} }
}, },
"/migration/wunderlist/auth": {
"get": {
"security": [
{
"JWTKeyAuth": []
}
],
"description": "Returns the auth url where the user needs to get its auth code. This code can then be used to migrate everything from wunderlist to Vikunja.",
"produces": [
"application/json"
],
"tags": [
"migration"
],
"summary": "Get the auth url from wunderlist",
"responses": {
"200": {
"description": "The auth url.",
"schema": {
"$ref": "#/definitions/handler.AuthURL"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/migration/wunderlist/migrate": {
"post": {
"security": [
{
"JWTKeyAuth": []
}
],
"description": "Migrates all folders, lists, tasks, notes, reminders, subtasks and files from wunderlist to vikunja.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"migration"
],
"summary": "Migrate all lists, tasks etc. from wunderlist",
"parameters": [
{
"description": "The auth code previously obtained from the auth url. See the docs for /migration/wunderlist/auth.",
"name": "migrationCode",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/wunderlist.Migration"
}
}
],
"responses": {
"200": {
"description": "A message telling you everything was migrated successfully.",
"schema": {
"$ref": "#/definitions/models.Message"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/migration/wunderlist/status": {
"get": {
"security": [
{
"JWTKeyAuth": []
}
],
"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.",
"produces": [
"application/json"
],
"tags": [
"migration"
],
"summary": "Get migration status",
"responses": {
"200": {
"description": "The migration status",
"schema": {
"$ref": "#/definitions/migration.Status"
}
},
"500": {
"description": "Internal server error",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/namespace/{id}": { "/namespace/{id}": {
"post": { "post": {
"security": [ "security": [
@ -7718,36 +7611,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who initially created the bucket.", "description": "The user who initially created the bucket.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
},
"filter_by": {
"description": "The field name of the field to filter by",
"type": "array",
"items": {
"type": "string"
}
},
"filter_comparator": {
"description": "The comparator for field and value",
"type": "array",
"items": {
"type": "string"
}
},
"filter_concat": {
"description": "The way all filter conditions are concatenated together, can be either \"and\" or \"or\".,",
"type": "string"
},
"filter_include_nulls": {
"description": "If set to true, the result will also include null values",
"type": "boolean"
},
"filter_value": {
"description": "The value of the field name to filter by",
"type": "array",
"items": {
"type": "string"
} }
]
}, },
"id": { "id": {
"description": "The unique, numeric id of this bucket.", "description": "The unique, numeric id of this bucket.",
@ -7766,24 +7634,10 @@
"description": "The list this bucket belongs to.", "description": "The list this bucket belongs to.",
"type": "integer" "type": "integer"
}, },
"order_by": {
"description": "The query parameter to order the items by. This can be either asc or desc, with asc being the default.",
"type": "array",
"items": {
"type": "string"
}
},
"position": { "position": {
"description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.", "description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.",
"type": "number" "type": "number"
}, },
"sort_by": {
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
"type": "array",
"items": {
"type": "string"
}
},
"tasks": { "tasks": {
"description": "All tasks which belong to this bucket.", "description": "All tasks which belong to this bucket.",
"type": "array", "type": "array",
@ -7799,9 +7653,7 @@
"updated": { "updated": {
"description": "A timestamp when this bucket was last updated. You cannot change this value.", "description": "A timestamp when this bucket was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.BulkAssignees": { "models.BulkAssignees": {
@ -7813,9 +7665,7 @@
"items": { "items": {
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
} }
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.BulkTask": { "models.BulkTask": {
@ -7849,7 +7699,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who initially created the task.", "description": "The user who initially created the task.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The task description.", "description": "The task description.",
@ -7921,7 +7775,11 @@
}, },
"related_tasks": { "related_tasks": {
"description": "All related tasks, grouped by their relation kind", "description": "All related tasks, grouped by their relation kind",
"allOf": [
{
"$ref": "#/definitions/models.RelatedTaskMap" "$ref": "#/definitions/models.RelatedTaskMap"
}
]
}, },
"reminder_dates": { "reminder_dates": {
"description": "An array of datetimes when the user wants to be reminded of the task.", "description": "An array of datetimes when the user wants to be reminded of the task.",
@ -7936,7 +7794,11 @@
}, },
"repeat_mode": { "repeat_mode": {
"description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.", "description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.",
"type": "integer" "allOf": [
{
"$ref": "#/definitions/models.TaskRepeatMode"
}
]
}, },
"start_date": { "start_date": {
"description": "When this task starts.", "description": "When this task starts.",
@ -7944,7 +7806,11 @@
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.", "description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"task_ids": { "task_ids": {
"description": "A list of task ids to update", "description": "A list of task ids to update",
@ -7961,9 +7827,7 @@
"updated": { "updated": {
"description": "A timestamp when this task was last updated. You cannot change this value.", "description": "A timestamp when this task was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.DatabaseNotifications": { "models.DatabaseNotifications": {
@ -7991,9 +7855,7 @@
"read_at": { "read_at": {
"description": "When this notification is marked as read, this will be updated with the current timestamp.", "description": "When this notification is marked as read, this will be updated with the current timestamp.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.Label": { "models.Label": {
@ -8005,7 +7867,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who created this label", "description": "The user who created this label",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The label description.", "description": "The label description.",
@ -8029,9 +7895,7 @@
"updated": { "updated": {
"description": "A timestamp when this label was last updated. You cannot change this value.", "description": "A timestamp when this label was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.LabelTask": { "models.LabelTask": {
@ -8044,9 +7908,7 @@
"label_id": { "label_id": {
"description": "The label id you want to associate with a task.", "description": "The label id you want to associate with a task.",
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.LabelTaskBulk": { "models.LabelTaskBulk": {
@ -8058,9 +7920,7 @@
"items": { "items": {
"$ref": "#/definitions/models.Label" "$ref": "#/definitions/models.Label"
} }
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.LinkSharing": { "models.LinkSharing": {
@ -8088,26 +7948,36 @@
}, },
"right": { "right": {
"description": "The right this list is shared with. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this list is shared with. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"shared_by": { "shared_by": {
"description": "The user who shared this list", "description": "The user who shared this list",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"sharing_type": { "sharing_type": {
"description": "The kind of this link. 0 = undefined, 1 = without password, 2 = with password.", "description": "The kind of this link. 0 = undefined, 1 = without password, 2 = with password.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.SharingType"
}
]
}, },
"updated": { "updated": {
"description": "A timestamp when this share was last updated. You cannot change this value.", "description": "A timestamp when this share was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.List": { "models.List": {
@ -8156,7 +8026,11 @@
}, },
"owner": { "owner": {
"description": "The user who created this list.", "description": "The user who created this list.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"position": { "position": {
"description": "The position this list has when querying all lists. See the tasks.position property on how to use this.", "description": "The position this list has when querying all lists. See the tasks.position property on how to use this.",
@ -8164,7 +8038,11 @@
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.", "description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The title of the list. You'll see this in the namespace overview.", "description": "The title of the list. You'll see this in the namespace overview.",
@ -8175,9 +8053,7 @@
"updated": { "updated": {
"description": "A timestamp when this list was last updated. You cannot change this value.", "description": "A timestamp when this list was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.ListDuplicate": { "models.ListDuplicate": {
@ -8185,14 +8061,16 @@
"properties": { "properties": {
"list": { "list": {
"description": "The copied list", "description": "The copied list",
"allOf": [
{
"$ref": "#/definitions/models.List" "$ref": "#/definitions/models.List"
}
]
}, },
"namespace_id": { "namespace_id": {
"description": "The target namespace ID", "description": "The target namespace ID",
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.ListUser": { "models.ListUser": {
@ -8208,9 +8086,13 @@
}, },
"right": { "right": {
"description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
@ -8219,9 +8101,7 @@
"user_id": { "user_id": {
"description": "The username.", "description": "The username.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.Message": { "models.Message": {
@ -8259,11 +8139,19 @@
}, },
"owner": { "owner": {
"description": "The user who owns this namespace", "description": "The user who owns this namespace",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.", "description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The name of this namespace.", "description": "The name of this namespace.",
@ -8274,9 +8162,7 @@
"updated": { "updated": {
"description": "A timestamp when this namespace was last updated. You cannot change this value.", "description": "A timestamp when this namespace was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.NamespaceUser": { "models.NamespaceUser": {
@ -8292,9 +8178,13 @@
}, },
"right": { "right": {
"description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
@ -8303,9 +8193,7 @@
"user_id": { "user_id": {
"description": "The username.", "description": "The username.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.NamespaceWithLists": { "models.NamespaceWithLists": {
@ -8340,11 +8228,19 @@
}, },
"owner": { "owner": {
"description": "The user who owns this namespace", "description": "The user who owns this namespace",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.", "description": "The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one namespace.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The name of this namespace.", "description": "The name of this namespace.",
@ -8355,9 +8251,7 @@
"updated": { "updated": {
"description": "A timestamp when this namespace was last updated. You cannot change this value.", "description": "A timestamp when this namespace was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.RelatedTaskMap": { "models.RelatedTaskMap": {
@ -8369,6 +8263,50 @@
} }
} }
}, },
"models.RelationKind": {
"type": "string",
"enum": [
"unknown",
"subtask",
"parenttask",
"related",
"duplicateof",
"duplicates",
"blocking",
"blocked",
"precedes",
"follows",
"copiedfrom",
"copiedto"
],
"x-enum-varnames": [
"RelationKindUnknown",
"RelationKindSubtask",
"RelationKindParenttask",
"RelationKindRelated",
"RelationKindDuplicateOf",
"RelationKindDuplicates",
"RelationKindBlocking",
"RelationKindBlocked",
"RelationKindPreceeds",
"RelationKindFollows",
"RelationKindCopiedFrom",
"RelationKindCopiedTo"
]
},
"models.Right": {
"type": "integer",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"RightRead",
"RightWrite",
"RightAdmin"
]
},
"models.SavedFilter": { "models.SavedFilter": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -8382,7 +8320,11 @@
}, },
"filters": { "filters": {
"description": "The actual filters this filter contains", "description": "The actual filters this filter contains",
"allOf": [
{
"$ref": "#/definitions/models.TaskCollection" "$ref": "#/definitions/models.TaskCollection"
}
]
}, },
"id": { "id": {
"description": "The unique numeric id of this saved filter", "description": "The unique numeric id of this saved filter",
@ -8394,7 +8336,11 @@
}, },
"owner": { "owner": {
"description": "The user who owns this filter", "description": "The user who owns this filter",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"title": { "title": {
"description": "The title of the filter.", "description": "The title of the filter.",
@ -8405,10 +8351,21 @@
"updated": { "updated": {
"description": "A timestamp when this filter was last updated. You cannot change this value.", "description": "A timestamp when this filter was last updated. You cannot change this value.",
"type": "string" "type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
} }
}
},
"models.SharingType": {
"type": "integer",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"SharingTypeUnknown",
"SharingTypeWithoutPassword",
"SharingTypeWithPassword"
]
}, },
"models.Subscription": { "models.Subscription": {
"type": "object", "type": "object",
@ -8430,10 +8387,12 @@
}, },
"user": { "user": {
"description": "The user who made this subscription", "description": "The user who made this subscription",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}, }
"web.CRUDable": {}, ]
"web.Rights": {} }
} }
}, },
"models.Task": { "models.Task": {
@ -8467,7 +8426,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who initially created the task.", "description": "The user who initially created the task.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The task description.", "description": "The task description.",
@ -8539,7 +8502,11 @@
}, },
"related_tasks": { "related_tasks": {
"description": "All related tasks, grouped by their relation kind", "description": "All related tasks, grouped by their relation kind",
"allOf": [
{
"$ref": "#/definitions/models.RelatedTaskMap" "$ref": "#/definitions/models.RelatedTaskMap"
}
]
}, },
"reminder_dates": { "reminder_dates": {
"description": "An array of datetimes when the user wants to be reminded of the task.", "description": "An array of datetimes when the user wants to be reminded of the task.",
@ -8554,7 +8521,11 @@
}, },
"repeat_mode": { "repeat_mode": {
"description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.", "description": "Can have three possible values which will trigger when the task is marked as done: 0 = repeats after the amount specified in repeat_after, 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from the current date rather than the last set date.",
"type": "integer" "allOf": [
{
"$ref": "#/definitions/models.TaskRepeatMode"
}
]
}, },
"start_date": { "start_date": {
"description": "When this task starts.", "description": "When this task starts.",
@ -8562,7 +8533,11 @@
}, },
"subscription": { "subscription": {
"description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.", "description": "The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one task.",
"allOf": [
{
"$ref": "#/definitions/models.Subscription" "$ref": "#/definitions/models.Subscription"
}
]
}, },
"title": { "title": {
"description": "The task text. This is what you'll see in the list.", "description": "The task text. This is what you'll see in the list.",
@ -8572,9 +8547,7 @@
"updated": { "updated": {
"description": "A timestamp when this task was last updated. You cannot change this value.", "description": "A timestamp when this task was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskAssginee": { "models.TaskAssginee": {
@ -8585,9 +8558,7 @@
}, },
"user_id": { "user_id": {
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskAttachment": { "models.TaskAttachment": {
@ -8607,9 +8578,7 @@
}, },
"task_id": { "task_id": {
"type": "integer" "type": "integer"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskCollection": { "models.TaskCollection": {
@ -8657,9 +8626,7 @@
"items": { "items": {
"type": "string" "type": "string"
} }
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskComment": { "models.TaskComment": {
@ -8679,9 +8646,7 @@
}, },
"updated": { "updated": {
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TaskRelation": { "models.TaskRelation": {
@ -8693,7 +8658,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who created this relation", "description": "The user who created this relation",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"other_task_id": { "other_task_id": {
"description": "The ID of the other task, the task which is being related.", "description": "The ID of the other task, the task which is being related.",
@ -8701,15 +8670,30 @@
}, },
"relation_kind": { "relation_kind": {
"description": "The kind of the relation.", "description": "The kind of the relation.",
"type": "string" "allOf": [
{
"$ref": "#/definitions/models.RelationKind"
}
]
}, },
"task_id": { "task_id": {
"description": "The ID of the \"base\" task, the task which has a relation to another.", "description": "The ID of the \"base\" task, the task which has a relation to another.",
"type": "integer" "type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
} }
}
},
"models.TaskRepeatMode": {
"type": "integer",
"enum": [
0,
1,
2
],
"x-enum-varnames": [
"TaskRepeatModeDefault",
"TaskRepeatModeMonth",
"TaskRepeatModeFromCurrentDate"
]
}, },
"models.Team": { "models.Team": {
"type": "object", "type": "object",
@ -8720,7 +8704,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who created this team.", "description": "The user who created this team.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The team's description.", "description": "The team's description.",
@ -8746,9 +8734,7 @@
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamList": { "models.TeamList": {
@ -8764,9 +8750,13 @@
}, },
"right": { "right": {
"description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"team_id": { "team_id": {
"description": "The team id.", "description": "The team id.",
@ -8775,9 +8765,7 @@
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamMember": { "models.TeamMember": {
@ -8798,9 +8786,7 @@
"username": { "username": {
"description": "The username of the member. We use this to prevent automated user id entering.", "description": "The username of the member. We use this to prevent automated user id entering.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamNamespace": { "models.TeamNamespace": {
@ -8816,9 +8802,13 @@
}, },
"right": { "right": {
"description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.",
"type": "integer",
"default": 0, "default": 0,
"maximum": 2 "maximum": 2,
"allOf": [
{
"$ref": "#/definitions/models.Right"
}
]
}, },
"team_id": { "team_id": {
"description": "The team id.", "description": "The team id.",
@ -8827,9 +8817,7 @@
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.TeamUser": { "models.TeamUser": {
@ -8865,8 +8853,7 @@
"type": "string", "type": "string",
"maxLength": 250, "maxLength": 250,
"minLength": 1 "minLength": 1
}, }
"web.Auth": {}
} }
}, },
"models.TeamWithRight": { "models.TeamWithRight": {
@ -8878,7 +8865,11 @@
}, },
"created_by": { "created_by": {
"description": "The user who created this team.", "description": "The user who created this team.",
"allOf": [
{
"$ref": "#/definitions/user.User" "$ref": "#/definitions/user.User"
}
]
}, },
"description": { "description": {
"description": "The team's description.", "description": "The team's description.",
@ -8902,16 +8893,12 @@
"minLength": 1 "minLength": 1
}, },
"right": { "right": {
"description": "The right this team has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "$ref": "#/definitions/models.Right"
"type": "integer",
"default": 0
}, },
"updated": { "updated": {
"description": "A timestamp when this relation was last updated. You cannot change this value.", "description": "A timestamp when this relation was last updated. You cannot change this value.",
"type": "string" "type": "string"
}, }
"web.CRUDable": {},
"web.Rights": {}
} }
}, },
"models.UserWithRight": { "models.UserWithRight": {
@ -8935,9 +8922,7 @@
"type": "string" "type": "string"
}, },
"right": { "right": {
"description": "The right this user has. 0 = Read only, 1 = Read \u0026 Write, 2 = Admin. See the docs for more details.", "$ref": "#/definitions/models.Right"
"type": "integer",
"default": 0
}, },
"updated": { "updated": {
"description": "A timestamp when this task was last updated. You cannot change this value.", "description": "A timestamp when this task was last updated. You cannot change this value.",
@ -8948,8 +8933,7 @@
"type": "string", "type": "string",
"maxLength": 250, "maxLength": 250,
"minLength": 1 "minLength": 1
}, }
"web.Auth": {}
} }
}, },
"notifications.DatabaseNotification": { "notifications.DatabaseNotification": {
@ -8999,6 +8983,9 @@
"key": { "key": {
"type": "string" "type": "string"
}, },
"logout_url": {
"type": "string"
},
"name": { "name": {
"type": "string" "type": "string"
} }
@ -9178,8 +9165,7 @@
"type": "string", "type": "string",
"maxLength": 250, "maxLength": 250,
"minLength": 1 "minLength": 1
}, }
"web.Auth": {}
} }
}, },
"v1.LinkShareAuth": { "v1.LinkShareAuth": {
@ -9387,15 +9373,6 @@
"type": "string" "type": "string"
} }
} }
},
"wunderlist.Migration": {
"type": "object",
"properties": {
"code": {
"description": "Code is the code used to get a user api token",
"type": "string"
}
}
} }
}, },
"securityDefinitions": { "securityDefinitions": {

View File

@ -58,30 +58,9 @@ definitions:
value. value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who initially created the bucket. description: The user who initially created the bucket.
filter_by:
description: The field name of the field to filter by
items:
type: string
type: array
filter_comparator:
description: The comparator for field and value
items:
type: string
type: array
filter_concat:
description: The way all filter conditions are concatenated together, can
be either "and" or "or".,
type: string
filter_include_nulls:
description: If set to true, the result will also include null values
type: boolean
filter_value:
description: The value of the field name to filter by
items:
type: string
type: array
id: id:
description: The unique, numeric id of this bucket. description: The unique, numeric id of this bucket.
type: integer type: integer
@ -97,22 +76,10 @@ definitions:
list_id: list_id:
description: The list this bucket belongs to. description: The list this bucket belongs to.
type: integer type: integer
order_by:
description: The query parameter to order the items by. This can be either
asc or desc, with asc being the default.
items:
type: string
type: array
position: position:
description: The position this bucket has when querying all buckets. See the description: The position this bucket has when querying all buckets. See the
tasks.position property on how to use this. tasks.position property on how to use this.
type: number type: number
sort_by:
description: The query parameter to sort by. This is for ex. done, priority,
etc.
items:
type: string
type: array
tasks: tasks:
description: All tasks which belong to this bucket. description: All tasks which belong to this bucket.
items: items:
@ -126,8 +93,6 @@ definitions:
description: A timestamp when this bucket was last updated. You cannot change description: A timestamp when this bucket was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.BulkAssignees: models.BulkAssignees:
properties: properties:
@ -136,8 +101,6 @@ definitions:
items: items:
$ref: '#/definitions/user.User' $ref: '#/definitions/user.User'
type: array type: array
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.BulkTask: models.BulkTask:
properties: properties:
@ -163,7 +126,8 @@ definitions:
value. value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who initially created the task. description: The user who initially created the task.
description: description:
description: The task description. description: The task description.
@ -228,7 +192,8 @@ definitions:
sort by this later. sort by this later.
type: integer type: integer
related_tasks: related_tasks:
$ref: '#/definitions/models.RelatedTaskMap' allOf:
- $ref: '#/definitions/models.RelatedTaskMap'
description: All related tasks, grouped by their relation kind description: All related tasks, grouped by their relation kind
reminder_dates: reminder_dates:
description: An array of datetimes when the user wants to be reminded of the description: An array of datetimes when the user wants to be reminded of the
@ -242,16 +207,18 @@ definitions:
increase all remindes and the due date by its amount. increase all remindes and the due date by its amount.
type: integer type: integer
repeat_mode: repeat_mode:
allOf:
- $ref: '#/definitions/models.TaskRepeatMode'
description: 'Can have three possible values which will trigger when the task description: 'Can have three possible values which will trigger when the task
is marked as done: 0 = repeats after the amount specified in repeat_after, is marked as done: 0 = repeats after the amount specified in repeat_after,
1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from
the current date rather than the last set date.' the current date rather than the last set date.'
type: integer
start_date: start_date:
description: When this task starts. description: When this task starts.
type: string type: string
subscription: subscription:
$ref: '#/definitions/models.Subscription' allOf:
- $ref: '#/definitions/models.Subscription'
description: |- description: |-
The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it. The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.
Will only returned when retreiving one task. Will only returned when retreiving one task.
@ -268,8 +235,6 @@ definitions:
description: A timestamp when this task was last updated. You cannot change description: A timestamp when this task was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.DatabaseNotifications: models.DatabaseNotifications:
properties: properties:
@ -294,8 +259,6 @@ definitions:
description: When this notification is marked as read, this will be updated description: When this notification is marked as read, this will be updated
with the current timestamp. with the current timestamp.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.Label: models.Label:
properties: properties:
@ -304,7 +267,8 @@ definitions:
value. value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who created this label description: The user who created this label
description: description:
description: The label description. description: The label description.
@ -326,8 +290,6 @@ definitions:
description: A timestamp when this label was last updated. You cannot change description: A timestamp when this label was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.LabelTask: models.LabelTask:
properties: properties:
@ -338,8 +300,6 @@ definitions:
label_id: label_id:
description: The label id you want to associate with a task. description: The label id you want to associate with a task.
type: integer type: integer
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.LabelTaskBulk: models.LabelTaskBulk:
properties: properties:
@ -348,8 +308,6 @@ definitions:
items: items:
$ref: '#/definitions/models.Label' $ref: '#/definitions/models.Label'
type: array type: array
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.LinkSharing: models.LinkSharing:
properties: properties:
@ -372,26 +330,27 @@ definitions:
it after the link share has been created. it after the link share has been created.
type: string type: string
right: right:
allOf:
- $ref: '#/definitions/models.Right'
default: 0 default: 0
description: The right this list is shared with. 0 = Read only, 1 = Read & description: The right this list is shared with. 0 = Read only, 1 = Read &
Write, 2 = Admin. See the docs for more details. Write, 2 = Admin. See the docs for more details.
maximum: 2 maximum: 2
type: integer
shared_by: shared_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who shared this list description: The user who shared this list
sharing_type: sharing_type:
allOf:
- $ref: '#/definitions/models.SharingType'
default: 0 default: 0
description: The kind of this link. 0 = undefined, 1 = without password, 2 description: The kind of this link. 0 = undefined, 1 = without password, 2
= with password. = with password.
maximum: 2 maximum: 2
type: integer
updated: updated:
description: A timestamp when this share was last updated. You cannot change description: A timestamp when this share was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.List: models.List:
properties: properties:
@ -433,14 +392,16 @@ definitions:
namespace_id: namespace_id:
type: integer type: integer
owner: owner:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who created this list. description: The user who created this list.
position: position:
description: The position this list has when querying all lists. See the tasks.position description: The position this list has when querying all lists. See the tasks.position
property on how to use this. property on how to use this.
type: number type: number
subscription: subscription:
$ref: '#/definitions/models.Subscription' allOf:
- $ref: '#/definitions/models.Subscription'
description: |- description: |-
The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it. The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.
Will only returned when retreiving one list. Will only returned when retreiving one list.
@ -453,19 +414,16 @@ definitions:
description: A timestamp when this list was last updated. You cannot change description: A timestamp when this list was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.ListDuplicate: models.ListDuplicate:
properties: properties:
list: list:
$ref: '#/definitions/models.List' allOf:
- $ref: '#/definitions/models.List'
description: The copied list description: The copied list
namespace_id: namespace_id:
description: The target namespace ID description: The target namespace ID
type: integer type: integer
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.ListUser: models.ListUser:
properties: properties:
@ -477,11 +435,12 @@ definitions:
description: The unique, numeric id of this list <-> user relation. description: The unique, numeric id of this list <-> user relation.
type: integer type: integer
right: right:
allOf:
- $ref: '#/definitions/models.Right'
default: 0 default: 0
description: The right this user has. 0 = Read only, 1 = Read & Write, 2 = description: The right this user has. 0 = Read only, 1 = Read & Write, 2 =
Admin. See the docs for more details. Admin. See the docs for more details.
maximum: 2 maximum: 2
type: integer
updated: updated:
description: A timestamp when this relation was last updated. You cannot change description: A timestamp when this relation was last updated. You cannot change
this value. this value.
@ -489,8 +448,6 @@ definitions:
user_id: user_id:
description: The username. description: The username.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.Message: models.Message:
properties: properties:
@ -518,10 +475,12 @@ definitions:
description: Whether or not a namespace is archived. description: Whether or not a namespace is archived.
type: boolean type: boolean
owner: owner:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who owns this namespace description: The user who owns this namespace
subscription: subscription:
$ref: '#/definitions/models.Subscription' allOf:
- $ref: '#/definitions/models.Subscription'
description: |- description: |-
The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it. The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.
Will only returned when retreiving one namespace. Will only returned when retreiving one namespace.
@ -534,8 +493,6 @@ definitions:
description: A timestamp when this namespace was last updated. You cannot description: A timestamp when this namespace was last updated. You cannot
change this value. change this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.NamespaceUser: models.NamespaceUser:
properties: properties:
@ -547,11 +504,12 @@ definitions:
description: The unique, numeric id of this namespace <-> user relation. description: The unique, numeric id of this namespace <-> user relation.
type: integer type: integer
right: right:
allOf:
- $ref: '#/definitions/models.Right'
default: 0 default: 0
description: The right this user has. 0 = Read only, 1 = Read & Write, 2 = description: The right this user has. 0 = Read only, 1 = Read & Write, 2 =
Admin. See the docs for more details. Admin. See the docs for more details.
maximum: 2 maximum: 2
type: integer
updated: updated:
description: A timestamp when this relation was last updated. You cannot change description: A timestamp when this relation was last updated. You cannot change
this value. this value.
@ -559,8 +517,6 @@ definitions:
user_id: user_id:
description: The username. description: The username.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.NamespaceWithLists: models.NamespaceWithLists:
properties: properties:
@ -586,10 +542,12 @@ definitions:
$ref: '#/definitions/models.List' $ref: '#/definitions/models.List'
type: array type: array
owner: owner:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who owns this namespace description: The user who owns this namespace
subscription: subscription:
$ref: '#/definitions/models.Subscription' allOf:
- $ref: '#/definitions/models.Subscription'
description: |- description: |-
The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it. The subscription status for the user reading this namespace. You can only read this property, use the subscription endpoints to modify it.
Will only returned when retreiving one namespace. Will only returned when retreiving one namespace.
@ -602,8 +560,6 @@ definitions:
description: A timestamp when this namespace was last updated. You cannot description: A timestamp when this namespace was last updated. You cannot
change this value. change this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.RelatedTaskMap: models.RelatedTaskMap:
additionalProperties: additionalProperties:
@ -611,6 +567,44 @@ definitions:
$ref: '#/definitions/models.Task' $ref: '#/definitions/models.Task'
type: array type: array
type: object type: object
models.RelationKind:
enum:
- unknown
- subtask
- parenttask
- related
- duplicateof
- duplicates
- blocking
- blocked
- precedes
- follows
- copiedfrom
- copiedto
type: string
x-enum-varnames:
- RelationKindUnknown
- RelationKindSubtask
- RelationKindParenttask
- RelationKindRelated
- RelationKindDuplicateOf
- RelationKindDuplicates
- RelationKindBlocking
- RelationKindBlocked
- RelationKindPreceeds
- RelationKindFollows
- RelationKindCopiedFrom
- RelationKindCopiedTo
models.Right:
enum:
- 0
- 1
- 2
type: integer
x-enum-varnames:
- RightRead
- RightWrite
- RightAdmin
models.SavedFilter: models.SavedFilter:
properties: properties:
created: created:
@ -621,7 +615,8 @@ definitions:
description: The description of the filter description: The description of the filter
type: string type: string
filters: filters:
$ref: '#/definitions/models.TaskCollection' allOf:
- $ref: '#/definitions/models.TaskCollection'
description: The actual filters this filter contains description: The actual filters this filter contains
id: id:
description: The unique numeric id of this saved filter description: The unique numeric id of this saved filter
@ -631,7 +626,8 @@ definitions:
a separate namespace together with favorite lists. a separate namespace together with favorite lists.
type: boolean type: boolean
owner: owner:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who owns this filter description: The user who owns this filter
title: title:
description: The title of the filter. description: The title of the filter.
@ -642,9 +638,17 @@ definitions:
description: A timestamp when this filter was last updated. You cannot change description: A timestamp when this filter was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.SharingType:
enum:
- 0
- 1
- 2
type: integer
x-enum-varnames:
- SharingTypeUnknown
- SharingTypeWithoutPassword
- SharingTypeWithPassword
models.Subscription: models.Subscription:
properties: properties:
created: created:
@ -660,10 +664,9 @@ definitions:
description: The numeric ID of the subscription description: The numeric ID of the subscription
type: integer type: integer
user: user:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who made this subscription description: The user who made this subscription
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.Task: models.Task:
properties: properties:
@ -689,7 +692,8 @@ definitions:
value. value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who initially created the task. description: The user who initially created the task.
description: description:
description: The task description. description: The task description.
@ -754,7 +758,8 @@ definitions:
sort by this later. sort by this later.
type: integer type: integer
related_tasks: related_tasks:
$ref: '#/definitions/models.RelatedTaskMap' allOf:
- $ref: '#/definitions/models.RelatedTaskMap'
description: All related tasks, grouped by their relation kind description: All related tasks, grouped by their relation kind
reminder_dates: reminder_dates:
description: An array of datetimes when the user wants to be reminded of the description: An array of datetimes when the user wants to be reminded of the
@ -768,16 +773,18 @@ definitions:
increase all remindes and the due date by its amount. increase all remindes and the due date by its amount.
type: integer type: integer
repeat_mode: repeat_mode:
allOf:
- $ref: '#/definitions/models.TaskRepeatMode'
description: 'Can have three possible values which will trigger when the task description: 'Can have three possible values which will trigger when the task
is marked as done: 0 = repeats after the amount specified in repeat_after, is marked as done: 0 = repeats after the amount specified in repeat_after,
1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from 1 = repeats all dates each months (ignoring repeat_after), 3 = repeats from
the current date rather than the last set date.' the current date rather than the last set date.'
type: integer
start_date: start_date:
description: When this task starts. description: When this task starts.
type: string type: string
subscription: subscription:
$ref: '#/definitions/models.Subscription' allOf:
- $ref: '#/definitions/models.Subscription'
description: |- description: |-
The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it. The subscription status for the user reading this task. You can only read this property, use the subscription endpoints to modify it.
Will only returned when retreiving one task. Will only returned when retreiving one task.
@ -789,8 +796,6 @@ definitions:
description: A timestamp when this task was last updated. You cannot change description: A timestamp when this task was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TaskAssginee: models.TaskAssginee:
properties: properties:
@ -798,8 +803,6 @@ definitions:
type: string type: string
user_id: user_id:
type: integer type: integer
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TaskAttachment: models.TaskAttachment:
properties: properties:
@ -813,8 +816,6 @@ definitions:
type: integer type: integer
task_id: task_id:
type: integer type: integer
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TaskCollection: models.TaskCollection:
properties: properties:
@ -852,8 +853,6 @@ definitions:
items: items:
type: string type: string
type: array type: array
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TaskComment: models.TaskComment:
properties: properties:
@ -867,8 +866,6 @@ definitions:
type: integer type: integer
updated: updated:
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TaskRelation: models.TaskRelation:
properties: properties:
@ -877,20 +874,30 @@ definitions:
value. value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who created this relation description: The user who created this relation
other_task_id: other_task_id:
description: The ID of the other task, the task which is being related. description: The ID of the other task, the task which is being related.
type: integer type: integer
relation_kind: relation_kind:
allOf:
- $ref: '#/definitions/models.RelationKind'
description: The kind of the relation. description: The kind of the relation.
type: string
task_id: task_id:
description: The ID of the "base" task, the task which has a relation to another. description: The ID of the "base" task, the task which has a relation to another.
type: integer type: integer
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TaskRepeatMode:
enum:
- 0
- 1
- 2
type: integer
x-enum-varnames:
- TaskRepeatModeDefault
- TaskRepeatModeMonth
- TaskRepeatModeFromCurrentDate
models.Team: models.Team:
properties: properties:
created: created:
@ -898,7 +905,8 @@ definitions:
this value. this value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who created this team. description: The user who created this team.
description: description:
description: The team's description. description: The team's description.
@ -920,8 +928,6 @@ definitions:
description: A timestamp when this relation was last updated. You cannot change description: A timestamp when this relation was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TeamList: models.TeamList:
properties: properties:
@ -933,11 +939,12 @@ definitions:
description: The unique, numeric id of this list <-> team relation. description: The unique, numeric id of this list <-> team relation.
type: integer type: integer
right: right:
allOf:
- $ref: '#/definitions/models.Right'
default: 0 default: 0
description: The right this team has. 0 = Read only, 1 = Read & Write, 2 = description: The right this team has. 0 = Read only, 1 = Read & Write, 2 =
Admin. See the docs for more details. Admin. See the docs for more details.
maximum: 2 maximum: 2
type: integer
team_id: team_id:
description: The team id. description: The team id.
type: integer type: integer
@ -945,8 +952,6 @@ definitions:
description: A timestamp when this relation was last updated. You cannot change description: A timestamp when this relation was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TeamMember: models.TeamMember:
properties: properties:
@ -965,8 +970,6 @@ definitions:
description: The username of the member. We use this to prevent automated description: The username of the member. We use this to prevent automated
user id entering. user id entering.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TeamNamespace: models.TeamNamespace:
properties: properties:
@ -978,11 +981,12 @@ definitions:
description: The unique, numeric id of this namespace <-> team relation. description: The unique, numeric id of this namespace <-> team relation.
type: integer type: integer
right: right:
allOf:
- $ref: '#/definitions/models.Right'
default: 0 default: 0
description: The right this team has. 0 = Read only, 1 = Read & Write, 2 = description: The right this team has. 0 = Read only, 1 = Read & Write, 2 =
Admin. See the docs for more details. Admin. See the docs for more details.
maximum: 2 maximum: 2
type: integer
team_id: team_id:
description: The team id. description: The team id.
type: integer type: integer
@ -990,8 +994,6 @@ definitions:
description: A timestamp when this relation was last updated. You cannot change description: A timestamp when this relation was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.TeamUser: models.TeamUser:
properties: properties:
@ -1022,7 +1024,6 @@ definitions:
maxLength: 250 maxLength: 250
minLength: 1 minLength: 1
type: string type: string
web.Auth: {}
type: object type: object
models.TeamWithRight: models.TeamWithRight:
properties: properties:
@ -1031,7 +1032,8 @@ definitions:
this value. this value.
type: string type: string
created_by: created_by:
$ref: '#/definitions/user.User' allOf:
- $ref: '#/definitions/user.User'
description: The user who created this team. description: The user who created this team.
description: description:
description: The team's description. description: The team's description.
@ -1050,16 +1052,11 @@ definitions:
minLength: 1 minLength: 1
type: string type: string
right: right:
default: 0 $ref: '#/definitions/models.Right'
description: The right this team has. 0 = Read only, 1 = Read & Write, 2 =
Admin. See the docs for more details.
type: integer
updated: updated:
description: A timestamp when this relation was last updated. You cannot change description: A timestamp when this relation was last updated. You cannot change
this value. this value.
type: string type: string
web.CRUDable: {}
web.Rights: {}
type: object type: object
models.UserWithRight: models.UserWithRight:
properties: properties:
@ -1078,10 +1075,7 @@ definitions:
description: The full name of the user. description: The full name of the user.
type: string type: string
right: right:
default: 0 $ref: '#/definitions/models.Right'
description: The right this user has. 0 = Read only, 1 = Read & Write, 2 =
Admin. See the docs for more details.
type: integer
updated: updated:
description: A timestamp when this task was last updated. You cannot change description: A timestamp when this task was last updated. You cannot change
this value. this value.
@ -1091,7 +1085,6 @@ definitions:
maxLength: 250 maxLength: 250
minLength: 1 minLength: 1
type: string type: string
web.Auth: {}
type: object type: object
notifications.DatabaseNotification: notifications.DatabaseNotification:
properties: properties:
@ -1127,6 +1120,8 @@ definitions:
type: string type: string
key: key:
type: string type: string
logout_url:
type: string
name: name:
type: string type: string
type: object type: object
@ -1258,7 +1253,6 @@ definitions:
maxLength: 250 maxLength: 250
minLength: 1 minLength: 1
type: string type: string
web.Auth: {}
type: object type: object
v1.LinkShareAuth: v1.LinkShareAuth:
properties: properties:
@ -1407,12 +1401,6 @@ definitions:
message: message:
type: string type: string
type: object type: object
wunderlist.Migration:
properties:
code:
description: Code is the code used to get a user api token
type: string
type: object
info: info:
contact: contact:
email: hello@vikunja.io email: hello@vikunja.io
@ -3490,77 +3478,6 @@ paths:
summary: Get migration status summary: Get migration status
tags: tags:
- migration - migration
/migration/wunderlist/auth:
get:
description: Returns the auth url where the user needs to get its auth code.
This code can then be used to migrate everything from wunderlist to Vikunja.
produces:
- application/json
responses:
"200":
description: The auth url.
schema:
$ref: '#/definitions/handler.AuthURL'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.Message'
security:
- JWTKeyAuth: []
summary: Get the auth url from wunderlist
tags:
- migration
/migration/wunderlist/migrate:
post:
consumes:
- application/json
description: Migrates all folders, lists, tasks, notes, reminders, subtasks
and files from wunderlist to vikunja.
parameters:
- description: The auth code previously obtained from the auth url. See the
docs for /migration/wunderlist/auth.
in: body
name: migrationCode
required: true
schema:
$ref: '#/definitions/wunderlist.Migration'
produces:
- application/json
responses:
"200":
description: A message telling you everything was migrated successfully.
schema:
$ref: '#/definitions/models.Message'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.Message'
security:
- JWTKeyAuth: []
summary: Migrate all lists, tasks etc. from wunderlist
tags:
- migration
/migration/wunderlist/status:
get:
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.
produces:
- application/json
responses:
"200":
description: The migration status
schema:
$ref: '#/definitions/migration.Status'
"500":
description: Internal server error
schema:
$ref: '#/definitions/models.Message'
security:
- JWTKeyAuth: []
summary: Get migration status
tags:
- migration
/namespace/{id}: /namespace/{id}:
post: post:
consumes: consumes: