Compare commits
42 Commits
f785024dc4
...
f54fdd7f6d
Author | SHA1 | Date |
---|---|---|
renovate | f54fdd7f6d | |
Dominik Pschenitschni | 508a3157e2 | |
TheDubliner | 321a8f7e2b | |
renovate | dd7dcdd0cc | |
renovate | cb6368036c | |
renovate | 36dfcb8ddb | |
renovate | 7f8c85118e | |
renovate | f3476bec6c | |
kolaente | 392bdd1b94 | |
renovate | 80634d43c1 | |
kolaente | 4fa45bf9dc | |
konrad | ef1d1e2b20 | |
Dominik Pschenitschni | ca3580766e | |
renovate | c6429c8b13 | |
renovate | 304481cf28 | |
kolaente | 897a6e5d5c | |
kolaente | 194b88e2eb | |
kolaente | c5327845ee | |
kolaente | ea1d06bda6 | |
kolaente | 0104aa504b | |
kolaente | 6a97a214a3 | |
viehlieb | a79b1de2d0 | |
renovate | e9ce930230 | |
renovate | 6cb48e430e | |
renovate | a2c8426d02 | |
renovate | 3be10ca4a2 | |
renovate | ec297009d3 | |
renovate | dbc30284f3 | |
renovate | 879324dcd0 | |
renovate | 3be6e93a05 | |
kolaente | f93317bf5d | |
renovate | 1cfdb085e5 | |
kolaente | 51cf8beaed | |
kolaente | b8c3b570a4 | |
renovate | 8ae062a095 | |
kolaente | 941d1e06c5 | |
kolaente | 1f2eb57602 | |
kolaente | 51911a8868 | |
kolaente | 47aae115df | |
kolaente | fbc4b91e0f | |
kolaente | 8c67be558f | |
renovate | e27cd9b336 |
86
.drone.yml
86
.drone.yml
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: testing
|
||||
|
||||
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.
|
||||
- name: mage
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
commands:
|
||||
|
@ -122,7 +123,7 @@ steps:
|
|||
|
||||
- name: build
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
depends_on: [ mage ]
|
||||
|
@ -133,7 +134,7 @@ steps:
|
|||
|
||||
- name: lint
|
||||
image: golang:1.19-alpine
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
depends_on: [ build ]
|
||||
|
@ -147,7 +148,7 @@ steps:
|
|||
|
||||
- name: test-migration-prepare
|
||||
image: kolaente/toolbox:latest
|
||||
pull: true
|
||||
pull: always
|
||||
commands:
|
||||
# Get the latest version
|
||||
- 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
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
depends_on: [ test-migration-prepare, build ]
|
||||
environment:
|
||||
VIKUNJA_DATABASE_TYPE: sqlite
|
||||
|
@ -174,7 +175,7 @@ steps:
|
|||
|
||||
- name: test-migration-mysql
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
depends_on: [ test-migration-prepare, build ]
|
||||
environment:
|
||||
VIKUNJA_DATABASE_TYPE: mysql
|
||||
|
@ -193,7 +194,7 @@ steps:
|
|||
|
||||
- name: test-migration-psql
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
depends_on: [ test-migration-prepare, build ]
|
||||
environment:
|
||||
VIKUNJA_DATABASE_TYPE: postgres
|
||||
|
@ -213,7 +214,7 @@ steps:
|
|||
|
||||
- name: test
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
commands:
|
||||
|
@ -224,7 +225,7 @@ steps:
|
|||
|
||||
- name: test-sqlite
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
VIKUNJA_TESTS_USE_CONFIG: 1
|
||||
|
@ -241,7 +242,7 @@ steps:
|
|||
|
||||
- name: test-mysql
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
VIKUNJA_TESTS_USE_CONFIG: 1
|
||||
|
@ -258,7 +259,7 @@ steps:
|
|||
|
||||
- name: test-postgres
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
VIKUNJA_TESTS_USE_CONFIG: 1
|
||||
|
@ -276,7 +277,7 @@ steps:
|
|||
|
||||
- name: integration-test
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
commands:
|
||||
|
@ -287,7 +288,7 @@ steps:
|
|||
|
||||
- name: integration-test-sqlite
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
VIKUNJA_TESTS_USE_CONFIG: 1
|
||||
|
@ -304,7 +305,7 @@ steps:
|
|||
|
||||
- name: integration-test-mysql
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
VIKUNJA_TESTS_USE_CONFIG: 1
|
||||
|
@ -321,7 +322,7 @@ steps:
|
|||
|
||||
- name: integration-test-postgres
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
VIKUNJA_TESTS_USE_CONFIG: 1
|
||||
|
@ -343,14 +344,15 @@ steps:
|
|||
########
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: release
|
||||
|
||||
depends_on:
|
||||
- testing
|
||||
|
||||
workspace:
|
||||
base: /go
|
||||
path: src/code.vikunja.io/api
|
||||
base: /source
|
||||
path: /
|
||||
|
||||
trigger:
|
||||
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.
|
||||
- name: mage
|
||||
image: vikunja/golang-build:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
GOPROXY: 'https://goproxy.kolaente.de'
|
||||
commands:
|
||||
|
@ -378,7 +380,7 @@ steps:
|
|||
|
||||
- name: before-static-build
|
||||
image: techknowlogick/xgo:latest
|
||||
pull: true
|
||||
pull: always
|
||||
commands:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- go install github.com/magefile/mage
|
||||
|
@ -387,7 +389,7 @@ steps:
|
|||
|
||||
- name: static-build-windows
|
||||
image: techknowlogick/xgo:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
# 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.
|
||||
|
@ -400,7 +402,7 @@ steps:
|
|||
|
||||
- name: static-build-linux
|
||||
image: techknowlogick/xgo:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
# 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.
|
||||
|
@ -413,7 +415,7 @@ steps:
|
|||
|
||||
- name: static-build-darwin
|
||||
image: techknowlogick/xgo:latest
|
||||
pull: true
|
||||
pull: always
|
||||
environment:
|
||||
# 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.
|
||||
|
@ -426,7 +428,7 @@ steps:
|
|||
|
||||
- name: after-build-compress
|
||||
image: kolaente/upx
|
||||
pull: true
|
||||
pull: always
|
||||
depends_on:
|
||||
- static-build-windows
|
||||
- static-build-linux
|
||||
|
@ -436,7 +438,7 @@ steps:
|
|||
|
||||
- name: after-build-static
|
||||
image: techknowlogick/xgo:latest
|
||||
pull: true
|
||||
pull: always
|
||||
depends_on:
|
||||
- after-build-compress
|
||||
commands:
|
||||
|
@ -448,7 +450,7 @@ steps:
|
|||
|
||||
- name: sign-release
|
||||
image: plugins/gpgsign:1
|
||||
pull: true
|
||||
pull: always
|
||||
depends_on: [ after-build-static ]
|
||||
settings:
|
||||
key:
|
||||
|
@ -462,7 +464,7 @@ steps:
|
|||
# Push the releases to our pseudo-s3-bucket
|
||||
- name: release-latest
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
bucket: vikunja-releases
|
||||
access_key:
|
||||
|
@ -484,7 +486,7 @@ steps:
|
|||
|
||||
- name: release-version
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
bucket: vikunja-releases
|
||||
access_key:
|
||||
|
@ -504,8 +506,8 @@ steps:
|
|||
|
||||
# Build os packages and push it to our bucket
|
||||
- name: build-os-packages-unstable
|
||||
image: goreleaser/nfpm
|
||||
pull: true
|
||||
image: goreleaser/nfpm:v2.22.2
|
||||
pull: always
|
||||
commands:
|
||||
- apk add git go
|
||||
- ./mage-static release:packages
|
||||
|
@ -517,11 +519,11 @@ steps:
|
|||
- main
|
||||
event:
|
||||
- push
|
||||
depends_on: [ static-build-linux ]
|
||||
depends_on: [ after-build-compress ]
|
||||
|
||||
- name: build-os-packages-version
|
||||
image: goreleaser/nfpm
|
||||
pull: true
|
||||
image: goreleaser/nfpm:v2.22.2
|
||||
pull: always
|
||||
commands:
|
||||
- apk add git go
|
||||
- ./mage-static release:packages
|
||||
|
@ -531,12 +533,12 @@ steps:
|
|||
when:
|
||||
event:
|
||||
- tag
|
||||
depends_on: [ static-build-linux ]
|
||||
depends_on: [ after-build-compress ]
|
||||
|
||||
# Push the os releases to our pseudo-s3-bucket
|
||||
- name: release-os-latest
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
bucket: vikunja-releases
|
||||
access_key:
|
||||
|
@ -558,7 +560,7 @@ steps:
|
|||
|
||||
- name: release-os-version
|
||||
image: plugins/s3
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
bucket: vikunja-releases
|
||||
access_key:
|
||||
|
@ -578,6 +580,7 @@ steps:
|
|||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: deploy-docs
|
||||
|
||||
workspace:
|
||||
|
@ -596,8 +599,7 @@ trigger:
|
|||
steps:
|
||||
- name: theme
|
||||
image: kolaente/toolbox
|
||||
pull: true
|
||||
group: build-static
|
||||
pull: always
|
||||
commands:
|
||||
- mkdir docs/themes/vikunja -p
|
||||
- cd docs/themes/vikunja
|
||||
|
@ -606,7 +608,7 @@ steps:
|
|||
|
||||
- name: build
|
||||
image: klakegg/hugo:0.107.0
|
||||
pull: true
|
||||
pull: always
|
||||
commands:
|
||||
- cd docs
|
||||
- hugo
|
||||
|
@ -614,7 +616,7 @@ steps:
|
|||
|
||||
- name: docker
|
||||
image: plugins/docker
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
|
@ -646,7 +648,7 @@ steps:
|
|||
- name: docker-unstable
|
||||
image: thegeeklab/drone-docker-buildx
|
||||
privileged: true
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
|
@ -668,7 +670,7 @@ steps:
|
|||
- name: docker-release
|
||||
image: thegeeklab/drone-docker-buildx
|
||||
privileged: true
|
||||
pull: true
|
||||
pull: always
|
||||
settings:
|
||||
username:
|
||||
from_secret: docker_username
|
||||
|
@ -719,6 +721,6 @@ steps:
|
|||
- failure
|
||||
---
|
||||
kind: signature
|
||||
hmac: 768d54fc8433705fb63f754adf19536a16152a4046a040afdbcbb7df60614056
|
||||
hmac: 2c7e3250304826cb62d54db4e6d2638bc8f182097306fb93772d07d7bc3cf7e8
|
||||
|
||||
...
|
||||
|
|
|
@ -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
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
##############
|
||||
# Build stage
|
||||
FROM --platform=$BUILDPLATFORM techknowlogick/xgo:latest AS build-env
|
||||
FROM --platform=$BUILDPLATFORM techknowlogick/xgo:go-1.19.2 AS build-env
|
||||
|
||||
RUN \
|
||||
go install github.com/magefile/mage@latest && \
|
||||
|
|
|
@ -191,21 +191,6 @@ files:
|
|||
maxsize: 20MB
|
||||
|
||||
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:
|
||||
# Wheter to enable the todoist migrator or not
|
||||
enable: false
|
||||
|
@ -311,6 +296,9 @@ auth:
|
|||
- name:
|
||||
# The auth url to send users to if they want to authenticate using OpenID Connect.
|
||||
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.
|
||||
clientid:
|
||||
# The client secret used to authenticate Vikunja at the OpenID Connect provider.
|
||||
|
|
|
@ -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
|
||||
|
||||
Default: `<empty>`
|
||||
|
|
|
@ -10,7 +10,7 @@ menu:
|
|||
|
||||
# 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.
|
||||
|
||||
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
|
||||
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
|
||||
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/).
|
||||
|
||||
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`
|
||||
* The entrypoint you want to make vikunja available from is called `https`
|
||||
|
@ -398,7 +398,7 @@ docker main folders:
|
|||
* vikunja
|
||||
* 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
|
||||
|
||||
|
@ -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):
|
||||
1. Go to **Dashboard / Stacks** click the button **"Add Stack"**
|
||||
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)
|
||||
|
||||
|
|
|
@ -10,6 +10,6 @@ menu:
|
|||
|
||||
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)
|
||||
|
||||
|
|
36
go.mod
36
go.mod
|
@ -25,30 +25,31 @@ require (
|
|||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
|
||||
github.com/bbrks/go-blurhash v1.1.1
|
||||
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/d4l3k/messagediff v1.2.1
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
|
||||
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-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/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/google/uuid v1.3.0
|
||||
github.com/iancoleman/strcase v0.2.0
|
||||
github.com/imdario/mergo v0.3.13
|
||||
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/lib/pq v1.10.7
|
||||
github.com/magefile/mage v1.14.0
|
||||
github.com/mattn/go-sqlite3 v1.14.16
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
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/robfig/cron/v3 v3.0.1
|
||||
github.com/samedi/caldav-go v3.0.0+incompatible
|
||||
|
@ -56,18 +57,18 @@ require (
|
|||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/viper v1.14.0
|
||||
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/ulule/limiter/v3 v3.10.0
|
||||
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
|
||||
golang.org/x/crypto v0.3.0
|
||||
golang.org/x/image v0.1.0
|
||||
golang.org/x/oauth2 v0.1.0
|
||||
golang.org/x/crypto v0.5.0
|
||||
golang.org/x/image v0.3.0
|
||||
golang.org/x/oauth2 v0.3.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.2.0
|
||||
golang.org/x/term v0.2.0
|
||||
golang.org/x/sys v0.4.0
|
||||
golang.org/x/term v0.4.0
|
||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
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/ghodss/yaml v1.0.0 // 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/jsonreference v0.19.6 // 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/urfave/cli/v2 v2.3.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/net v0.2.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||
golang.org/x/net v0.5.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
|
|
126
go.sum
126
go.sum
|
@ -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.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/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.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
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/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/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/go.mod h1:BSTTrYHuM12oAL8jDdcmPdw02SBThKYWNFHQlvEG6b0=
|
||||
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/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.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-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=
|
||||
|
@ -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/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.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/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/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
|
||||
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
||||
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.14.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I=
|
||||
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/getsentry/sentry-go v0.16.0 h1:owk+S+5XcgJLlGR/3+3s6N4d+uKwqYvh/eS0AIMjPWo=
|
||||
github.com/getsentry/sentry-go v0.16.0/go.mod h1:ZXCloQLj0pG7mja5NK6NPf2V4A88YJ4pNlc2mOHwh6Y=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
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/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-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.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
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.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.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
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-testfixtures/testfixtures/v3 v3.8.1 h1:uonwvepqRvSgddcrReZQhojTlWlmOlHkYAb9ZaOMWgU=
|
||||
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/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/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
|
||||
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/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
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.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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.9.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
|
||||
github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
|
||||
github.com/labstack/echo/v4 v4.10.0 h1:5CiyngihEO4HXsz3vVsJn7f8xAlWwRr3aY6Ih280ZKA=
|
||||
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.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
|
||||
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.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.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/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
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.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
|
||||
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.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.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/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
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-20190812154241-14fe0d1b01d4/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.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
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/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/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/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
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 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/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
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.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
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/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
|
||||
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.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.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.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
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/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU=
|
||||
github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
|
||||
github.com/swaggo/swag v1.8.9 h1:kHtaBe/Ob9AZzAANfcn5c6RyCke9gG9QpH0jky0I/sA=
|
||||
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/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
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.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.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
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/go.mod h1:PnwzbSst7KD3vpBzzlntZU5gjVa455Uqa5QPiKSYJzQ=
|
||||
github.com/wneessen/go-mail v0.3.1 h1:9hSthi8T57gDHMI0fgl58O667OQJm9wZ1EHyuy3hclA=
|
||||
github.com/wneessen/go-mail v0.3.1/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
|
||||
github.com/wneessen/go-mail v0.3.2 h1:nTjAF4Ek2+JG7qunyk6oImf5YKrAE5a7A3uIazYsdM0=
|
||||
github.com/wneessen/go-mail v0.3.2/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/wneessen/go-mail v0.3.6 h1:hT8PMIBdcTkoiDwoUGJssPYOe1Gg1/cUcp2o9+ls63o=
|
||||
github.com/wneessen/go-mail v0.3.6/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
|
||||
github.com/wneessen/go-mail v0.3.7 h1:loEAGLvsDZLSiE6c+keBfg0gpias/R3ocFU8Eoh3Pq4=
|
||||
github.com/wneessen/go-mail v0.3.7/go.mod h1:m25lkU2GYQnlVr6tdwK533/UXxo57V0kLOjaFYmub0E=
|
||||
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.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.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.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/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
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-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.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE=
|
||||
golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
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/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
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-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-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.1.0 h1:r8Oj8ZA2Xy12/b5KZYj3tuv7NG/fBz3TwQVvpJ9l8Rk=
|
||||
golang.org/x/image v0.1.0/go.mod h1:iyPr49SD/G/TBxYVB/9RRtGUT5eNbo2u4NamWeQcD5c=
|
||||
golang.org/x/image v0.2.0 h1:/DcQ0w3VHKCC5p0/P2B0JpAZ9Z++V2KOo2fyU89CXBQ=
|
||||
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-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
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-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.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
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-20190226205417-e64efc72b421/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-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
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.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
|
||||
golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8=
|
||||
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-20181108010431-42b317875d0f/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-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.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
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-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.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
||||
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.3.0/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.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.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
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-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-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-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
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-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
|
@ -703,7 +703,7 @@ func (Release) Packages() error {
|
|||
binpath := "nfpm"
|
||||
err = exec.Command(binpath).Run()
|
||||
if err != nil && strings.Contains(err.Error(), "executable file not found") {
|
||||
binpath = "/nfpm"
|
||||
binpath = "/usr/bin/nfpm"
|
||||
err = exec.Command(binpath).Run()
|
||||
}
|
||||
if err != nil && strings.Contains(err.Error(), "executable file not found") {
|
||||
|
@ -712,7 +712,7 @@ func (Release) Packages() error {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Because nfpm does not support templating, we replace the values in the config file and restore it after running
|
||||
// Because nfpm does not support templating, we replace the values in the config file and restore it after running
|
||||
nfpmConfigPath := RootPath + "/nfpm.yaml"
|
||||
nfpmconfig, err := os.ReadFile(nfpmConfigPath)
|
||||
if err != nil {
|
||||
|
|
|
@ -22,7 +22,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
)
|
||||
|
@ -58,10 +59,12 @@ type Todo struct {
|
|||
RelatedToUID string
|
||||
Color string
|
||||
|
||||
Start time.Time
|
||||
End time.Time
|
||||
DueDate time.Time
|
||||
Duration time.Duration
|
||||
Start time.Time
|
||||
End time.Time
|
||||
DueDate time.Time
|
||||
Duration time.Duration
|
||||
RepeatAfter int64
|
||||
RepeatMode models.TaskRepeatMode
|
||||
|
||||
Created time.Time
|
||||
Updated time.Time // last-mod
|
||||
|
@ -226,6 +229,16 @@ CREATED:` + makeCalDavTimeFromTimeStamp(t.Created)
|
|||
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 += `
|
||||
LAST-MODIFIED:` + makeCalDavTimeFromTimeStamp(t.Updated)
|
||||
|
||||
|
@ -240,7 +253,7 @@ END:VCALENDAR` // Need a line break
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -84,25 +86,25 @@ X-APPLE-CALENDAR-COLOR:#affffeFF
|
|||
X-OUTLOOK-COLOR:#affffeFF
|
||||
X-FUNAMBOL-COLOR:#affffeFF
|
||||
DESCRIPTION:Lorem Ipsum
|
||||
DTSTAMP:20181201T011204
|
||||
DTSTART:20181201T011204
|
||||
DTEND:20181201T013024
|
||||
DTSTAMP:20181201T011204Z
|
||||
DTSTART:20181201T011204Z
|
||||
DTEND:20181201T013024Z
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:randommduidd
|
||||
SUMMARY:Event #2
|
||||
DESCRIPTION:
|
||||
DTSTAMP:20181202T045844
|
||||
DTSTART:20181202T045844
|
||||
DTEND:20181202T081844
|
||||
DTSTAMP:20181202T045844Z
|
||||
DTSTART:20181202T045844Z
|
||||
DTEND:20181202T081844Z
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:20181202T0600242aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83
|
||||
SUMMARY:Event #3 with empty uid
|
||||
DESCRIPTION:
|
||||
DTSTAMP:20181202T050024
|
||||
DTSTART:20181202T050024
|
||||
DTEND:20181202T050320
|
||||
DTSTAMP:20181202T050024Z
|
||||
DTSTART:20181202T050024Z
|
||||
DTEND:20181202T050320Z
|
||||
END:VEVENT
|
||||
END:VCALENDAR`,
|
||||
},
|
||||
|
@ -169,9 +171,9 @@ BEGIN:VEVENT
|
|||
UID:randommduid
|
||||
SUMMARY:Event #1
|
||||
DESCRIPTION:Lorem Ipsum
|
||||
DTSTAMP:20181201T011204
|
||||
DTSTART:20181201T011204
|
||||
DTEND:20181201T013024
|
||||
DTSTAMP:20181201T011204Z
|
||||
DTSTART:20181201T011204Z
|
||||
DTEND:20181201T013024Z
|
||||
BEGIN:VALARM
|
||||
TRIGGER:-PT3M20S
|
||||
ACTION:DISPLAY
|
||||
|
@ -192,9 +194,9 @@ BEGIN:VEVENT
|
|||
UID:randommduidd
|
||||
SUMMARY:Event #2
|
||||
DESCRIPTION:
|
||||
DTSTAMP:20181202T045844
|
||||
DTSTART:20181202T045844
|
||||
DTEND:20181202T081844
|
||||
DTSTAMP:20181202T045844Z
|
||||
DTSTART:20181202T045844Z
|
||||
DTEND:20181202T081844Z
|
||||
BEGIN:VALARM
|
||||
TRIGGER:-PT27H50M0S
|
||||
ACTION:DISPLAY
|
||||
|
@ -212,12 +214,12 @@ DESCRIPTION:Event #2
|
|||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:20181202T0500242aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83
|
||||
UID:20181202T050024Z2aaef4a81d770c1e775e26bc5abebc87f1d3d7bffaa83
|
||||
SUMMARY:Event #3 with empty uid
|
||||
DESCRIPTION:
|
||||
DTSTAMP:20181202T050024
|
||||
DTSTART:20181202T050024
|
||||
DTEND:20181202T050320
|
||||
DTSTAMP:20181202T050024Z
|
||||
DTSTART:20181202T050024Z
|
||||
DTEND:20181202T050320Z
|
||||
BEGIN:VALARM
|
||||
TRIGGER:-PT27H51M40S
|
||||
ACTION:DISPLAY
|
||||
|
@ -240,12 +242,12 @@ DESCRIPTION:Event #3 with empty uid
|
|||
END:VALARM
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:20181202T050024ae7548ce9556df85038abe90dc674d4741a61ce74d1cf
|
||||
UID:20181202T050024Zae7548ce9556df85038abe90dc674d4741a61ce74d1cf
|
||||
SUMMARY:Event #4 without any
|
||||
DESCRIPTION:
|
||||
DTSTAMP:20181202T050024
|
||||
DTSTART:20181202T050024
|
||||
DTEND:20181202T050320
|
||||
DTSTAMP:20181202T050024Z
|
||||
DTSTART:20181202T050024Z
|
||||
DTEND:20181202T050320Z
|
||||
END:VEVENT
|
||||
END:VCALENDAR`,
|
||||
},
|
||||
|
@ -278,9 +280,9 @@ BEGIN:VEVENT
|
|||
UID:randommduid
|
||||
SUMMARY:Event #1
|
||||
DESCRIPTION:Lorem Ipsum\nDolor sit amet
|
||||
DTSTAMP:20181201T011204
|
||||
DTSTART:20181201T011204
|
||||
DTEND:20181201T013024
|
||||
DTSTAMP:20181201T011204Z
|
||||
DTSTART:20181201T011204Z
|
||||
DTEND:20181201T013024Z
|
||||
END:VEVENT
|
||||
END:VCALENDAR`,
|
||||
},
|
||||
|
@ -333,13 +335,13 @@ X-OUTLOOK-COLOR:#ffffffFF
|
|||
X-FUNAMBOL-COLOR:#ffffffFF
|
||||
BEGIN:VTODO
|
||||
UID:randommduid
|
||||
DTSTAMP:20181201T011204
|
||||
DTSTAMP:20181201T011204Z
|
||||
SUMMARY:Todo #1
|
||||
X-APPLE-CALENDAR-COLOR:#affffeFF
|
||||
X-OUTLOOK-COLOR:#affffeFF
|
||||
X-FUNAMBOL-COLOR:#affffeFF
|
||||
DESCRIPTION:Lorem Ipsum\nDolor sit amet
|
||||
LAST-MODIFIED:00010101T000000
|
||||
LAST-MODIFIED:00010101T000000Z
|
||||
END:VTODO
|
||||
END:VCALENDAR`,
|
||||
},
|
||||
|
@ -368,12 +370,12 @@ X-WR-CALNAME:test
|
|||
PRODID:-//RandomProdID which is not random//EN
|
||||
BEGIN:VTODO
|
||||
UID:randommduid
|
||||
DTSTAMP:20181201T011204
|
||||
DTSTAMP:20181201T011204Z
|
||||
SUMMARY:Todo #1
|
||||
DESCRIPTION:Lorem Ipsum
|
||||
COMPLETED:20181201T013024
|
||||
COMPLETED:20181201T013024Z
|
||||
STATUS:COMPLETED
|
||||
LAST-MODIFIED:00010101T000000
|
||||
LAST-MODIFIED:00010101T000000Z
|
||||
END:VTODO
|
||||
END:VCALENDAR`,
|
||||
},
|
||||
|
@ -402,11 +404,82 @@ X-WR-CALNAME:test
|
|||
PRODID:-//RandomProdID which is not random//EN
|
||||
BEGIN:VTODO
|
||||
UID:randommduid
|
||||
DTSTAMP:20181201T011204
|
||||
DTSTAMP:20181201T011204Z
|
||||
SUMMARY:Todo #1
|
||||
DESCRIPTION:Lorem Ipsum
|
||||
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:VCALENDAR`,
|
||||
},
|
||||
|
|
|
@ -42,13 +42,15 @@ func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*m
|
|||
Description: t.Description,
|
||||
Completed: t.DoneAt,
|
||||
// Organizer: &t.CreatedBy, // Disabled until we figure out how this works
|
||||
Priority: t.Priority,
|
||||
Start: t.StartDate,
|
||||
End: t.EndDate,
|
||||
Created: t.Created,
|
||||
Updated: t.Updated,
|
||||
DueDate: t.DueDate,
|
||||
Duration: duration,
|
||||
Priority: t.Priority,
|
||||
Start: t.StartDate,
|
||||
End: t.EndDate,
|
||||
Created: t.Created,
|
||||
Updated: t.Updated,
|
||||
DueDate: t.DueDate,
|
||||
Duration: duration,
|
||||
RepeatAfter: t.RepeatAfter,
|
||||
RepeatMode: t.RepeatMode,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -128,10 +128,6 @@ const (
|
|||
FilesBasePath Key = `files.basepath`
|
||||
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`
|
||||
MigrationTodoistClientID Key = `migration.todoist.clientid`
|
||||
MigrationTodoistClientSecret Key = `migration.todoist.clientsecret`
|
||||
|
@ -369,7 +365,6 @@ func InitDefaultConfig() {
|
|||
CorsOrigins.setDefault([]string{"*"})
|
||||
CorsMaxAge.setDefault(0)
|
||||
// Migration
|
||||
MigrationWunderlistEnable.setDefault(false)
|
||||
MigrationTodoistEnable.setDefault(false)
|
||||
MigrationTrelloEnable.setDefault(false)
|
||||
MigrationMicrosoftTodoEnable.setDefault(false)
|
||||
|
|
|
@ -18,6 +18,7 @@ package db
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
|
||||
|
@ -53,7 +54,35 @@ func Restore(table string, contents []map[string]interface{}) (err error) {
|
|||
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 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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -337,6 +337,7 @@
|
|||
bucket_id: 20
|
||||
created: 2018-12-01 01:12:04
|
||||
updated: 2018-12-01 01:12:04
|
||||
due_date: 2018-10-30 22:25:24
|
||||
- id: 37
|
||||
title: 'task #37'
|
||||
done: false
|
||||
|
|
|
@ -156,7 +156,7 @@ func GetListsByNamespaceID(s *xorm.Session, nID int64, doer *user.User) (lists [
|
|||
Alias("l").
|
||||
Join("LEFT", []string{"namespaces", "n"}, "l.namespace_id = n.id").
|
||||
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).
|
||||
Find(&lists)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,9 @@ func getUndoneOverdueTasks(s *xorm.Session, now time.Time) (usersWithTasks map[i
|
|||
|
||||
var tasks []*Task
|
||||
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").
|
||||
Find(&tasks)
|
||||
if err != nil {
|
||||
|
@ -138,9 +140,13 @@ func RegisterOverdueReminderCron() {
|
|||
}
|
||||
|
||||
if len(ut.tasks) == 1 {
|
||||
n = &UndoneTaskOverdueNotification{
|
||||
User: ut.user,
|
||||
Task: ut.tasks[0],
|
||||
// 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{
|
||||
User: ut.user,
|
||||
Task: t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
bucket, err = getDefaultBucket(s, task.ListID)
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -1369,7 +1374,7 @@ func setTaskDatesFromCurrentDateRepeat(oldTask, newTask *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.
|
||||
// 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
|
||||
// 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) {
|
||||
|
|
|
@ -51,6 +51,7 @@ type Provider struct {
|
|||
Key string `json:"key"`
|
||||
OriginalAuthURL string `json:"-"`
|
||||
AuthURL string `json:"auth_url"`
|
||||
LogoutURL string `json:"logout_url"`
|
||||
ClientID string `json:"client_id"`
|
||||
ClientSecret string `json:"-"`
|
||||
openIDProvider *oidc.Provider
|
||||
|
|
|
@ -60,6 +60,7 @@ func GetAllProviders() (providers []*Provider, err error) {
|
|||
}
|
||||
|
||||
provider, err := getProviderFromMap(pi)
|
||||
|
||||
if err != nil {
|
||||
if provider != nil {
|
||||
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)
|
||||
|
||||
logoutURL, ok := pi["logouturl"].(string)
|
||||
if !ok {
|
||||
logoutURL = ""
|
||||
}
|
||||
|
||||
provider = &Provider{
|
||||
Name: pi["name"].(string),
|
||||
Key: k,
|
||||
AuthURL: pi["authurl"].(string),
|
||||
OriginalAuthURL: pi["authurl"].(string),
|
||||
ClientSecret: pi["clientsecret"].(string),
|
||||
LogoutURL: logoutURL,
|
||||
}
|
||||
|
||||
cl, is := pi["clientid"].(int)
|
||||
|
@ -143,7 +150,6 @@ func getProviderFromMap(pi map[string]interface{}) (provider *Provider, err erro
|
|||
ClientID: provider.ClientID,
|
||||
ClientSecret: provider.ClientSecret,
|
||||
RedirectURL: config.AuthOpenIDRedirectURL.GetString() + k,
|
||||
|
||||
// Discovery returns the OAuth2 endpoints.
|
||||
Endpoint: provider.openIDProvider.Endpoint(),
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import (
|
|||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"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.
|
||||
if table == "notifications" {
|
||||
for i := range content {
|
||||
decoded, err := base64.StdEncoding.DecodeString(content[i]["notification"].(string))
|
||||
if err != nil {
|
||||
var decoded []byte
|
||||
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)
|
||||
}
|
||||
|
||||
if err != nil && errors.Is(err, base64.CorruptInputError(0)) {
|
||||
decoded = []byte(content[i]["notification"].(string))
|
||||
}
|
||||
|
||||
content[i]["notification"] = string(decoded)
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
@ -45,28 +45,25 @@ type apiTokenResponse struct {
|
|||
}
|
||||
|
||||
type label struct {
|
||||
ID int64 `json:"id"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Color int64 `json:"color"`
|
||||
Color string `json:"color"`
|
||||
ItemOrder int64 `json:"item_order"`
|
||||
IsDeleted int64 `json:"is_deleted"`
|
||||
IsFavorite int64 `json:"is_favorite"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
}
|
||||
|
||||
type project struct {
|
||||
ID int64 `json:"id"`
|
||||
LegacyID int64 `json:"legacy_id"`
|
||||
Name string `json:"name"`
|
||||
Color int64 `json:"color"`
|
||||
ParentID int64 `json:"parent_id"`
|
||||
ChildOrder int64 `json:"child_order"`
|
||||
Collapsed int64 `json:"collapsed"`
|
||||
Shared bool `json:"shared"`
|
||||
LegacyParentID int64 `json:"legacy_parent_id"`
|
||||
SyncID int64 `json:"sync_id"`
|
||||
IsDeleted int64 `json:"is_deleted"`
|
||||
IsArchived int64 `json:"is_archived"`
|
||||
IsFavorite int64 `json:"is_favorite"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Color string `json:"color"`
|
||||
ParentID string `json:"parent_id"`
|
||||
ChildOrder int64 `json:"child_order"`
|
||||
Collapsed bool `json:"collapsed"`
|
||||
Shared bool `json:"shared"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
IsArchived bool `json:"is_archived"`
|
||||
IsFavorite bool `json:"is_favorite"`
|
||||
}
|
||||
|
||||
type dueDate struct {
|
||||
|
@ -78,31 +75,26 @@ type dueDate struct {
|
|||
}
|
||||
|
||||
type item struct {
|
||||
ID int64 `json:"id"`
|
||||
LegacyID int64 `json:"legacy_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
LegacyProjectID int64 `json:"legacy_project_id"`
|
||||
Content string `json:"content"`
|
||||
Priority int64 `json:"priority"`
|
||||
Due *dueDate `json:"due"`
|
||||
ParentID int64 `json:"parent_id"`
|
||||
LegacyParentID int64 `json:"legacy_parent_id"`
|
||||
ChildOrder int64 `json:"child_order"`
|
||||
SectionID int64 `json:"section_id"`
|
||||
DayOrder int64 `json:"day_order"`
|
||||
Collapsed int64 `json:"collapsed"`
|
||||
Children interface{} `json:"children"`
|
||||
Labels []int64 `json:"labels"`
|
||||
AddedByUID int64 `json:"added_by_uid"`
|
||||
AssignedByUID int64 `json:"assigned_by_uid"`
|
||||
ResponsibleUID int64 `json:"responsible_uid"`
|
||||
Checked int64 `json:"checked"`
|
||||
InHistory int64 `json:"in_history"`
|
||||
IsDeleted int64 `json:"is_deleted"`
|
||||
DateAdded time.Time `json:"date_added"`
|
||||
HasMoreNotes bool `json:"has_more_notes"`
|
||||
DateCompleted time.Time `json:"date_completed"`
|
||||
ID string `json:"id"`
|
||||
LegacyID string `json:"legacy_id"`
|
||||
UserID string `json:"user_id"`
|
||||
ProjectID string `json:"project_id"`
|
||||
Content string `json:"content"`
|
||||
Priority int64 `json:"priority"`
|
||||
Due *dueDate `json:"due"`
|
||||
ParentID string `json:"parent_id"`
|
||||
ChildOrder int64 `json:"child_order"`
|
||||
SectionID string `json:"section_id"`
|
||||
Children interface{} `json:"children"`
|
||||
Labels []string `json:"labels"`
|
||||
AddedByUID string `json:"added_by_uid"`
|
||||
AssignedByUID string `json:"assigned_by_uid"`
|
||||
ResponsibleUID string `json:"responsible_uid"`
|
||||
Checked bool `json:"checked"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
DateAdded time.Time `json:"added_at"`
|
||||
HasMoreNotes bool `json:"has_more_notes"`
|
||||
DateCompleted time.Time `json:"completed_at"`
|
||||
}
|
||||
|
||||
type itemWrapper struct {
|
||||
|
@ -110,12 +102,11 @@ type itemWrapper struct {
|
|||
}
|
||||
|
||||
type doneItem struct {
|
||||
CompletedDate time.Time `json:"completed_date"`
|
||||
CompletedDate time.Time `json:"completed_at"`
|
||||
Content string `json:"content"`
|
||||
ID int64 `json:"id"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
TaskID int64 `json:"task_id"`
|
||||
UserID int `json:"user_id"`
|
||||
ID string `json:"id"`
|
||||
ProjectID string `json:"project_id"`
|
||||
TaskID string `json:"task_id"`
|
||||
}
|
||||
|
||||
type doneItemSync struct {
|
||||
|
@ -132,18 +123,14 @@ type fileAttachment struct {
|
|||
}
|
||||
|
||||
type note struct {
|
||||
ID int64 `json:"id"`
|
||||
LegacyID int64 `json:"legacy_id"`
|
||||
PostedUID int64 `json:"posted_uid"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
LegacyProjectID int64 `json:"legacy_project_id"`
|
||||
ItemID int64 `json:"item_id"`
|
||||
LegacyItemID int64 `json:"legacy_item_id"`
|
||||
Content string `json:"content"`
|
||||
FileAttachment *fileAttachment `json:"file_attachment"`
|
||||
UidsToNotify []int64 `json:"uids_to_notify"`
|
||||
IsDeleted int64 `json:"is_deleted"`
|
||||
Posted time.Time `json:"posted"`
|
||||
ID string `json:"id"`
|
||||
PostedUID int64 `json:"posted_uid"`
|
||||
ProjectID string `json:"project_id"`
|
||||
ItemID string `json:"item_id"`
|
||||
Content string `json:"content"`
|
||||
FileAttachment *fileAttachment `json:"file_attachment"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
Posted time.Time `json:"posted_at"`
|
||||
}
|
||||
|
||||
type projectNote struct {
|
||||
|
@ -153,15 +140,13 @@ type projectNote struct {
|
|||
IsDeleted int64 `json:"is_deleted"`
|
||||
Posted time.Time `json:"posted"`
|
||||
PostedUID int64 `json:"posted_uid"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
ProjectID string `json:"project_id"`
|
||||
UidsToNotify []int64 `json:"uids_to_notify"`
|
||||
}
|
||||
|
||||
type reminder struct {
|
||||
ID int64 `json:"id"`
|
||||
NotifyUID int64 `json:"notify_uid"`
|
||||
ItemID int64 `json:"item_id"`
|
||||
Service string `json:"service"`
|
||||
ID string `json:"id"`
|
||||
ItemID string `json:"item_id"`
|
||||
Type string `json:"type"`
|
||||
Due *dueDate `json:"due"`
|
||||
MmOffset int64 `json:"mm_offset"`
|
||||
|
@ -169,11 +154,11 @@ type reminder struct {
|
|||
}
|
||||
|
||||
type section struct {
|
||||
ID int64 `json:"id"`
|
||||
DateAdded time.Time `json:"date_added"`
|
||||
ID string `json:"id"`
|
||||
DateAdded time.Time `json:"added_at"`
|
||||
IsDeleted bool `json:"is_deleted"`
|
||||
Name string `json:"name"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
ProjectID string `json:"project_id"`
|
||||
SectionOrder int64 `json:"section_order"`
|
||||
}
|
||||
|
||||
|
@ -187,32 +172,32 @@ type sync struct {
|
|||
Sections []*section `json:"sections"`
|
||||
}
|
||||
|
||||
var todoistColors = map[int64]string{}
|
||||
var todoistColors = map[string]string{}
|
||||
|
||||
func init() {
|
||||
todoistColors = make(map[int64]string, 19)
|
||||
// The todoists colors are static, taken from https://developer.todoist.com/sync/v8/#colors
|
||||
todoistColors = map[int64]string{
|
||||
30: "b8256f",
|
||||
31: "db4035",
|
||||
32: "ff9933",
|
||||
33: "fad000",
|
||||
34: "afb83b",
|
||||
35: "7ecc49",
|
||||
36: "299438",
|
||||
37: "6accbc",
|
||||
38: "158fad",
|
||||
39: "14aaf5",
|
||||
40: "96c3eb",
|
||||
41: "4073ff",
|
||||
42: "884dff",
|
||||
43: "af38eb",
|
||||
44: "eb96eb",
|
||||
45: "e05194",
|
||||
46: "ff8d85",
|
||||
47: "808080",
|
||||
48: "b8b8b8",
|
||||
49: "ccac93",
|
||||
todoistColors = make(map[string]string, 19)
|
||||
// The todoists colors are static, taken from https://developer.todoist.com/guides/#colors
|
||||
todoistColors = map[string]string{
|
||||
"berry_red": "b8256f",
|
||||
"red": "db4035",
|
||||
"orange": "ff9933",
|
||||
"yellow": "fad000",
|
||||
"olive_green": "afb83b",
|
||||
"lime_green": "7ecc49",
|
||||
"green": "299438",
|
||||
"mint_green": "6accbc",
|
||||
"teal": "158fad",
|
||||
"sky_blue": "14aaf5",
|
||||
"light_blue": "96c3eb",
|
||||
"blue": "4073ff",
|
||||
"grape": "884dff",
|
||||
"violet": "af38eb",
|
||||
"lavender": "eb96eb",
|
||||
"magenta": "e05194",
|
||||
"salmon": "ff8d85",
|
||||
"charcoal": "808080",
|
||||
"grey": "b8b8b8",
|
||||
"taupe": "ccac93",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,7 +251,7 @@ func parseDate(dateString string) (date time.Time, err error) {
|
|||
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{
|
||||
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
|
||||
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
|
||||
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
|
||||
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 {
|
||||
list := &models.ListWithTasksAndBuckets{
|
||||
List: models.List{
|
||||
Title: p.Name,
|
||||
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
|
||||
})
|
||||
|
||||
var fabricatedSectionID int64 = 1
|
||||
for _, section := range sync.Sections {
|
||||
if section.IsDeleted || section.ProjectID == 0 {
|
||||
if section.IsDeleted || section.ProjectID == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
lists[section.ProjectID].Buckets = append(lists[section.ProjectID].Buckets, &models.Bucket{
|
||||
ID: section.ID,
|
||||
ID: fabricatedSectionID,
|
||||
Title: section.Name,
|
||||
Created: section.DateAdded,
|
||||
})
|
||||
sections[section.ID] = fabricatedSectionID
|
||||
}
|
||||
|
||||
for _, label := range sync.Labels {
|
||||
labels[label.ID] = &models.Label{
|
||||
labels[label.Name] = &models.Label{
|
||||
Title: label.Name,
|
||||
HexColor: todoistColors[label.Color],
|
||||
}
|
||||
|
@ -325,8 +314,8 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||
Task: models.Task{
|
||||
Title: i.Content,
|
||||
Created: i.DateAdded.In(config.GetTimeZone()),
|
||||
Done: i.Checked == 1,
|
||||
BucketID: i.SectionID,
|
||||
Done: i.Checked,
|
||||
BucketID: sections[i.SectionID],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -357,29 +346,31 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||
}
|
||||
|
||||
// Put all labels together from earlier
|
||||
for _, lID := range i.Labels {
|
||||
task.Labels = append(task.Labels, labels[lID])
|
||||
for _, lName := range i.Labels {
|
||||
task.Labels = append(task.Labels, labels[lName])
|
||||
}
|
||||
|
||||
tasks[i.ID] = task
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
lists[i.ProjectID].Tasks = append(lists[i.ProjectID].Tasks, task)
|
||||
|
||||
fabricatedSectionID++
|
||||
}
|
||||
|
||||
// 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
|
||||
for _, i := range sync.Items {
|
||||
if i.ParentID == 0 {
|
||||
if i.ParentID == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -407,7 +398,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||
// FIXME: Should be comments
|
||||
for _, n := range sync.Notes {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -460,7 +451,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[int64]*doneItem) (fullVik
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -537,7 +528,7 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||
"sync_token": []string{"*"},
|
||||
"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 {
|
||||
return
|
||||
}
|
||||
|
@ -553,10 +544,10 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||
|
||||
// Get all done tasks and projects
|
||||
offset := 0
|
||||
doneItems := make(map[int64]*doneItem)
|
||||
doneItems := make(map[string]*doneItem)
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -580,9 +571,9 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||
doneItems[i.TaskID] = i
|
||||
|
||||
// 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},
|
||||
"item_id": []string{strconv.FormatInt(i.TaskID, 10)},
|
||||
"item_id": []string{i.TaskID},
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -594,7 +585,7 @@ func (m *Migration) Migrate(u *user.User) (err error) {
|
|||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
// 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 {
|
||||
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)
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package todoist
|
|||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -47,33 +46,32 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
dueTimeWithTime = dueTimeWithTime.In(config.GetTimeZone())
|
||||
nilTime, err := time.Parse(time.RFC3339Nano, "0001-01-01T00:00:00Z")
|
||||
assert.NoError(t, err)
|
||||
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg")
|
||||
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/testimage.jpg")
|
||||
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{
|
||||
ID: id,
|
||||
UserID: 1855589,
|
||||
UserID: "1855589",
|
||||
ProjectID: projectId,
|
||||
Content: "Task" + strconv.FormatInt(id, 10),
|
||||
Content: "Task" + id,
|
||||
Priority: 1,
|
||||
ParentID: 0,
|
||||
ChildOrder: 1,
|
||||
DateAdded: time1,
|
||||
DateCompleted: nilTime,
|
||||
}
|
||||
|
||||
if done {
|
||||
item.Checked = 1
|
||||
item.Checked = true
|
||||
item.DateCompleted = time3
|
||||
}
|
||||
|
||||
if hasLabels {
|
||||
item.Labels = []int64{
|
||||
80000,
|
||||
80001,
|
||||
80002,
|
||||
80003,
|
||||
item.Labels = []string{
|
||||
"Label1",
|
||||
"Label2",
|
||||
"Label3",
|
||||
"Label4",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,163 +89,163 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
testSync := &sync{
|
||||
Projects: []*project{
|
||||
{
|
||||
ID: 396936926,
|
||||
ID: "396936926",
|
||||
Name: "Project1",
|
||||
Color: 30,
|
||||
Color: "berry_red",
|
||||
ChildOrder: 1,
|
||||
Collapsed: 0,
|
||||
Collapsed: false,
|
||||
Shared: false,
|
||||
IsDeleted: 0,
|
||||
IsArchived: 0,
|
||||
IsFavorite: 0,
|
||||
IsDeleted: false,
|
||||
IsArchived: false,
|
||||
IsFavorite: false,
|
||||
},
|
||||
{
|
||||
ID: 396936927,
|
||||
ID: "396936927",
|
||||
Name: "Project2",
|
||||
Color: 37,
|
||||
Color: "mint_green",
|
||||
ChildOrder: 1,
|
||||
Collapsed: 0,
|
||||
Collapsed: false,
|
||||
Shared: false,
|
||||
IsDeleted: 0,
|
||||
IsArchived: 0,
|
||||
IsFavorite: 0,
|
||||
IsDeleted: false,
|
||||
IsArchived: false,
|
||||
IsFavorite: false,
|
||||
},
|
||||
{
|
||||
ID: 396936928,
|
||||
ID: "396936928",
|
||||
Name: "Project3 - Archived",
|
||||
Color: 37,
|
||||
Color: "mint_green",
|
||||
ChildOrder: 1,
|
||||
Collapsed: 0,
|
||||
Collapsed: false,
|
||||
Shared: false,
|
||||
IsDeleted: 0,
|
||||
IsArchived: 1,
|
||||
IsFavorite: 0,
|
||||
IsDeleted: false,
|
||||
IsArchived: true,
|
||||
IsFavorite: false,
|
||||
},
|
||||
},
|
||||
Items: []*item{
|
||||
makeTestItem(400000000, 396936926, false, false, false),
|
||||
makeTestItem(400000001, 396936926, false, false, false),
|
||||
makeTestItem(400000002, 396936926, false, false, false),
|
||||
makeTestItem(400000003, 396936926, true, true, true),
|
||||
makeTestItem(400000004, 396936926, false, true, false),
|
||||
makeTestItem(400000005, 396936926, true, false, true),
|
||||
makeTestItem(400000006, 396936926, true, false, true),
|
||||
makeTestItem("400000000", "396936926", false, false, false),
|
||||
makeTestItem("400000001", "396936926", false, false, false),
|
||||
makeTestItem("400000002", "396936926", false, false, false),
|
||||
makeTestItem("400000003", "396936926", true, true, true),
|
||||
makeTestItem("400000004", "396936926", false, true, false),
|
||||
makeTestItem("400000005", "396936926", true, false, true),
|
||||
makeTestItem("400000006", "396936926", true, false, true),
|
||||
{
|
||||
ID: 400000110,
|
||||
UserID: 1855589,
|
||||
ProjectID: 396936926,
|
||||
ID: "400000110",
|
||||
UserID: "1855589",
|
||||
ProjectID: "396936926",
|
||||
Content: "Task with parent",
|
||||
Priority: 2,
|
||||
ParentID: 400000006,
|
||||
ParentID: "400000006",
|
||||
ChildOrder: 1,
|
||||
Checked: 0,
|
||||
Checked: false,
|
||||
DateAdded: time1,
|
||||
},
|
||||
{
|
||||
ID: 400000106,
|
||||
UserID: 1855589,
|
||||
ProjectID: 396936926,
|
||||
ID: "400000106",
|
||||
UserID: "1855589",
|
||||
ProjectID: "396936926",
|
||||
Content: "Task400000106",
|
||||
Priority: 1,
|
||||
ParentID: 0,
|
||||
ParentID: "",
|
||||
ChildOrder: 1,
|
||||
DateAdded: time1,
|
||||
Checked: 1,
|
||||
Checked: true,
|
||||
DateCompleted: time3,
|
||||
Due: &dueDate{
|
||||
Date: "2021-01-31T19:00:00Z",
|
||||
Timezone: nil,
|
||||
IsRecurring: false,
|
||||
},
|
||||
Labels: []int64{
|
||||
80000,
|
||||
80001,
|
||||
80002,
|
||||
80003,
|
||||
Labels: []string{
|
||||
"Label1",
|
||||
"Label2",
|
||||
"Label3",
|
||||
"Label4",
|
||||
},
|
||||
},
|
||||
makeTestItem(400000107, 396936926, false, false, true),
|
||||
makeTestItem(400000108, 396936926, false, false, true),
|
||||
makeTestItem("400000107", "396936926", false, false, true),
|
||||
makeTestItem("400000108", "396936926", false, false, true),
|
||||
{
|
||||
ID: 400000109,
|
||||
UserID: 1855589,
|
||||
ProjectID: 396936926,
|
||||
ID: "400000109",
|
||||
UserID: "1855589",
|
||||
ProjectID: "396936926",
|
||||
Content: "Task400000109",
|
||||
Priority: 1,
|
||||
ChildOrder: 1,
|
||||
Checked: 1,
|
||||
Checked: true,
|
||||
DateAdded: time1,
|
||||
DateCompleted: time3,
|
||||
SectionID: 1234,
|
||||
SectionID: "1234",
|
||||
},
|
||||
|
||||
makeTestItem(400000007, 396936927, true, false, false),
|
||||
makeTestItem(400000008, 396936927, true, false, false),
|
||||
makeTestItem(400000009, 396936927, false, false, false),
|
||||
makeTestItem(400000010, 396936927, false, false, true),
|
||||
makeTestItem(400000101, 396936927, false, false, false),
|
||||
makeTestItem(400000102, 396936927, true, true, false),
|
||||
makeTestItem(400000103, 396936927, false, true, false),
|
||||
makeTestItem(400000104, 396936927, false, true, false),
|
||||
makeTestItem(400000105, 396936927, true, true, false),
|
||||
makeTestItem("400000007", "396936927", true, false, false),
|
||||
makeTestItem("400000008", "396936927", true, false, false),
|
||||
makeTestItem("400000009", "396936927", false, false, false),
|
||||
makeTestItem("400000010", "396936927", false, false, true),
|
||||
makeTestItem("400000101", "396936927", false, false, false),
|
||||
makeTestItem("400000102", "396936927", true, true, false),
|
||||
makeTestItem("400000103", "396936927", false, true, false),
|
||||
makeTestItem("400000104", "396936927", false, true, false),
|
||||
makeTestItem("400000105", "396936927", true, true, false),
|
||||
|
||||
makeTestItem(400000111, 396936928, false, false, true),
|
||||
makeTestItem("400000111", "396936928", false, false, true),
|
||||
},
|
||||
Labels: []*label{
|
||||
{
|
||||
ID: 80000,
|
||||
ID: "80000",
|
||||
Name: "Label1",
|
||||
Color: 30,
|
||||
Color: "berry_red",
|
||||
},
|
||||
{
|
||||
ID: 80001,
|
||||
ID: "80001",
|
||||
Name: "Label2",
|
||||
Color: 31,
|
||||
Color: "red",
|
||||
},
|
||||
{
|
||||
ID: 80002,
|
||||
ID: "80002",
|
||||
Name: "Label3",
|
||||
Color: 32,
|
||||
Color: "orange",
|
||||
},
|
||||
{
|
||||
ID: 80003,
|
||||
ID: "80003",
|
||||
Name: "Label4",
|
||||
Color: 33,
|
||||
Color: "yellow",
|
||||
},
|
||||
},
|
||||
Notes: []*note{
|
||||
{
|
||||
ID: 101476,
|
||||
ID: "101476",
|
||||
PostedUID: 1855589,
|
||||
ItemID: 400000000,
|
||||
ItemID: "400000000",
|
||||
Content: "Lorem Ipsum dolor sit amet",
|
||||
Posted: time1,
|
||||
},
|
||||
{
|
||||
ID: 101477,
|
||||
ID: "101477",
|
||||
PostedUID: 1855589,
|
||||
ItemID: 400000001,
|
||||
ItemID: "400000001",
|
||||
Content: "Lorem Ipsum dolor sit amet",
|
||||
Posted: time1,
|
||||
},
|
||||
{
|
||||
ID: 101478,
|
||||
ID: "101478",
|
||||
PostedUID: 1855589,
|
||||
ItemID: 400000003,
|
||||
ItemID: "400000003",
|
||||
Content: "Lorem Ipsum dolor sit amet",
|
||||
Posted: time1,
|
||||
},
|
||||
{
|
||||
ID: 101479,
|
||||
ID: "101479",
|
||||
PostedUID: 1855589,
|
||||
ItemID: 400000010,
|
||||
ItemID: "400000010",
|
||||
Content: "Lorem Ipsum dolor sit amet",
|
||||
Posted: time1,
|
||||
},
|
||||
{
|
||||
ID: 101480,
|
||||
ID: "101480",
|
||||
PostedUID: 1855589,
|
||||
ItemID: 400000101,
|
||||
ItemID: "400000101",
|
||||
Content: "Lorem Ipsum dolor sit amet",
|
||||
FileAttachment: &fileAttachment{
|
||||
FileName: "file.md",
|
||||
|
@ -263,43 +261,43 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
{
|
||||
ID: 102000,
|
||||
Content: "Lorem Ipsum dolor sit amet",
|
||||
ProjectID: 396936926,
|
||||
ProjectID: "396936926",
|
||||
Posted: time3,
|
||||
PostedUID: 1855589,
|
||||
},
|
||||
{
|
||||
ID: 102001,
|
||||
Content: "Lorem Ipsum dolor sit amet 2",
|
||||
ProjectID: 396936926,
|
||||
ProjectID: "396936926",
|
||||
Posted: time3,
|
||||
PostedUID: 1855589,
|
||||
},
|
||||
{
|
||||
ID: 102002,
|
||||
Content: "Lorem Ipsum dolor sit amet 3",
|
||||
ProjectID: 396936926,
|
||||
ProjectID: "396936926",
|
||||
Posted: time3,
|
||||
PostedUID: 1855589,
|
||||
},
|
||||
{
|
||||
ID: 102003,
|
||||
Content: "Lorem Ipsum dolor sit amet 4",
|
||||
ProjectID: 396936927,
|
||||
ProjectID: "396936927",
|
||||
Posted: time3,
|
||||
PostedUID: 1855589,
|
||||
},
|
||||
{
|
||||
ID: 102004,
|
||||
Content: "Lorem Ipsum dolor sit amet 5",
|
||||
ProjectID: 396936927,
|
||||
ProjectID: "396936927",
|
||||
Posted: time3,
|
||||
PostedUID: 1855589,
|
||||
},
|
||||
},
|
||||
Reminders: []*reminder{
|
||||
{
|
||||
ID: 103000,
|
||||
ItemID: 400000000,
|
||||
ID: "103000",
|
||||
ItemID: "400000000",
|
||||
Due: &dueDate{
|
||||
Date: "2020-06-15",
|
||||
IsRecurring: false,
|
||||
|
@ -307,40 +305,40 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
MmOffset: 180,
|
||||
},
|
||||
{
|
||||
ID: 103001,
|
||||
ItemID: 400000000,
|
||||
ID: "103001",
|
||||
ItemID: "400000000",
|
||||
Due: &dueDate{
|
||||
Date: "2020-06-16T07:00:00",
|
||||
IsRecurring: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 103002,
|
||||
ItemID: 400000002,
|
||||
ID: "103002",
|
||||
ItemID: "400000002",
|
||||
Due: &dueDate{
|
||||
Date: "2020-07-15T07:00:00Z",
|
||||
IsRecurring: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 103003,
|
||||
ItemID: 400000003,
|
||||
ID: "103003",
|
||||
ItemID: "400000003",
|
||||
Due: &dueDate{
|
||||
Date: "2020-06-15T07:00:00",
|
||||
IsRecurring: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 103004,
|
||||
ItemID: 400000005,
|
||||
ID: "103004",
|
||||
ItemID: "400000005",
|
||||
Due: &dueDate{
|
||||
Date: "2020-06-15T07:00:00",
|
||||
IsRecurring: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 103006,
|
||||
ItemID: 400000009,
|
||||
ID: "103006",
|
||||
ItemID: "400000009",
|
||||
Due: &dueDate{
|
||||
Date: "2020-06-15T07:00:00",
|
||||
IsRecurring: false,
|
||||
|
@ -349,9 +347,9 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
},
|
||||
Sections: []*section{
|
||||
{
|
||||
ID: 1234,
|
||||
ID: "1234",
|
||||
Name: "Some Bucket",
|
||||
ProjectID: 396936926,
|
||||
ProjectID: "396936926",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -359,19 +357,19 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
vikunjaLabels := []*models.Label{
|
||||
{
|
||||
Title: "Label1",
|
||||
HexColor: todoistColors[30],
|
||||
HexColor: todoistColors["berry_red"],
|
||||
},
|
||||
{
|
||||
Title: "Label2",
|
||||
HexColor: todoistColors[31],
|
||||
HexColor: todoistColors["red"],
|
||||
},
|
||||
{
|
||||
Title: "Label3",
|
||||
HexColor: todoistColors[32],
|
||||
HexColor: todoistColors["orange"],
|
||||
},
|
||||
{
|
||||
Title: "Label4",
|
||||
HexColor: todoistColors[33],
|
||||
HexColor: todoistColors["yellow"],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -385,11 +383,11 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
List: models.List{
|
||||
Title: "Project1",
|
||||
Description: "Lorem Ipsum dolor sit amet\nLorem Ipsum dolor sit amet 2\nLorem Ipsum dolor sit amet 3",
|
||||
HexColor: todoistColors[30],
|
||||
HexColor: todoistColors["berry_red"],
|
||||
},
|
||||
Buckets: []*models.Bucket{
|
||||
{
|
||||
ID: 1234,
|
||||
ID: 1,
|
||||
Title: "Some Bucket",
|
||||
},
|
||||
},
|
||||
|
@ -510,7 +508,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
Done: true,
|
||||
Created: time1,
|
||||
DoneAt: time3,
|
||||
BucketID: 1234,
|
||||
BucketID: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -519,7 +517,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
List: models.List{
|
||||
Title: "Project2",
|
||||
Description: "Lorem Ipsum dolor sit amet 4\nLorem Ipsum dolor sit amet 5",
|
||||
HexColor: todoistColors[37],
|
||||
HexColor: todoistColors["mint_green"],
|
||||
},
|
||||
Tasks: []*models.TaskWithComments{
|
||||
{
|
||||
|
@ -616,7 +614,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
|
|||
{
|
||||
List: models.List{
|
||||
Title: "Project3 - Archived",
|
||||
HexColor: todoistColors[37],
|
||||
HexColor: todoistColors["mint_green"],
|
||||
IsArchived: true,
|
||||
},
|
||||
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)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, hierachie)
|
||||
|
|
|
@ -36,7 +36,7 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
|||
|
||||
time1, err := time.Parse(time.RFC3339Nano, "2014-09-26T08:25:05Z")
|
||||
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)
|
||||
|
||||
trelloData := []*trello.Board{
|
||||
|
|
|
@ -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", ¬es, 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"
|
||||
}
|
|
@ -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 ¬e{
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ import (
|
|||
"code.vikunja.io/api/pkg/modules/migration/todoist"
|
||||
"code.vikunja.io/api/pkg/modules/migration/trello"
|
||||
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"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
@ -121,10 +120,6 @@ func Info(c echo.Context) error {
|
|||
info.AuthInfo.OpenIDConnect.Providers = providers
|
||||
|
||||
// Migrators
|
||||
if config.MigrationWunderlistEnable.GetBool() {
|
||||
m := &wunderlist.Migration{}
|
||||
info.AvailableMigrators = append(info.AvailableMigrators, m.Name())
|
||||
}
|
||||
if config.MigrationTodoistEnable.GetBool() {
|
||||
m := &todoist.Migration{}
|
||||
info.AvailableMigrators = append(info.AvailableMigrators, m.Name())
|
||||
|
|
|
@ -48,7 +48,6 @@ package routes
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -70,7 +69,6 @@ import (
|
|||
"code.vikunja.io/api/pkg/modules/migration/todoist"
|
||||
"code.vikunja.io/api/pkg/modules/migration/trello"
|
||||
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"
|
||||
"code.vikunja.io/api/pkg/routes/caldav"
|
||||
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
|
||||
|
@ -80,7 +78,7 @@ import (
|
|||
|
||||
"github.com/getsentry/sentry-go"
|
||||
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/middleware"
|
||||
elog "github.com/labstack/gommon/log"
|
||||
|
@ -273,29 +271,8 @@ func registerAPIRoutes(a *echo.Group) {
|
|||
ur.POST("/shares/:share/auth", apiv1.AuthenticateLinkShare)
|
||||
}
|
||||
|
||||
// ===== Routes with Authetication =====
|
||||
// Authetification
|
||||
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
|
||||
},
|
||||
}))
|
||||
// ===== Routes with Authentication =====
|
||||
a.Use(echojwt.JWT([]byte(config.ServiceJWTSecret.GetString())))
|
||||
|
||||
// Rate limit
|
||||
setupRateLimit(a, config.RateLimitKind.GetString())
|
||||
|
@ -612,16 +589,6 @@ func registerAPIRoutes(a *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
|
||||
if config.MigrationTodoistEnable.GetBool() {
|
||||
todoistMigrationHandler := &migrationHandler.MigrationWeb{
|
||||
|
|
|
@ -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}": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -7727,36 +7620,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who initially created the bucket.",
|
||||
"$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"
|
||||
}
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "The unique, numeric id of this bucket.",
|
||||
|
@ -7775,24 +7643,10 @@ const docTemplate = `{
|
|||
"description": "The list this bucket belongs to.",
|
||||
"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": {
|
||||
"description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.",
|
||||
"type": "number"
|
||||
},
|
||||
"sort_by": {
|
||||
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"description": "All tasks which belong to this bucket.",
|
||||
"type": "array",
|
||||
|
@ -7808,9 +7662,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this bucket was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.BulkAssignees": {
|
||||
|
@ -7822,9 +7674,7 @@ const docTemplate = `{
|
|||
"items": {
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.BulkTask": {
|
||||
|
@ -7858,7 +7708,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who initially created the task.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The task description.",
|
||||
|
@ -7930,7 +7784,11 @@ const docTemplate = `{
|
|||
},
|
||||
"related_tasks": {
|
||||
"description": "All related tasks, grouped by their relation kind",
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reminder_dates": {
|
||||
"description": "An array of datetimes when the user wants to be reminded of the task.",
|
||||
|
@ -7945,7 +7803,11 @@ const docTemplate = `{
|
|||
},
|
||||
"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.",
|
||||
"type": "integer"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TaskRepeatMode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start_date": {
|
||||
"description": "When this task starts.",
|
||||
|
@ -7953,7 +7815,11 @@ const docTemplate = `{
|
|||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"task_ids": {
|
||||
"description": "A list of task ids to update",
|
||||
|
@ -7970,9 +7836,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this task was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.DatabaseNotifications": {
|
||||
|
@ -8000,9 +7864,7 @@ const docTemplate = `{
|
|||
"read_at": {
|
||||
"description": "When this notification is marked as read, this will be updated with the current timestamp.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Label": {
|
||||
|
@ -8014,7 +7876,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this label",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The label description.",
|
||||
|
@ -8038,9 +7904,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this label was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LabelTask": {
|
||||
|
@ -8053,9 +7917,7 @@ const docTemplate = `{
|
|||
"label_id": {
|
||||
"description": "The label id you want to associate with a task.",
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LabelTaskBulk": {
|
||||
|
@ -8067,9 +7929,7 @@ const docTemplate = `{
|
|||
"items": {
|
||||
"$ref": "#/definitions/models.Label"
|
||||
}
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LinkSharing": {
|
||||
|
@ -8097,26 +7957,36 @@ const docTemplate = `{
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"shared_by": {
|
||||
"description": "The user who shared this list",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sharing_type": {
|
||||
"description": "The kind of this link. 0 = undefined, 1 = without password, 2 = with password.",
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.SharingType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this share was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.List": {
|
||||
|
@ -8165,7 +8035,11 @@ const docTemplate = `{
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who created this list.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"position": {
|
||||
"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": {
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the list. You'll see this in the namespace overview.",
|
||||
|
@ -8184,9 +8062,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this list was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.ListDuplicate": {
|
||||
|
@ -8194,14 +8070,16 @@ const docTemplate = `{
|
|||
"properties": {
|
||||
"list": {
|
||||
"description": "The copied list",
|
||||
"$ref": "#/definitions/models.List"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.List"
|
||||
}
|
||||
]
|
||||
},
|
||||
"namespace_id": {
|
||||
"description": "The target namespace ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.ListUser": {
|
||||
|
@ -8217,9 +8095,13 @@ const docTemplate = `{
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
|
@ -8228,9 +8110,7 @@ const docTemplate = `{
|
|||
"user_id": {
|
||||
"description": "The username.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Message": {
|
||||
|
@ -8268,11 +8148,19 @@ const docTemplate = `{
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who owns this namespace",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The name of this namespace.",
|
||||
|
@ -8283,9 +8171,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this namespace was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.NamespaceUser": {
|
||||
|
@ -8301,9 +8187,13 @@ const docTemplate = `{
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
|
@ -8312,9 +8202,7 @@ const docTemplate = `{
|
|||
"user_id": {
|
||||
"description": "The username.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.NamespaceWithLists": {
|
||||
|
@ -8349,11 +8237,19 @@ const docTemplate = `{
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who owns this namespace",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The name of this namespace.",
|
||||
|
@ -8364,9 +8260,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this namespace was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8391,7 +8329,11 @@ const docTemplate = `{
|
|||
},
|
||||
"filters": {
|
||||
"description": "The actual filters this filter contains",
|
||||
"$ref": "#/definitions/models.TaskCollection"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TaskCollection"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "The unique numeric id of this saved filter",
|
||||
|
@ -8403,7 +8345,11 @@ const docTemplate = `{
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who owns this filter",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the filter.",
|
||||
|
@ -8414,11 +8360,22 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this filter was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.SharingType": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"SharingTypeUnknown",
|
||||
"SharingTypeWithoutPassword",
|
||||
"SharingTypeWithPassword"
|
||||
]
|
||||
},
|
||||
"models.Subscription": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8439,10 +8396,12 @@ const docTemplate = `{
|
|||
},
|
||||
"user": {
|
||||
"description": "The user who made this subscription",
|
||||
"$ref": "#/definitions/user.User"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Task": {
|
||||
|
@ -8476,7 +8435,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who initially created the task.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The task description.",
|
||||
|
@ -8548,7 +8511,11 @@ const docTemplate = `{
|
|||
},
|
||||
"related_tasks": {
|
||||
"description": "All related tasks, grouped by their relation kind",
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reminder_dates": {
|
||||
"description": "An array of datetimes when the user wants to be reminded of the task.",
|
||||
|
@ -8563,7 +8530,11 @@ const docTemplate = `{
|
|||
},
|
||||
"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.",
|
||||
"type": "integer"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TaskRepeatMode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start_date": {
|
||||
"description": "When this task starts.",
|
||||
|
@ -8571,7 +8542,11 @@ const docTemplate = `{
|
|||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The task text. This is what you'll see in the list.",
|
||||
|
@ -8581,9 +8556,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this task was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskAssginee": {
|
||||
|
@ -8594,9 +8567,7 @@ const docTemplate = `{
|
|||
},
|
||||
"user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskAttachment": {
|
||||
|
@ -8616,9 +8587,7 @@ const docTemplate = `{
|
|||
},
|
||||
"task_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskCollection": {
|
||||
|
@ -8666,9 +8635,7 @@ const docTemplate = `{
|
|||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskComment": {
|
||||
|
@ -8688,9 +8655,7 @@ const docTemplate = `{
|
|||
},
|
||||
"updated": {
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskRelation": {
|
||||
|
@ -8702,7 +8667,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this relation",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"other_task_id": {
|
||||
"description": "The ID of the other task, the task which is being related.",
|
||||
|
@ -8710,16 +8679,31 @@ const docTemplate = `{
|
|||
},
|
||||
"relation_kind": {
|
||||
"description": "The kind of the relation.",
|
||||
"type": "string"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.RelationKind"
|
||||
}
|
||||
]
|
||||
},
|
||||
"task_id": {
|
||||
"description": "The ID of the \"base\" task, the task which has a relation to another.",
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskRepeatMode": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"TaskRepeatModeDefault",
|
||||
"TaskRepeatModeMonth",
|
||||
"TaskRepeatModeFromCurrentDate"
|
||||
]
|
||||
},
|
||||
"models.Team": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8729,7 +8713,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this team.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The team's description.",
|
||||
|
@ -8755,9 +8743,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamList": {
|
||||
|
@ -8773,9 +8759,13 @@ const docTemplate = `{
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"team_id": {
|
||||
"description": "The team id.",
|
||||
|
@ -8784,9 +8774,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamMember": {
|
||||
|
@ -8807,9 +8795,7 @@ const docTemplate = `{
|
|||
"username": {
|
||||
"description": "The username of the member. We use this to prevent automated user id entering.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamNamespace": {
|
||||
|
@ -8825,9 +8811,13 @@ const docTemplate = `{
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"team_id": {
|
||||
"description": "The team id.",
|
||||
|
@ -8836,9 +8826,7 @@ const docTemplate = `{
|
|||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamUser": {
|
||||
|
@ -8874,8 +8862,7 @@ const docTemplate = `{
|
|||
"type": "string",
|
||||
"maxLength": 250,
|
||||
"minLength": 1
|
||||
},
|
||||
"web.Auth": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamWithRight": {
|
||||
|
@ -8887,7 +8874,11 @@ const docTemplate = `{
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this team.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The team's description.",
|
||||
|
@ -8911,16 +8902,12 @@ const docTemplate = `{
|
|||
"minLength": 1
|
||||
},
|
||||
"right": {
|
||||
"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
|
||||
"$ref": "#/definitions/models.Right"
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.UserWithRight": {
|
||||
|
@ -8944,9 +8931,7 @@ const docTemplate = `{
|
|||
"type": "string"
|
||||
},
|
||||
"right": {
|
||||
"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
|
||||
"$ref": "#/definitions/models.Right"
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this task was last updated. You cannot change this value.",
|
||||
|
@ -8957,8 +8942,7 @@ const docTemplate = `{
|
|||
"type": "string",
|
||||
"maxLength": 250,
|
||||
"minLength": 1
|
||||
},
|
||||
"web.Auth": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.DatabaseNotification": {
|
||||
|
@ -9008,6 +8992,9 @@ const docTemplate = `{
|
|||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"logout_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -9187,8 +9174,7 @@ const docTemplate = `{
|
|||
"type": "string",
|
||||
"maxLength": 250,
|
||||
"minLength": 1
|
||||
},
|
||||
"web.Auth": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.LinkShareAuth": {
|
||||
|
@ -9396,15 +9382,6 @@ const docTemplate = `{
|
|||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wunderlist.Migration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "Code is the code used to get a user api token",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
|
|
@ -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}": {
|
||||
"post": {
|
||||
"security": [
|
||||
|
@ -7718,36 +7611,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who initially created the bucket.",
|
||||
"$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"
|
||||
}
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "The unique, numeric id of this bucket.",
|
||||
|
@ -7766,24 +7634,10 @@
|
|||
"description": "The list this bucket belongs to.",
|
||||
"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": {
|
||||
"description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.",
|
||||
"type": "number"
|
||||
},
|
||||
"sort_by": {
|
||||
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"description": "All tasks which belong to this bucket.",
|
||||
"type": "array",
|
||||
|
@ -7799,9 +7653,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this bucket was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.BulkAssignees": {
|
||||
|
@ -7813,9 +7665,7 @@
|
|||
"items": {
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.BulkTask": {
|
||||
|
@ -7849,7 +7699,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who initially created the task.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The task description.",
|
||||
|
@ -7921,7 +7775,11 @@
|
|||
},
|
||||
"related_tasks": {
|
||||
"description": "All related tasks, grouped by their relation kind",
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reminder_dates": {
|
||||
"description": "An array of datetimes when the user wants to be reminded of the task.",
|
||||
|
@ -7936,7 +7794,11 @@
|
|||
},
|
||||
"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.",
|
||||
"type": "integer"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TaskRepeatMode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start_date": {
|
||||
"description": "When this task starts.",
|
||||
|
@ -7944,7 +7806,11 @@
|
|||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"task_ids": {
|
||||
"description": "A list of task ids to update",
|
||||
|
@ -7961,9 +7827,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this task was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.DatabaseNotifications": {
|
||||
|
@ -7991,9 +7855,7 @@
|
|||
"read_at": {
|
||||
"description": "When this notification is marked as read, this will be updated with the current timestamp.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Label": {
|
||||
|
@ -8005,7 +7867,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this label",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The label description.",
|
||||
|
@ -8029,9 +7895,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this label was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LabelTask": {
|
||||
|
@ -8044,9 +7908,7 @@
|
|||
"label_id": {
|
||||
"description": "The label id you want to associate with a task.",
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LabelTaskBulk": {
|
||||
|
@ -8058,9 +7920,7 @@
|
|||
"items": {
|
||||
"$ref": "#/definitions/models.Label"
|
||||
}
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LinkSharing": {
|
||||
|
@ -8088,26 +7948,36 @@
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"shared_by": {
|
||||
"description": "The user who shared this list",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sharing_type": {
|
||||
"description": "The kind of this link. 0 = undefined, 1 = without password, 2 = with password.",
|
||||
"type": "integer",
|
||||
"default": 0,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.SharingType"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this share was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.List": {
|
||||
|
@ -8156,7 +8026,11 @@
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who created this list.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"position": {
|
||||
"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": {
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the list. You'll see this in the namespace overview.",
|
||||
|
@ -8175,9 +8053,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this list was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.ListDuplicate": {
|
||||
|
@ -8185,14 +8061,16 @@
|
|||
"properties": {
|
||||
"list": {
|
||||
"description": "The copied list",
|
||||
"$ref": "#/definitions/models.List"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.List"
|
||||
}
|
||||
]
|
||||
},
|
||||
"namespace_id": {
|
||||
"description": "The target namespace ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.ListUser": {
|
||||
|
@ -8208,9 +8086,13 @@
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
|
@ -8219,9 +8101,7 @@
|
|||
"user_id": {
|
||||
"description": "The username.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Message": {
|
||||
|
@ -8259,11 +8139,19 @@
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who owns this namespace",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The name of this namespace.",
|
||||
|
@ -8274,9 +8162,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this namespace was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.NamespaceUser": {
|
||||
|
@ -8292,9 +8178,13 @@
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
|
@ -8303,9 +8193,7 @@
|
|||
"user_id": {
|
||||
"description": "The username.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.NamespaceWithLists": {
|
||||
|
@ -8340,11 +8228,19 @@
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who owns this namespace",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The name of this namespace.",
|
||||
|
@ -8355,9 +8251,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this namespace was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8382,7 +8320,11 @@
|
|||
},
|
||||
"filters": {
|
||||
"description": "The actual filters this filter contains",
|
||||
"$ref": "#/definitions/models.TaskCollection"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TaskCollection"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "The unique numeric id of this saved filter",
|
||||
|
@ -8394,7 +8336,11 @@
|
|||
},
|
||||
"owner": {
|
||||
"description": "The user who owns this filter",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the filter.",
|
||||
|
@ -8405,11 +8351,22 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this filter was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.SharingType": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"SharingTypeUnknown",
|
||||
"SharingTypeWithoutPassword",
|
||||
"SharingTypeWithPassword"
|
||||
]
|
||||
},
|
||||
"models.Subscription": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8430,10 +8387,12 @@
|
|||
},
|
||||
"user": {
|
||||
"description": "The user who made this subscription",
|
||||
"$ref": "#/definitions/user.User"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.Task": {
|
||||
|
@ -8467,7 +8426,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who initially created the task.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The task description.",
|
||||
|
@ -8539,7 +8502,11 @@
|
|||
},
|
||||
"related_tasks": {
|
||||
"description": "All related tasks, grouped by their relation kind",
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.RelatedTaskMap"
|
||||
}
|
||||
]
|
||||
},
|
||||
"reminder_dates": {
|
||||
"description": "An array of datetimes when the user wants to be reminded of the task.",
|
||||
|
@ -8554,7 +8521,11 @@
|
|||
},
|
||||
"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.",
|
||||
"type": "integer"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TaskRepeatMode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"start_date": {
|
||||
"description": "When this task starts.",
|
||||
|
@ -8562,7 +8533,11 @@
|
|||
},
|
||||
"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.",
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Subscription"
|
||||
}
|
||||
]
|
||||
},
|
||||
"title": {
|
||||
"description": "The task text. This is what you'll see in the list.",
|
||||
|
@ -8572,9 +8547,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this task was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskAssginee": {
|
||||
|
@ -8585,9 +8558,7 @@
|
|||
},
|
||||
"user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskAttachment": {
|
||||
|
@ -8607,9 +8578,7 @@
|
|||
},
|
||||
"task_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskCollection": {
|
||||
|
@ -8657,9 +8626,7 @@
|
|||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskComment": {
|
||||
|
@ -8679,9 +8646,7 @@
|
|||
},
|
||||
"updated": {
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskRelation": {
|
||||
|
@ -8693,7 +8658,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this relation",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"other_task_id": {
|
||||
"description": "The ID of the other task, the task which is being related.",
|
||||
|
@ -8701,16 +8670,31 @@
|
|||
},
|
||||
"relation_kind": {
|
||||
"description": "The kind of the relation.",
|
||||
"type": "string"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.RelationKind"
|
||||
}
|
||||
]
|
||||
},
|
||||
"task_id": {
|
||||
"description": "The ID of the \"base\" task, the task which has a relation to another.",
|
||||
"type": "integer"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TaskRepeatMode": {
|
||||
"type": "integer",
|
||||
"enum": [
|
||||
0,
|
||||
1,
|
||||
2
|
||||
],
|
||||
"x-enum-varnames": [
|
||||
"TaskRepeatModeDefault",
|
||||
"TaskRepeatModeMonth",
|
||||
"TaskRepeatModeFromCurrentDate"
|
||||
]
|
||||
},
|
||||
"models.Team": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
@ -8720,7 +8704,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this team.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The team's description.",
|
||||
|
@ -8746,9 +8734,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamList": {
|
||||
|
@ -8764,9 +8750,13 @@
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"team_id": {
|
||||
"description": "The team id.",
|
||||
|
@ -8775,9 +8765,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamMember": {
|
||||
|
@ -8798,9 +8786,7 @@
|
|||
"username": {
|
||||
"description": "The username of the member. We use this to prevent automated user id entering.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamNamespace": {
|
||||
|
@ -8816,9 +8802,13 @@
|
|||
},
|
||||
"right": {
|
||||
"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,
|
||||
"maximum": 2
|
||||
"maximum": 2,
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.Right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"team_id": {
|
||||
"description": "The team id.",
|
||||
|
@ -8827,9 +8817,7 @@
|
|||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamUser": {
|
||||
|
@ -8865,8 +8853,7 @@
|
|||
"type": "string",
|
||||
"maxLength": 250,
|
||||
"minLength": 1
|
||||
},
|
||||
"web.Auth": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.TeamWithRight": {
|
||||
|
@ -8878,7 +8865,11 @@
|
|||
},
|
||||
"created_by": {
|
||||
"description": "The user who created this team.",
|
||||
"$ref": "#/definitions/user.User"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/user.User"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"description": "The team's description.",
|
||||
|
@ -8902,16 +8893,12 @@
|
|||
"minLength": 1
|
||||
},
|
||||
"right": {
|
||||
"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
|
||||
"$ref": "#/definitions/models.Right"
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this relation was last updated. You cannot change this value.",
|
||||
"type": "string"
|
||||
},
|
||||
"web.CRUDable": {},
|
||||
"web.Rights": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.UserWithRight": {
|
||||
|
@ -8935,9 +8922,7 @@
|
|||
"type": "string"
|
||||
},
|
||||
"right": {
|
||||
"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
|
||||
"$ref": "#/definitions/models.Right"
|
||||
},
|
||||
"updated": {
|
||||
"description": "A timestamp when this task was last updated. You cannot change this value.",
|
||||
|
@ -8948,8 +8933,7 @@
|
|||
"type": "string",
|
||||
"maxLength": 250,
|
||||
"minLength": 1
|
||||
},
|
||||
"web.Auth": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.DatabaseNotification": {
|
||||
|
@ -8999,6 +8983,9 @@
|
|||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"logout_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -9178,8 +9165,7 @@
|
|||
"type": "string",
|
||||
"maxLength": 250,
|
||||
"minLength": 1
|
||||
},
|
||||
"web.Auth": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"v1.LinkShareAuth": {
|
||||
|
@ -9387,15 +9373,6 @@
|
|||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"wunderlist.Migration": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"description": "Code is the code used to get a user api token",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
|
|
@ -58,30 +58,9 @@ definitions:
|
|||
value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
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:
|
||||
description: The unique, numeric id of this bucket.
|
||||
type: integer
|
||||
|
@ -97,22 +76,10 @@ definitions:
|
|||
list_id:
|
||||
description: The list this bucket belongs to.
|
||||
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:
|
||||
description: The position this bucket has when querying all buckets. See the
|
||||
tasks.position property on how to use this.
|
||||
type: number
|
||||
sort_by:
|
||||
description: The query parameter to sort by. This is for ex. done, priority,
|
||||
etc.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
tasks:
|
||||
description: All tasks which belong to this bucket.
|
||||
items:
|
||||
|
@ -126,8 +93,6 @@ definitions:
|
|||
description: A timestamp when this bucket was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.BulkAssignees:
|
||||
properties:
|
||||
|
@ -136,8 +101,6 @@ definitions:
|
|||
items:
|
||||
$ref: '#/definitions/user.User'
|
||||
type: array
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.BulkTask:
|
||||
properties:
|
||||
|
@ -163,7 +126,8 @@ definitions:
|
|||
value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who initially created the task.
|
||||
description:
|
||||
description: The task description.
|
||||
|
@ -228,7 +192,8 @@ definitions:
|
|||
sort by this later.
|
||||
type: integer
|
||||
related_tasks:
|
||||
$ref: '#/definitions/models.RelatedTaskMap'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.RelatedTaskMap'
|
||||
description: All related tasks, grouped by their relation kind
|
||||
reminder_dates:
|
||||
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.
|
||||
type: integer
|
||||
repeat_mode:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.TaskRepeatMode'
|
||||
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
|
||||
start_date:
|
||||
description: When this task starts.
|
||||
type: string
|
||||
subscription:
|
||||
$ref: '#/definitions/models.Subscription'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Subscription'
|
||||
description: |-
|
||||
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.
|
||||
|
@ -268,8 +235,6 @@ definitions:
|
|||
description: A timestamp when this task was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.DatabaseNotifications:
|
||||
properties:
|
||||
|
@ -294,8 +259,6 @@ definitions:
|
|||
description: When this notification is marked as read, this will be updated
|
||||
with the current timestamp.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.Label:
|
||||
properties:
|
||||
|
@ -304,7 +267,8 @@ definitions:
|
|||
value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who created this label
|
||||
description:
|
||||
description: The label description.
|
||||
|
@ -326,8 +290,6 @@ definitions:
|
|||
description: A timestamp when this label was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.LabelTask:
|
||||
properties:
|
||||
|
@ -338,8 +300,6 @@ definitions:
|
|||
label_id:
|
||||
description: The label id you want to associate with a task.
|
||||
type: integer
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.LabelTaskBulk:
|
||||
properties:
|
||||
|
@ -348,8 +308,6 @@ definitions:
|
|||
items:
|
||||
$ref: '#/definitions/models.Label'
|
||||
type: array
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.LinkSharing:
|
||||
properties:
|
||||
|
@ -372,26 +330,27 @@ definitions:
|
|||
it after the link share has been created.
|
||||
type: string
|
||||
right:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Right'
|
||||
default: 0
|
||||
description: The right this list is shared with. 0 = Read only, 1 = Read &
|
||||
Write, 2 = Admin. See the docs for more details.
|
||||
maximum: 2
|
||||
type: integer
|
||||
shared_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who shared this list
|
||||
sharing_type:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.SharingType'
|
||||
default: 0
|
||||
description: The kind of this link. 0 = undefined, 1 = without password, 2
|
||||
= with password.
|
||||
maximum: 2
|
||||
type: integer
|
||||
updated:
|
||||
description: A timestamp when this share was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.List:
|
||||
properties:
|
||||
|
@ -433,14 +392,16 @@ definitions:
|
|||
namespace_id:
|
||||
type: integer
|
||||
owner:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who created this list.
|
||||
position:
|
||||
description: The position this list has when querying all lists. See the tasks.position
|
||||
property on how to use this.
|
||||
type: number
|
||||
subscription:
|
||||
$ref: '#/definitions/models.Subscription'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Subscription'
|
||||
description: |-
|
||||
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.
|
||||
|
@ -453,19 +414,16 @@ definitions:
|
|||
description: A timestamp when this list was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.ListDuplicate:
|
||||
properties:
|
||||
list:
|
||||
$ref: '#/definitions/models.List'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.List'
|
||||
description: The copied list
|
||||
namespace_id:
|
||||
description: The target namespace ID
|
||||
type: integer
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.ListUser:
|
||||
properties:
|
||||
|
@ -477,11 +435,12 @@ definitions:
|
|||
description: The unique, numeric id of this list <-> user relation.
|
||||
type: integer
|
||||
right:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Right'
|
||||
default: 0
|
||||
description: The right this user has. 0 = Read only, 1 = Read & Write, 2 =
|
||||
Admin. See the docs for more details.
|
||||
maximum: 2
|
||||
type: integer
|
||||
updated:
|
||||
description: A timestamp when this relation was last updated. You cannot change
|
||||
this value.
|
||||
|
@ -489,8 +448,6 @@ definitions:
|
|||
user_id:
|
||||
description: The username.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.Message:
|
||||
properties:
|
||||
|
@ -518,10 +475,12 @@ definitions:
|
|||
description: Whether or not a namespace is archived.
|
||||
type: boolean
|
||||
owner:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who owns this namespace
|
||||
subscription:
|
||||
$ref: '#/definitions/models.Subscription'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Subscription'
|
||||
description: |-
|
||||
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.
|
||||
|
@ -534,8 +493,6 @@ definitions:
|
|||
description: A timestamp when this namespace was last updated. You cannot
|
||||
change this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.NamespaceUser:
|
||||
properties:
|
||||
|
@ -547,11 +504,12 @@ definitions:
|
|||
description: The unique, numeric id of this namespace <-> user relation.
|
||||
type: integer
|
||||
right:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Right'
|
||||
default: 0
|
||||
description: The right this user has. 0 = Read only, 1 = Read & Write, 2 =
|
||||
Admin. See the docs for more details.
|
||||
maximum: 2
|
||||
type: integer
|
||||
updated:
|
||||
description: A timestamp when this relation was last updated. You cannot change
|
||||
this value.
|
||||
|
@ -559,8 +517,6 @@ definitions:
|
|||
user_id:
|
||||
description: The username.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.NamespaceWithLists:
|
||||
properties:
|
||||
|
@ -586,10 +542,12 @@ definitions:
|
|||
$ref: '#/definitions/models.List'
|
||||
type: array
|
||||
owner:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who owns this namespace
|
||||
subscription:
|
||||
$ref: '#/definitions/models.Subscription'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Subscription'
|
||||
description: |-
|
||||
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.
|
||||
|
@ -602,8 +560,6 @@ definitions:
|
|||
description: A timestamp when this namespace was last updated. You cannot
|
||||
change this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.RelatedTaskMap:
|
||||
additionalProperties:
|
||||
|
@ -611,6 +567,44 @@ definitions:
|
|||
$ref: '#/definitions/models.Task'
|
||||
type: array
|
||||
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:
|
||||
properties:
|
||||
created:
|
||||
|
@ -621,7 +615,8 @@ definitions:
|
|||
description: The description of the filter
|
||||
type: string
|
||||
filters:
|
||||
$ref: '#/definitions/models.TaskCollection'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.TaskCollection'
|
||||
description: The actual filters this filter contains
|
||||
id:
|
||||
description: The unique numeric id of this saved filter
|
||||
|
@ -631,7 +626,8 @@ definitions:
|
|||
a separate namespace together with favorite lists.
|
||||
type: boolean
|
||||
owner:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who owns this filter
|
||||
title:
|
||||
description: The title of the filter.
|
||||
|
@ -642,9 +638,17 @@ definitions:
|
|||
description: A timestamp when this filter was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.SharingType:
|
||||
enum:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
||||
type: integer
|
||||
x-enum-varnames:
|
||||
- SharingTypeUnknown
|
||||
- SharingTypeWithoutPassword
|
||||
- SharingTypeWithPassword
|
||||
models.Subscription:
|
||||
properties:
|
||||
created:
|
||||
|
@ -660,10 +664,9 @@ definitions:
|
|||
description: The numeric ID of the subscription
|
||||
type: integer
|
||||
user:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who made this subscription
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.Task:
|
||||
properties:
|
||||
|
@ -689,7 +692,8 @@ definitions:
|
|||
value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who initially created the task.
|
||||
description:
|
||||
description: The task description.
|
||||
|
@ -754,7 +758,8 @@ definitions:
|
|||
sort by this later.
|
||||
type: integer
|
||||
related_tasks:
|
||||
$ref: '#/definitions/models.RelatedTaskMap'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.RelatedTaskMap'
|
||||
description: All related tasks, grouped by their relation kind
|
||||
reminder_dates:
|
||||
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.
|
||||
type: integer
|
||||
repeat_mode:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.TaskRepeatMode'
|
||||
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
|
||||
start_date:
|
||||
description: When this task starts.
|
||||
type: string
|
||||
subscription:
|
||||
$ref: '#/definitions/models.Subscription'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Subscription'
|
||||
description: |-
|
||||
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.
|
||||
|
@ -789,8 +796,6 @@ definitions:
|
|||
description: A timestamp when this task was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TaskAssginee:
|
||||
properties:
|
||||
|
@ -798,8 +803,6 @@ definitions:
|
|||
type: string
|
||||
user_id:
|
||||
type: integer
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TaskAttachment:
|
||||
properties:
|
||||
|
@ -813,8 +816,6 @@ definitions:
|
|||
type: integer
|
||||
task_id:
|
||||
type: integer
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TaskCollection:
|
||||
properties:
|
||||
|
@ -852,8 +853,6 @@ definitions:
|
|||
items:
|
||||
type: string
|
||||
type: array
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TaskComment:
|
||||
properties:
|
||||
|
@ -867,8 +866,6 @@ definitions:
|
|||
type: integer
|
||||
updated:
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TaskRelation:
|
||||
properties:
|
||||
|
@ -877,20 +874,30 @@ definitions:
|
|||
value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who created this relation
|
||||
other_task_id:
|
||||
description: The ID of the other task, the task which is being related.
|
||||
type: integer
|
||||
relation_kind:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.RelationKind'
|
||||
description: The kind of the relation.
|
||||
type: string
|
||||
task_id:
|
||||
description: The ID of the "base" task, the task which has a relation to another.
|
||||
type: integer
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TaskRepeatMode:
|
||||
enum:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
||||
type: integer
|
||||
x-enum-varnames:
|
||||
- TaskRepeatModeDefault
|
||||
- TaskRepeatModeMonth
|
||||
- TaskRepeatModeFromCurrentDate
|
||||
models.Team:
|
||||
properties:
|
||||
created:
|
||||
|
@ -898,7 +905,8 @@ definitions:
|
|||
this value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who created this team.
|
||||
description:
|
||||
description: The team's description.
|
||||
|
@ -920,8 +928,6 @@ definitions:
|
|||
description: A timestamp when this relation was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TeamList:
|
||||
properties:
|
||||
|
@ -933,11 +939,12 @@ definitions:
|
|||
description: The unique, numeric id of this list <-> team relation.
|
||||
type: integer
|
||||
right:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Right'
|
||||
default: 0
|
||||
description: The right this team has. 0 = Read only, 1 = Read & Write, 2 =
|
||||
Admin. See the docs for more details.
|
||||
maximum: 2
|
||||
type: integer
|
||||
team_id:
|
||||
description: The team id.
|
||||
type: integer
|
||||
|
@ -945,8 +952,6 @@ definitions:
|
|||
description: A timestamp when this relation was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TeamMember:
|
||||
properties:
|
||||
|
@ -965,8 +970,6 @@ definitions:
|
|||
description: The username of the member. We use this to prevent automated
|
||||
user id entering.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TeamNamespace:
|
||||
properties:
|
||||
|
@ -978,11 +981,12 @@ definitions:
|
|||
description: The unique, numeric id of this namespace <-> team relation.
|
||||
type: integer
|
||||
right:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.Right'
|
||||
default: 0
|
||||
description: The right this team has. 0 = Read only, 1 = Read & Write, 2 =
|
||||
Admin. See the docs for more details.
|
||||
maximum: 2
|
||||
type: integer
|
||||
team_id:
|
||||
description: The team id.
|
||||
type: integer
|
||||
|
@ -990,8 +994,6 @@ definitions:
|
|||
description: A timestamp when this relation was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.TeamUser:
|
||||
properties:
|
||||
|
@ -1022,7 +1024,6 @@ definitions:
|
|||
maxLength: 250
|
||||
minLength: 1
|
||||
type: string
|
||||
web.Auth: {}
|
||||
type: object
|
||||
models.TeamWithRight:
|
||||
properties:
|
||||
|
@ -1031,7 +1032,8 @@ definitions:
|
|||
this value.
|
||||
type: string
|
||||
created_by:
|
||||
$ref: '#/definitions/user.User'
|
||||
allOf:
|
||||
- $ref: '#/definitions/user.User'
|
||||
description: The user who created this team.
|
||||
description:
|
||||
description: The team's description.
|
||||
|
@ -1050,16 +1052,11 @@ definitions:
|
|||
minLength: 1
|
||||
type: string
|
||||
right:
|
||||
default: 0
|
||||
description: The right this team has. 0 = Read only, 1 = Read & Write, 2 =
|
||||
Admin. See the docs for more details.
|
||||
type: integer
|
||||
$ref: '#/definitions/models.Right'
|
||||
updated:
|
||||
description: A timestamp when this relation was last updated. You cannot change
|
||||
this value.
|
||||
type: string
|
||||
web.CRUDable: {}
|
||||
web.Rights: {}
|
||||
type: object
|
||||
models.UserWithRight:
|
||||
properties:
|
||||
|
@ -1078,10 +1075,7 @@ definitions:
|
|||
description: The full name of the user.
|
||||
type: string
|
||||
right:
|
||||
default: 0
|
||||
description: The right this user has. 0 = Read only, 1 = Read & Write, 2 =
|
||||
Admin. See the docs for more details.
|
||||
type: integer
|
||||
$ref: '#/definitions/models.Right'
|
||||
updated:
|
||||
description: A timestamp when this task was last updated. You cannot change
|
||||
this value.
|
||||
|
@ -1091,7 +1085,6 @@ definitions:
|
|||
maxLength: 250
|
||||
minLength: 1
|
||||
type: string
|
||||
web.Auth: {}
|
||||
type: object
|
||||
notifications.DatabaseNotification:
|
||||
properties:
|
||||
|
@ -1127,6 +1120,8 @@ definitions:
|
|||
type: string
|
||||
key:
|
||||
type: string
|
||||
logout_url:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
|
@ -1258,7 +1253,6 @@ definitions:
|
|||
maxLength: 250
|
||||
minLength: 1
|
||||
type: string
|
||||
web.Auth: {}
|
||||
type: object
|
||||
v1.LinkShareAuth:
|
||||
properties:
|
||||
|
@ -1407,12 +1401,6 @@ definitions:
|
|||
message:
|
||||
type: string
|
||||
type: object
|
||||
wunderlist.Migration:
|
||||
properties:
|
||||
code:
|
||||
description: Code is the code used to get a user api token
|
||||
type: string
|
||||
type: object
|
||||
info:
|
||||
contact:
|
||||
email: hello@vikunja.io
|
||||
|
@ -3490,77 +3478,6 @@ paths:
|
|||
summary: Get migration status
|
||||
tags:
|
||||
- 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}:
|
||||
post:
|
||||
consumes:
|
||||
|
|
Loading…
Reference in New Issue