Compare commits

...

37 Commits

Author SHA1 Message Date
Dominik Pschenitschni ca3580766e fix(docs): old helm charts url (#1344)
Co-authored-by: Dominik Pschenitschni <mail@celement.de>
Reviewed-on: vikunja/api#1344
Co-authored-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
Co-committed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
2022-12-28 16:06:55 +00:00
renovate c6429c8b13 fix(deps): update module github.com/labstack/echo/v4 to v4.10.0 (#1343)
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1343
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-28 10:32:12 +00:00
renovate 304481cf28 fix(deps): update module github.com/wneessen/go-mail to v0.3.6 (#1342)
Reviewed-on: vikunja/api#1342
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-26 17:29:28 +00:00
kolaente 897a6e5d5c
fix(caldav): use const for repeat modes 2022-12-24 14:34:59 +01:00
kolaente 194b88e2eb
fix(tasks): don't reset the kanban bucket when updating a task and not providing one
Resolves https://github.com/go-vikunja/api/issues/56
2022-12-24 14:30:34 +01:00
kolaente c5327845ee
feat(caldav): add support for repeating tasks
Resolves https://github.com/go-vikunja/api/issues/57#issuecomment-1364373103
2022-12-24 12:19:51 +01:00
kolaente ea1d06bda6
fix(list): return lists for a namespace id even if that namespace is deleted
This fixes a problem where a namespace was deleted and its list were not.
Forum discussion: https://community.vikunja.io/t/list-deleted-but-tasks-showing-up-as-archived-and-overdue/1025
2022-12-23 17:48:21 +01:00
kolaente 0104aa504b
fix(ci): pin nfpm container version and binary location 2022-12-19 15:37:01 +01:00
kolaente 6a97a214a3
fix(migration): use Todoist v9 api to migrate tasks from them
Discussion: https://community.vikunja.io/t/importing-tasks-from-todoist/322/7
2022-12-18 20:38:58 +01:00
viehlieb a79b1de2d0 feat: provide logout url for openid providers (#1340)
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1340
Co-authored-by: viehlieb <pf@pragma-shift.net>
Co-committed-by: viehlieb <pf@pragma-shift.net>
2022-12-18 18:26:28 +00:00
renovate e9ce930230 fix(deps): update module github.com/swaggo/swag to v1.8.9 (#1327)
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1327
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-18 16:43:30 +00:00
renovate 6cb48e430e fix(deps): update module github.com/pquerna/otp to v1.4.0 (#1341)
Reviewed-on: vikunja/api#1341
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-14 07:21:11 +00:00
renovate a2c8426d02 fix(deps): update module golang.org/x/crypto to v0.4.0 (#1339)
Reviewed-on: vikunja/api#1339
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-07 13:16:10 +00:00
renovate 3be10ca4a2 fix(deps): update module github.com/getsentry/sentry-go to v0.16.0 (#1338)
Reviewed-on: vikunja/api#1338
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-07 12:15:16 +00:00
renovate ec297009d3 fix(deps): update module golang.org/x/oauth2 to v0.3.0 (#1337)
Reviewed-on: vikunja/api#1337
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 16:25:24 +00:00
renovate dbc30284f3 fix(deps): update module golang.org/x/oauth2 to v0.2.0 (#1316)
Reviewed-on: vikunja/api#1316
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 08:14:40 +00:00
renovate 879324dcd0 fix(deps): update module golang.org/x/image to v0.2.0 (#1335)
Reviewed-on: vikunja/api#1335
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 07:58:51 +00:00
renovate 3be6e93a05 fix(deps): update module golang.org/x/term to v0.3.0 (#1336)
Reviewed-on: vikunja/api#1336
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-06 07:58:21 +00:00
kolaente f93317bf5d
fix(caldav): add Z suffix to dates make it clear dates are in UTC 2022-12-04 21:01:04 +01:00
renovate 1cfdb085e5 fix(deps): update module golang.org/x/sys to v0.3.0 (#1333)
Reviewed-on: vikunja/api#1333
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-04 16:56:44 +00:00
kolaente 51cf8beaed
feat(release): use compressed binaries for package releases
vikunja/api#1330
2022-12-02 16:31:06 +01:00
kolaente b8c3b570a4
fix(restore): check if we're really dealing with a string 2022-12-02 14:49:32 +01:00
renovate 8ae062a095 fix(deps): update module github.com/go-sql-driver/mysql to v1.7.0 (#1332)
Reviewed-on: vikunja/api#1332
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-12-02 13:39:25 +00:00
kolaente 941d1e06c5
fix(build): downgrade xgo to 1.19.2 so that builds work again
See https://github.com/techknowlogick/xgo/issues/187
2022-12-01 19:00:48 +01:00
kolaente 1f2eb57602
fix(reminders): make sure an overdue reminder is sent when there is only one overdue task 2022-12-01 18:41:24 +01:00
kolaente 51911a8868
fix(reminders): overdue tasks join condition 2022-12-01 18:30:05 +01:00
kolaente 47aae115df
fix(tasks): don't include undone overdue tasks from archived lists or namespaces in notification mails
Resolves vikunja/api#1324
2022-12-01 18:07:30 +01:00
kolaente fbc4b91e0f
fix(dump): make sure null dates are properly set when restoring from a dump 2022-12-01 17:53:02 +01:00
kolaente 8c67be558f
fix: restore notifications table from dump when it already had the correct format 2022-12-01 17:33:00 +01:00
renovate e27cd9b336 fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.4.3 (#1328)
Reviewed-on: vikunja/api#1328
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-29 15:14:04 +00:00
renovate 23b01a1ff6 fix(deps): update github.com/arran4/golang-ical digest to 1093469 (#1326)
Reviewed-on: vikunja/api#1326
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-22 13:19:30 +00:00
renovate f47faf577a fix(deps): update module github.com/wneessen/go-mail to v0.3.5 (#1325)
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1325
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-21 11:56:19 +00:00
renovate 312525ebef fix(deps): update github.com/arran4/golang-ical digest to a677353 (#1323)
Reviewed-on: vikunja/api#1323
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-21 10:49:41 +00:00
renovate a17d2f4288 fix(deps): update module golang.org/x/crypto to v0.3.0 (#1321)
Reviewed-on: vikunja/api#1321
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-16 22:16:31 +00:00
kolaente 7e0aa20658
fix(docs): add docs about cli user delete 2022-11-15 14:53:58 +01:00
renovate c5a55e39bf fix(deps): update module github.com/spf13/afero to v1.9.3 (#1320)
Reviewed-on: vikunja/api#1320
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-11-14 20:55:13 +00:00
the-darkvoid 4d4ffe8b34 Added Google & Google Workspace to OpenId examples (#1319)
Reviewed-on: vikunja/api#1319
Co-authored-by: the-darkvoid <darkvoid@gmail.com>
Co-committed-by: the-darkvoid <darkvoid@gmail.com>
2022-11-14 11:41:45 +00:00
27 changed files with 1190 additions and 888 deletions

View File

@ -377,7 +377,7 @@ steps:
event: [ push, tag, pull_request ]
- name: before-static-build
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.19.2
pull: true
commands:
- export PATH=$PATH:$GOPATH/bin
@ -386,7 +386,7 @@ steps:
depends_on: [ fetch-tags, mage ]
- name: static-build-windows
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.19.2
pull: true
environment:
# This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why.
@ -399,7 +399,7 @@ steps:
depends_on: [ before-static-build ]
- name: static-build-linux
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.19.2
pull: true
environment:
# This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why.
@ -412,7 +412,7 @@ steps:
depends_on: [ before-static-build ]
- name: static-build-darwin
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.19.2
pull: true
environment:
# This path does not exist. However, when we set the gopath to /go, the build fails. Not sure why.
@ -435,7 +435,7 @@ steps:
- ./mage-static release:compress
- name: after-build-static
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.19.2
pull: true
depends_on:
- after-build-compress
@ -504,7 +504,7 @@ steps:
# Build os packages and push it to our bucket
- name: build-os-packages-unstable
image: goreleaser/nfpm
image: goreleaser/nfpm:v2.22.2
pull: true
commands:
- apk add git go
@ -517,10 +517,10 @@ steps:
- main
event:
- push
depends_on: [ static-build-linux ]
depends_on: [ after-build-compress ]
- name: build-os-packages-version
image: goreleaser/nfpm
image: goreleaser/nfpm:v2.22.2
pull: true
commands:
- apk add git go
@ -531,7 +531,7 @@ 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
@ -719,6 +719,6 @@ steps:
- failure
---
kind: signature
hmac: 768d54fc8433705fb63f754adf19536a16152a4046a040afdbcbb7df60614056
hmac: f3b261d9329113993cdf8ae785daee6f0b2c0ea38662d2714385d7a31f7e5b2f
...

View File

@ -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 && \

View File

@ -311,6 +311,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.

View File

@ -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)

View File

@ -43,3 +43,26 @@ scopes:
- email
- profile
```
## Google / Google Workspace
Vikunja Config:
```yaml
openid:
enabled: true
redirecturl: https://vikunja.mydomain.com/auth/openid/ <---- slash at the end is important
providers:
- name: Google
authurl: https://accounts.google.com
clientid: <google-oauth-client-id>
clientsecret: <google-oauth-client-secret>
```
Google config:
- Navigate to https://console.cloud.google.com/apis/credentials in the target project
- Create a new OAuth client ID
- Configure an authorized redirect URI of https://vikunja.mydomain.com/auth/openid/google
Note that there currently seems to be no way to stop creation of new users, even when enableregistration is false in the configuration. This means that this approach works well only with an "Internal Organization" app for Google Workspace, which limits the allowed users to organizational accounts only. External / public applications will potentially allow every Google user to register.

View File

@ -136,6 +136,21 @@ Flags:
* `-p`, `--password`: The password of the new user. You will be asked to enter it if not provided through the flag.
* `-u`, `--username`: The username of the new user.
#### `user delete`
Start the user deletion process.
If called without the `--now` flag, this command will only trigger an email to the user in order for them to confirm and start the deletion process (this is the same behavoir as if the user requested their deletion via the web interface).
With the flag the user is deleted **immediately**.
**USE WITH CAUTION.**
{{< highlight bash >}}
$ vikunja user delete <id> <flags>
{{< /highlight >}}
Flags:
* `-n`, `--now` If provided, deletes the user immediately instead of emailing them first.
#### `user list`
Shows a list of all users.

37
go.mod
View File

@ -21,7 +21,7 @@ require (
gitea.com/xorm/xorm-redis-cache v0.2.0
github.com/ThreeDotsLabs/watermill v1.1.1
github.com/adlio/trello v1.10.0
github.com/arran4/golang-ical v0.0.0-20220517104411-fd89fefb0182
github.com/arran4/golang-ical v0.0.0-20221122102835-109346913e54
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
@ -31,43 +31,44 @@ require (
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
github.com/spf13/afero v1.9.2
github.com/spf13/afero v1.9.3
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.4
github.com/wneessen/go-mail v0.3.6
github.com/yuin/goldmark v1.5.3
golang.org/x/crypto v0.2.0
golang.org/x/image v0.1.0
golang.org/x/oauth2 v0.1.0
golang.org/x/crypto v0.4.0
golang.org/x/image v0.2.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.3.0
golang.org/x/term v0.3.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
@ -133,11 +134,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.4.0 // indirect
golang.org/x/text v0.5.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

104
go.sum
View File

@ -99,8 +99,8 @@ 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-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=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
@ -198,18 +198,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=
@ -242,8 +238,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=
@ -258,8 +255,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=
@ -501,9 +498,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=
@ -558,8 +557,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=
@ -635,8 +632,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=
@ -644,10 +641,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=
@ -655,7 +648,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=
@ -709,13 +701,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=
@ -723,8 +713,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=
@ -742,14 +730,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=
@ -766,18 +753,13 @@ 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.6 h1:hT8PMIBdcTkoiDwoUGJssPYOe1Gg1/cUcp2o9+ls63o=
github.com/wneessen/go-mail v0.3.6/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=
@ -785,8 +767,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=
@ -835,10 +815,8 @@ 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.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
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=
@ -852,8 +830,8 @@ 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/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=
@ -935,10 +913,8 @@ 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.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
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=
@ -960,8 +936,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=
@ -1070,17 +1046,13 @@ 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/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/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=
@ -1090,15 +1062,15 @@ 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/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=

View File

@ -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 {

View File

@ -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) {

View File

@ -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`,
},

View File

@ -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,
})
}

View File

@ -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
}

View File

@ -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

View File

@ -85,7 +85,7 @@ func getMessage(opts *Opts) *mail.Msg {
m.Subject(opts.Subject)
for _, h := range opts.Headers {
m.SetHeader(h.Field, h.Content)
m.SetGenHeader(h.Field, h.Content)
}
for name, content := range opts.Embeds {

View File

@ -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)
}

View File

@ -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,
}
}
}

View File

@ -830,6 +830,11 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke
}
}
if task.BucketID == 0 && originalTask != nil && originalTask.BucketID != 0 {
task.BucketID = originalTask.BucketID
}
// Either no bucket was provided or the task was moved between lists
if task.BucketID == 0 || (originalTask != nil && task.ListID != 0 && originalTask.ListID != task.ListID) {
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) {

View File

@ -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

View File

@ -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(),

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -18,7 +18,6 @@ package todoist
import (
"os"
"strconv"
"testing"
"time"
@ -50,30 +49,29 @@ func TestConvertTodoistToVikunja(t *testing.T) {
exampleFile, err := os.ReadFile(config.ServiceRootpath.GetString() + "/pkg/modules/migration/wunderlist/testimage.jpg")
assert.NoError(t, err)
makeTestItem := func(id, projectId int64, hasDueDate, hasLabels, done bool) *item {
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)

View File

@ -48,7 +48,6 @@ package routes
import (
"errors"
"fmt"
"net/url"
"strings"
"time"
@ -80,7 +79,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 +272,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())

View File

@ -7727,36 +7727,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 +7750,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 +7769,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 +7781,7 @@ const docTemplate = `{
"items": {
"$ref": "#/definitions/user.User"
}
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.BulkTask": {
@ -7858,7 +7815,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 +7891,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 +7910,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 +7922,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 +7943,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 +7971,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 +7983,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 +8011,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 +8024,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 +8036,7 @@ const docTemplate = `{
"items": {
"$ref": "#/definitions/models.Label"
}
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.LinkSharing": {
@ -8097,26 +8064,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 +8142,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 +8154,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 +8169,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 +8177,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 +8202,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 +8217,7 @@ const docTemplate = `{
"user_id": {
"description": "The username.",
"type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.Message": {
@ -8268,11 +8255,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 +8278,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 +8294,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 +8309,7 @@ const docTemplate = `{
"user_id": {
"description": "The username.",
"type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.NamespaceWithLists": {
@ -8349,11 +8344,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 +8367,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 +8379,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 +8436,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 +8452,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 +8467,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 +8503,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 +8542,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 +8618,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 +8637,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 +8649,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 +8663,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 +8674,7 @@ const docTemplate = `{
},
"user_id": {
"type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskAttachment": {
@ -8616,9 +8694,7 @@ const docTemplate = `{
},
"task_id": {
"type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskCollection": {
@ -8666,9 +8742,7 @@ const docTemplate = `{
"items": {
"type": "string"
}
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskComment": {
@ -8688,9 +8762,7 @@ const docTemplate = `{
},
"updated": {
"type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskRelation": {
@ -8702,7 +8774,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 +8786,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 +8820,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 +8850,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 +8866,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 +8881,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 +8902,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 +8918,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 +8933,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 +8969,7 @@ const docTemplate = `{
"type": "string",
"maxLength": 250,
"minLength": 1
},
"web.Auth": {}
}
}
},
"models.TeamWithRight": {
@ -8887,7 +8981,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 +9009,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 +9038,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 +9049,7 @@ const docTemplate = `{
"type": "string",
"maxLength": 250,
"minLength": 1
},
"web.Auth": {}
}
}
},
"notifications.DatabaseNotification": {
@ -9008,6 +9099,9 @@ const docTemplate = `{
"key": {
"type": "string"
},
"logout_url": {
"type": "string"
},
"name": {
"type": "string"
}
@ -9187,8 +9281,7 @@ const docTemplate = `{
"type": "string",
"maxLength": 250,
"minLength": 1
},
"web.Auth": {}
}
}
},
"v1.LinkShareAuth": {

View File

@ -7718,36 +7718,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 +7741,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 +7760,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 +7772,7 @@
"items": {
"$ref": "#/definitions/user.User"
}
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.BulkTask": {
@ -7849,7 +7806,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 +7882,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 +7901,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 +7913,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 +7934,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 +7962,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 +7974,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 +8002,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 +8015,7 @@
"label_id": {
"description": "The label id you want to associate with a task.",
"type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.LabelTaskBulk": {
@ -8058,9 +8027,7 @@
"items": {
"$ref": "#/definitions/models.Label"
}
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.LinkSharing": {
@ -8088,26 +8055,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 +8133,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 +8145,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 +8160,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 +8168,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 +8193,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 +8208,7 @@
"user_id": {
"description": "The username.",
"type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.Message": {
@ -8259,11 +8246,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 +8269,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 +8285,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 +8300,7 @@
"user_id": {
"description": "The username.",
"type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.NamespaceWithLists": {
@ -8340,11 +8335,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 +8358,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 +8370,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 +8427,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 +8443,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 +8458,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 +8494,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 +8533,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 +8609,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 +8628,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 +8640,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 +8654,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 +8665,7 @@
},
"user_id": {
"type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskAttachment": {
@ -8607,9 +8685,7 @@
},
"task_id": {
"type": "integer"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskCollection": {
@ -8657,9 +8733,7 @@
"items": {
"type": "string"
}
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskComment": {
@ -8679,9 +8753,7 @@
},
"updated": {
"type": "string"
},
"web.CRUDable": {},
"web.Rights": {}
}
}
},
"models.TaskRelation": {
@ -8693,7 +8765,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 +8777,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 +8811,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 +8841,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 +8857,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 +8872,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 +8893,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 +8909,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 +8924,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 +8960,7 @@
"type": "string",
"maxLength": 250,
"minLength": 1
},
"web.Auth": {}
}
}
},
"models.TeamWithRight": {
@ -8878,7 +8972,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 +9000,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 +9029,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 +9040,7 @@
"type": "string",
"maxLength": 250,
"minLength": 1
},
"web.Auth": {}
}
}
},
"notifications.DatabaseNotification": {
@ -8999,6 +9090,9 @@
"key": {
"type": "string"
},
"logout_url": {
"type": "string"
},
"name": {
"type": "string"
}
@ -9178,8 +9272,7 @@
"type": "string",
"maxLength": 250,
"minLength": 1
},
"web.Auth": {}
}
}
},
"v1.LinkShareAuth": {

View File

@ -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: