Compare commits

..

131 Commits

Author SHA1 Message Date
kolaente 4323803fd6
feat: upgrade xorm
continuous-integration/drone/pr Build is failing Details
2022-10-01 16:32:22 +02:00
kolaente 903b8ff438
chore: go mod tidy 2022-10-01 16:26:22 +02:00
kolaente b1fd13bbcb
feat: upgrade xorm 2022-10-01 16:25:29 +02:00
kolaente 878d19beb8
fix: make sure pseudo namespaces and lists always have the current user as owner
continuous-integration/drone/push Build is passing Details
2022-10-01 15:19:46 +02:00
kolaente 96ed1e33e3
fix: don't allow setting a list namespace to 0
continuous-integration/drone/push Build is failing Details
See https://github.com/go-vikunja/app/issues/13
2022-10-01 15:02:17 +02:00
renovate 374a0f9ce3 fix(deps): update module github.com/spf13/viper to v1.13.0 (#1260)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1260
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-09-30 20:07:21 +00:00
kolaente 580bd5aeaa
fix(deps): update module github.com/lib/pq to v1.10.7
continuous-integration/drone/push Build is failing Details
2022-09-30 19:30:18 +02:00
kolaente c359d6a97d
fix(deps): update golang.org/x/term digest to 7a66f97 2022-09-30 19:29:32 +02:00
kolaente 038702a2a0
fix(deps): update golang.org/x/image digest to e7cb969 2022-09-30 19:29:09 +02:00
kolaente 6426d40825
fix(deps): update module github.com/coreos/go-oidc/v3 to v3.4.0 2022-09-30 19:28:42 +02:00
kolaente bbe102dd57
fix(deps): update module src.techknowlogick.com/xgo to v1.5.0+1.19 2022-09-30 19:28:06 +02:00
kolaente 65484bc432
fix(deps): update golang.org/x/oauth2 digest to f213421 2022-09-30 19:27:19 +02:00
kolaente 54f6cc7a64
fix(deps): update golang.org/x/sync digest to 8fcdb60 2022-09-30 19:26:17 +02:00
kolaente f1b2338227
chore(deps): update klakegg/hugo docker tag to v0.101.0 2022-09-30 19:24:49 +02:00
kolaente 45defebcf4
fix: tasks with the same assignee as doer should not appear twice in overdue task mails
continuous-integration/drone/push Build is passing Details
2022-09-30 18:35:40 +02:00
kolaente 86ee8273bc
chore: upgrade echo
continuous-integration/drone/push Build is failing Details
2022-09-30 13:48:18 +02:00
Luca Bernstein 3adfeb3b34 fix(namespaces): add list subscriptions (#1254)
continuous-integration/drone/push Build is failing Details
Add list subscriptions to namespaces call to enable frontend to show subscription state correctly.

Resolves https://github.com/go-vikunja/frontend/issues/75

Reviewed-on: vikunja/api#1254
Reviewed-by: konrad <k@knt.li>
Co-authored-by: Luca Bernstein <luca@lucabernstein.com>
Co-committed-by: Luca Bernstein <luca@lucabernstein.com>
2022-09-29 09:49:24 +00:00
Felix Breidenstein 9bb8a26706
fix(docs): Fix redirect_url example (#50)
continuous-integration/drone/push Build is failing Details
The name of the openid provider gets appended to the redirect_url
2022-09-28 15:34:53 +02:00
Luca Bernstein 54b7f7127c fix(caldav): no failed login emails for tokens (#1252)
continuous-integration/drone/push Build is passing Details
Prevent Vikunja from sending mail notifications for failed login attempts if CalDav token is used.

Before, as the provided password value was tested against the user password regardless of whether it was a CalDav token, it triggered a failed login attempt email every three times.

Reviewed-on: vikunja/api#1252
Reviewed-by: konrad <k@knt.li>
Co-authored-by: Luca Bernstein <luca@lucabernstein.com>
Co-committed-by: Luca Bernstein <luca@lucabernstein.com>
2022-09-27 15:12:37 +00:00
Luca Bernstein 25609db567 fix(mail): pass mail server timeout (#1253)
continuous-integration/drone/push Build is failing Details
Fix error log for mailserver closing logic, as default timeout of 15 seconds of mail client package used triggers before our logic leading to error on close.

Resolves https://github.com/go-vikunja/api/issues/48

Reviewed-on: vikunja/api#1253
Reviewed-by: konrad <k@knt.li>
Co-authored-by: Luca Bernstein <luca@lucabernstein.com>
Co-committed-by: Luca Bernstein <luca@lucabernstein.com>
2022-09-26 16:09:39 +00:00
kolaente 2e3603507c
fix(docs): document pnpm instead of yarn
continuous-integration/drone/push Build is failing Details
2022-09-23 12:26:42 +02:00
kolaente 2efc1b5a87
feat(docs): add docs about how to deploy Vikunja in a subdirectory 2022-09-23 12:23:59 +02:00
Arie 090c67138a
fix: preserve dates for repeating tasks (#47)
continuous-integration/drone/push Build is passing Details
Reviewed-At: https://github.com/go-vikunja/api/pull/47
2022-09-16 17:20:08 +02:00
kolaente d8f387f796
fix: don't try to compress riscv64 binaries in releases
continuous-integration/drone/push Build is passing Details
2022-09-07 16:38:43 +02:00
kolaente aaeffe925e
fix(caldav): make sure duration and due date follow rfc5545
continuous-integration/drone/push Build is failing Details
Related discussion: https://community.vikunja.io/t/error-with-davx-synchronization/810
2022-09-07 15:39:40 +02:00
kolaente f814dd03eb
feat: add sponsor to readme (relm)
continuous-integration/drone/push Build is failing Details
2022-09-06 12:02:35 +02:00
kolaente 2369ce5554
fix(docs): clarify using port 25 as mail port when mail does not work
continuous-integration/drone/push Build is failing Details
2022-09-05 17:32:48 +02:00
kolaente c19479757a
fix: properly log extra message
continuous-integration/drone/push Build is failing Details
2022-09-01 14:19:00 +02:00
kolaente 8fddbf43ba
chore: release preparations
continuous-integration/drone/push Build is passing Details
2022-08-17 17:04:47 +02:00
kolaente beb4d07cf9
fix: don't override saved filters
continuous-integration/drone/push Build is failing Details
2022-08-17 17:03:01 +02:00
kolaente 10ded56f66
fix: don't fail a migration if there is no filter saved
continuous-integration/drone/push Build is passing Details
2022-08-17 12:27:03 +02:00
kolaente d709db4e18
chore: release preparations
continuous-integration/drone/push Build is passing Details
2022-08-17 10:20:20 +02:00
kolaente 0c8bed4054 fix: lint
continuous-integration/drone/push Build is failing Details
2022-08-16 21:27:32 +00:00
kolaente 9ddd7f4889 fix: only list all users when allowed 2022-08-16 21:27:32 +00:00
kolaente 3047ccfd4a feat: add migration to change user ids to usernames in saved filters 2022-08-16 21:27:32 +00:00
kolaente 7f28865903 feat: search by assignee username instead of id 2022-08-16 21:27:32 +00:00
renovate a273d1ae76 fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.15 (#1238)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1238
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-16 08:21:11 +00:00
kolaente c9e044b3ad
fix: add debian-based docker image for arm 32 builds
continuous-integration/drone/push Build is passing Details
2022-08-15 23:56:15 +02:00
kolaente 8bf0f8bb57
fix: make sure generating blur hashes for bmp, tiff and webp images works
continuous-integration/drone/push Build is passing Details
2022-08-15 23:37:05 +02:00
kolaente 3ccc6365a6
fix: prevent moving a list into a pseudo namespace
continuous-integration/drone/push Build is passing Details
2022-08-15 23:25:39 +02:00
renovate 8d10130d4c fix(deps): update module github.com/wneessen/go-mail to v0.2.6 (#1235)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1235
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-14 16:08:20 +00:00
kolaente 51314f269d
feat(docs): add k8s docs
continuous-integration/drone/push Build is passing Details
2022-08-12 13:47:18 +02:00
renovate 9eefb2bea9 fix(deps): update golang.org/x/sys digest to fbc7d0a (#1234)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1234
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-12 11:21:09 +00:00
renovate 2e5c91efdf fix(deps): update module github.com/labstack/echo/v4 to v4.8.0 (#1233)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1233
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-11 10:26:11 +00:00
kolaente dbb0f54732
feat: add openid examples
continuous-integration/drone/push Build is passing Details
2022-08-09 10:48:50 +02:00
renovate 6e639d9ccb fix(deps): update golang.org/x/crypto digest to 630584e (#1218)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1218
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-08 20:16:39 +00:00
renovate a9a8bd54ee fix(deps): update golang.org/x/image digest to 062f8c9 (#1219)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1219
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-08 19:19:13 +00:00
renovate d3a655c75b fix(deps): update golang.org/x/oauth2 digest to 128564f (#1220)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1220
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-08 18:13:57 +00:00
renovate e0dc3807f6 fix(deps): update golang.org/x/sys digest to 1c4a2a7
continuous-integration/drone/pr Build is passing Details
continuous-integration/drone/push Build is failing Details
2022-08-08 16:00:51 +00:00
konrad 4e7510995c fix(deps): update module github.com/prometheus/client_golang to v1.13.0 (#1231)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1231
2022-08-07 09:28:15 +00:00
renovate f8300c9e1b fix(deps): update module github.com/prometheus/client_golang to v1.13.0
continuous-integration/drone/pr Build is passing Details
2022-08-06 10:00:57 +00:00
renovate ef3f07b677 fix(deps): update golang.org/x/term digest to a9ba230 (#1222)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1222
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-05 06:15:32 +00:00
renovate ea66875310 fix(deps): update golang.org/x/sys digest to 8e32c04 (#1230)
continuous-integration/drone/push Build encountered an error Details
Reviewed-on: vikunja/api#1230
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-05 05:23:26 +00:00
renovate 850ac0c601 fix(deps): update golang.org/x/sync digest to 886fb93 (#1221)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1221
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-04 20:58:59 +00:00
renovate 8ebb642d55 fix(deps): update golang.org/x/sys digest to 6e608f9 (#1229)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1229
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-04 19:12:47 +00:00
kolaente 2a569488d7
chore: release preparations
continuous-integration/drone/push Build is passing Details
2022-08-03 20:06:53 +02:00
kolaente 49b3ae82e4
chore: add git-cliff config 2022-08-03 20:06:35 +02:00
kolaente b71e6f8049
fix(docker): use official go image instead of our own to build
continuous-integration/drone/push Build is passing Details
2022-08-03 17:54:21 +02:00
kolaente fa82c71f8c
fix(ci): install git in lint step
continuous-integration/drone/push Build is failing Details
2022-08-03 17:19:29 +02:00
kolaente 8f473481ac
fix(mage): handle different types of errors
continuous-integration/drone/push Build was killed Details
2022-08-03 17:11:17 +02:00
kolaente 51cd2830dd
fix(ci): make sure the linter actually runs
continuous-integration/drone/push Build is failing Details
2022-08-03 16:20:49 +02:00
kolaente 430057a404
chore: update golangci-lint
continuous-integration/drone/push Build is failing Details
2022-08-03 15:20:11 +02:00
kolaente 7ffe9b625e
fix: switch back to alpine for everything, disable arm 32 docker builds
continuous-integration/drone/push Build is failing Details
2022-08-03 14:05:07 +02:00
kolaente d47edac376
feat(mail): don't try to authenticate when no username and password was provided
continuous-integration/drone/push Build is failing Details
2022-08-03 13:41:42 +02:00
kolaente aed1ad6d96
fix(ci): sign drone config
continuous-integration/drone/push Build is failing Details
2022-08-03 12:57:51 +02:00
kolaente 84bcdbf937
fix: use golang build image to test migrations
continuous-integration/drone/push Build is pending Details
2022-08-03 12:57:20 +02:00
kolaente 280ac1164b
fix(docker): switch to debian base image
continuous-integration/drone/push Build is failing Details
2022-08-03 12:44:18 +02:00
kolaente b6d7323cdf
fix: use our own build image as base build image
continuous-integration/drone/push Build is failing Details
2022-08-02 23:02:01 +02:00
kolaente 59796fd490
fix: switch to buster for build image
continuous-integration/drone/push Build is passing Details
The current alpine image does (still) not work on arm. Buster does, so we're just using that.
2022-08-02 22:53:10 +02:00
kolaente 26e2d0bdde
fix: increase test timeout 2022-08-02 22:49:48 +02:00
kolaente 251b877015
chore: use our custom build image to build docker image
continuous-integration/drone/push Build is failing Details
2022-08-02 22:01:29 +02:00
renovate b460fa8c82 chore(deps): update module go to 1.18 (#1225)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1225
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-02 17:11:06 +00:00
kolaente 77fafd5dc3
fix: lint
continuous-integration/drone/push Build is failing Details
2022-08-02 15:07:08 +02:00
kolaente 3688bbde20
fix: don't return email addresses from user search results
continuous-integration/drone/push Build is failing Details
2022-08-02 15:02:15 +02:00
kolaente c51ee94ad1
fix: return all users on a list when no search param was provided 2022-08-02 15:02:00 +02:00
kolaente 8f27e7e619
fix: properly decode params in url
continuous-integration/drone/push Build is failing Details
Resolves vikunja/api#1224
2022-08-02 14:50:03 +02:00
kolaente 382a7884be
fix: make sure to use user discoverability settings when searching list users
continuous-integration/drone/push Build is failing Details
Resolves vikunja/frontend#2196
2022-08-02 13:26:42 +02:00
renovate cd345b62c2 fix(deps): update module github.com/go-testfixtures/testfixtures/v3 to v3.8.1 (#1226)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1226
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-08-01 16:30:31 +00:00
renovate dc2285bcc9 fix(deps): update golang.org/x/sys digest to 1609e55 (#1217)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1217
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-31 18:32:31 +00:00
kolaente 1feb62cc45
fix: lint
continuous-integration/drone/push Build is failing Details
2022-07-31 15:50:38 +02:00
kolaente 117f6b38e1
feat: add issue template
continuous-integration/drone/push Build is failing Details
2022-07-21 16:50:30 +02:00
kolaente dd461746a6
fix: add validation for negative repeat after values
continuous-integration/drone/push Build is failing Details
Partial fix for vikunja/frontend#2179
2022-07-21 15:00:28 +02:00
kolaente 0f555b7ec7
fix: reset id sequence when importing a dump from postgres
continuous-integration/drone/push Build is failing Details
2022-07-21 14:54:52 +02:00
renovate f93b68819d fix(deps): update module github.com/spf13/viper to v1.12.0 (#1180)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1180
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-19 15:32:46 +00:00
kolaente 79b31673e2
fix: return 9:00 as default time for reminders if none was set
continuous-integration/drone/push Build is failing Details
Resolves vikunja/api#1211
2022-07-19 16:38:48 +02:00
kolaente f8cc67d37f
chore(docs): add frontendurl to all example configs
continuous-integration/drone/push Build is failing Details
2022-07-19 16:26:38 +02:00
renovate 6c92859f8c fix(deps): update module github.com/swaggo/swag to v1.8.4 (#1216)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1216
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-19 14:20:58 +00:00
renovate ef6fe9500e fix(deps): update module github.com/spf13/afero to v1.9.2 (#1215)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1215
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-19 11:46:58 +00:00
renovate 8578f3a927 fix(deps): update golang.org/x/oauth2 digest to c8730f7 (#1214)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1214
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-18 20:34:54 +00:00
renovate bfcebc63b7 fix(deps): update golang.org/x/sys digest to c0bba94 (#1206)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1206
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-18 10:00:24 +00:00
renovate 8cafe84170 fix(deps): update golang.org/x/oauth2 digest to 2104d58 (#1204)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1204
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-18 10:00:03 +00:00
renovate f3319e837a fix(deps): update github.com/c2h5oh/datasize digest to 859f65c (#1201)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1201
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-15 06:59:22 +00:00
renovate 7c70b5d4b3 fix(deps): update golang.org/x/sync digest to 0de741c (#1205)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1205
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-15 06:23:11 +00:00
renovate 1eceecf3ab fix(deps): update module github.com/gabriel-vasile/mimetype to v1.4.1 (#1208)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1208
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-14 21:17:31 +00:00
renovate 76fa841e9a fix(deps): update module github.com/spf13/afero to v1.9.0 (#1210)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1210
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-14 21:16:02 +00:00
renovate 2f601052fd fix(deps): update golang.org/x/crypto digest to 0559593 (#1202)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1202
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-14 14:15:52 +00:00
renovate 8023674adf fix(deps): update module github.com/yuin/goldmark to v1.4.13 (#1209)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1209
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-14 12:44:06 +00:00
renovate 560fa187e0 fix(deps): update golang.org/x/image digest to 41969df (#1203)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1203
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-14 07:03:12 +00:00
renovate a321c3cfb9 fix(deps): update golang.org/x/term digest to 065cf7b (#1207)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1207
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-14 07:02:43 +00:00
kolaente 6e15d46a93
fix(restore): use the correct initial migration
continuous-integration/drone/push Build is failing Details
Related to vikunja/api#1199
2022-07-13 23:44:21 +02:00
kolaente 54348c5891
fix(restore): make sure to reset sequences after importing a dump when using postgres
Related to vikunja/api#1199
2022-07-13 23:43:53 +02:00
kolaente 596d2bf676
fix(restore): properly decode notifications json data
Related to vikunja/api#1199
2022-07-13 23:43:20 +02:00
kolaente ac92499b7d
fix(caldav): make sure description is parsed correctly when multiline
continuous-integration/drone/push Build is passing Details
Resolves https://github.com/go-vikunja/api/issues/35
2022-07-13 22:47:25 +02:00
kolaente b1892eaf63
fix(mail): set server name in tls config so that sending mail works with skipTlsVerify set to false
continuous-integration/drone/push Build is passing Details
2022-07-13 19:57:44 +02:00
Pavle Portic b9793a267b Add exec to run script to run app as PID 1 (#1200)
continuous-integration/drone/push Build is failing Details
When running the docker container, the sh script will run as PID 1 and intercept any external signals (like docker stop) and won't pass it on to the app. Docker will wait for 10 seconds before proceeding to force kill the app, leading to both an unclean shutdown and an unnecessary wait of 10 seconds.

The exec in the script replaces the shell process with the `su` process, which correctly passes on signals to the app process and triggers a regular shutdown when doing a docker stop.

Co-authored-by: Pavle Portic <git@theedgeofrage.com>
Reviewed-on: vikunja/api#1200
Reviewed-by: konrad <k@knt.li>
Co-authored-by: TheEdgeOfRage <git@theedgeofrage.com>
Co-committed-by: TheEdgeOfRage <git@theedgeofrage.com>
2022-07-12 14:02:31 +00:00
kolaente c906fc2b07
fix(mail): don't try to authenticate against the mail server when no credentials are provided
continuous-integration/drone/push Build is passing Details
Related to https://github.com/go-vikunja/api/issues/34
2022-07-12 15:46:28 +02:00
kolaente 4bb77b5539
fix(mail): don't set a username by default
continuous-integration/drone/push Build is passing Details
2022-07-12 11:49:23 +02:00
kolaente 5743a4afe5
fix: properly set tls config for mailer
continuous-integration/drone/push Build is passing Details
2022-07-11 16:10:28 +02:00
kolaente 62325de9cd
feat: use actual uuids for tasks
continuous-integration/drone/push Build is failing Details
2022-07-11 14:54:33 +02:00
kolaente 8759937e3c
feat(docs): add versions explanation
continuous-integration/drone/push Build is passing Details
2022-07-08 00:14:01 +02:00
kolaente 5cc4927b9e
fix: add missing error check
continuous-integration/drone/push Build is passing Details
2022-07-07 23:23:15 +02:00
kolaente 2b074c60a7
fix(caldav): properly parse durations when returning VTODOs
continuous-integration/drone/push Build is failing Details
Resolves https://github.com/go-vikunja/frontend/issues/55
2022-07-07 23:20:37 +02:00
kolaente f5a4c136fb
fix: cycles in tasks array when memory caching was enabled
continuous-integration/drone/push Build is failing Details
Resolves #1119
2022-07-07 18:34:49 +02:00
kolaente 230478aae9
fix: remove credential escaping for postgres connections to allow for passwords with special characters
continuous-integration/drone/push Build is passing Details
Resolves https://github.com/go-vikunja/api/issues/22
2022-07-07 18:04:16 +02:00
kolaente 7e99618319
chore: upgrade trello api wrapper and remove fork
continuous-integration/drone/push Build is failing Details
2022-07-07 16:21:33 +02:00
kolaente 73c4c399e5
feat: use embed fs directly to embed the logo in mails
continuous-integration/drone/push Build is failing Details
2022-07-07 15:54:38 +02:00
kolaente 25ffa1bc2e
fix: prevent logging openid provider errors twice
continuous-integration/drone/push Build is failing Details
2022-07-07 15:47:37 +02:00
kolaente 4429ba2da1
fix(caldav): make sure the caldav tokens of non-local accounts are properly checked
continuous-integration/drone/push Build is failing Details
2022-07-04 18:08:46 +02:00
renovate db1ccff0de fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.14 (#1194)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1194
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-04 14:45:42 +00:00
renovate 2c9ab3d86f fix(deps): update module github.com/go-testfixtures/testfixtures/v3 to v3.8.0 (#1168)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1168
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-07-04 14:45:09 +00:00
kolaente 951d74b272
fix: go mod tidy
continuous-integration/drone/push Build is passing Details
2022-06-30 16:41:47 +02:00
kolaente a38efef734
fix(docs): clarify frontend requirements to use Vikunja
continuous-integration/drone/push Build is failing Details
2022-06-30 16:40:38 +02:00
kolaente a060cbe820
chore(docs): clarify openid setup with environment variables
continuous-integration/drone/push Build is failing Details
2022-06-30 16:27:06 +02:00
kolaente ad17ff5c32
fix(docs): image urls in synology setup explanation 2022-06-30 16:25:24 +02:00
kolaente d0e09d69d0 fix: tests
continuous-integration/drone/push Build is failing Details
2022-06-30 14:21:17 +00:00
kolaente 7a30294407 fix: go mod tidy 2022-06-30 14:21:17 +00:00
kolaente bc7f6a8586 fix: set the correct go version in go.mod 2022-06-30 14:21:17 +00:00
kolaente f30a9d1038 chore(docs): add new mailer option to docs 2022-06-30 14:21:17 +00:00
kolaente c62e26b6fe fix: revert renaming Attachments to Embeds everywhere 2022-06-30 14:21:17 +00:00
kolaente f4f8450d16 feat: embed the vikunja logo as inline attachment 2022-06-30 14:21:17 +00:00
kolaente 30e0e98f77 feat: migrate away from gomail 2022-06-30 14:21:17 +00:00
63 changed files with 2081 additions and 589 deletions

6
.dockerignore Normal file
View File

@ -0,0 +1,6 @@
files/
Dockerfile
docker-manifest.tmpl
docker-manifest-unstable.tmpl
*.db
*.zip

View File

@ -132,13 +132,14 @@ steps:
event: [ push, tag, pull_request ]
- name: lint
image: vikunja/golang-build:latest
image: golang:1.17-alpine
pull: true
environment:
GOPROXY: 'https://goproxy.kolaente.de'
depends_on: [ build ]
commands:
- wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.45.2
- apk --no-cache add build-base git
- wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.47.3
- ./mage-static check:all
when:
event: [ push, tag, pull_request ]
@ -152,7 +153,7 @@ steps:
- unzip vikunja-latest.zip vikunja-unstable-linux-amd64
- name: test-migration-sqlite
image: kolaente/toolbox:latest
image: vikunja/golang-build:latest
pull: true
depends_on: [ test-migration-prepare, build ]
environment:
@ -171,7 +172,7 @@ steps:
event: [ push, tag, pull_request ]
- name: test-migration-mysql
image: kolaente/toolbox:latest
image: vikunja/golang-build:latest
pull: true
depends_on: [ test-migration-prepare, build ]
environment:
@ -190,7 +191,7 @@ steps:
event: [ push, tag, pull_request ]
- name: test-migration-psql
image: kolaente/toolbox:latest
image: vikunja/golang-build:latest
pull: true
depends_on: [ test-migration-prepare, build ]
environment:
@ -621,7 +622,7 @@ steps:
- tar -xzf vikunja-theme.tar.gz
- name: build
image: klakegg/hugo:0.93.3
image: klakegg/hugo:0.101.0
pull: true
commands:
- cd docs
@ -662,6 +663,7 @@ steps:
image: docker:git
commands:
- git fetch --tags
- name: docker-arm-unstable
image: plugins/docker:linux-arm
pull: true
@ -672,6 +674,7 @@ steps:
from_secret: docker_password
repo: vikunja/api
tags: unstable-linux-arm
dockerfile: Dockerfile.arm32
depends_on: [ fetch-tags ]
when:
ref:
@ -688,6 +691,7 @@ steps:
repo: vikunja/api
auto_tag: true
auto_tag_suffix: linux-arm
dockerfile: Dockerfile.arm32
depends_on: [ fetch-tags ]
when:
ref:
@ -874,6 +878,6 @@ steps:
- failure
---
kind: signature
hmac: 1c4c211e66e4b6eddd2a1c1bad31e5c960d4f67d6033f4d5c4de7896dfae6c30
hmac: d95e5d4b31e22079ce6360f31ec9257b26cd206b614cb1ec660290c061eced8f
...

44
.gitea/issue_template.md Normal file
View File

@ -0,0 +1,44 @@
<!--
Please fill out this issue template to report a bug.
If you want to propose a new feature, please open a discussion thread in the forum: https://community.vikunja.io
-->
**Version information:**
Frontend Version:
API Version:
Browser and OS Version:
**Steps to reproduce:**
<!--
Add clear steps to reproduce the bug. Provide screenshots where applicable.
-->
1.
2.
...
**Expected behavior:**
<!--
Describe what happened.
-->
**Actual behavior:**
<!--
Describe what happened instead.
-->
**Checklist:**
* [ ] I have provided all required information
* [ ] I am using the latest release or the latest unstable build
* [ ] I was able to reproduce the bug on [try](https://try.vikunja.io)

View File

@ -7,6 +7,388 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
All releases can be found on https://code.vikunja.io/api/releases.
## [0.19.2] - 2022-08-17
### Bug Fixes
* Don't fail a migration if there is no filter saved ([10ded56](10ded56f6697ef47910ec68d37f26ed47cbe9180))
* Don't override saved filters ([beb4d07](beb4d07cf95fc25f7cc5f7471b46bdab49f95fe0))
## [0.19.1] - 2022-08-17
### Bug Fixes
* Prevent moving a list into a pseudo namespace ([3ccc636](3ccc6365a6892f37ee54b0750a34a61e52f6dba1))
* Make sure generating blur hashes for bmp, tiff and webp images works ([8bf0f8b](8bf0f8bb571ddff69a7142be1acaa2e4e0c38e3b))
* Add debian-based docker image for arm 32 builds ([c9e044b](c9e044b3ad60d25e9641d22d84571a7db83a26ac))
* Only list all users when allowed ([9ddd7f4](9ddd7f48895f508539d591aeebde450a86987024))
* Lint ([0c8bed4](0c8bed4054649de8510e5a636d1a14b65d52c402))
### Dependencies
* *(deps)* Update golang.org/x/sys digest to 6e608f9 (#1229)
* *(deps)* Update golang.org/x/sync digest to 886fb93 (#1221)
* *(deps)* Update golang.org/x/sys digest to 8e32c04 (#1230)
* *(deps)* Update golang.org/x/term digest to a9ba230 (#1222)
* *(deps)* Update module github.com/prometheus/client_golang to v1.13.0
* *(deps)* Update module github.com/prometheus/client_golang to v1.13.0 (#1231)
* *(deps)* Update golang.org/x/sys digest to 1c4a2a7
* *(deps)* Update golang.org/x/oauth2 digest to 128564f (#1220)
* *(deps)* Update golang.org/x/image digest to 062f8c9 (#1219)
* *(deps)* Update golang.org/x/crypto digest to 630584e (#1218)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.8.0 (#1233)
* *(deps)* Update golang.org/x/sys digest to fbc7d0a (#1234)
* *(deps)* Update module github.com/wneessen/go-mail to v0.2.6 (#1235)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.15 (#1238)
### Features
* *(docs)* Add k8s docs* Add openid examples ([dbb0f54](dbb0f5473269fb29c4a484cd233a5b76484c4ca7))
* Search by assignee username instead of id ([7f28865](7f28865903740d6dde15ee005323fbdee3072166))
* Add migration to change user ids to usernames in saved filters ([3047ccf](3047ccfd4af8fee55d9ebff49138911ab80cb3d2))
## [0.19.0] - 2022-08-03
### Bug Fixes
* *(caldav)* Make sure the caldav tokens of non-local accounts are properly checked
* *(caldav)* Properly parse durations when returning VTODOs
* *(caldav)* Make sure description is parsed correctly when multiline
* *(ci)* Sign drone config
* *(ci)* Make sure the linter actually runs
* *(ci)* Install git in lint step
* *(docker)* Switch to debian base image
* *(docker)* Use official go image instead of our own to build
* *(docs)* Update minimum required go version
* *(docs)* Use up-to-date hugo image for building
* *(docs)* Don't use cannonify url
* *(docs)* Image urls in synology setup explanation
* *(docs)* Clarify frontend requirements to use Vikunja
* *(dump)* Don't try to save a config file if none was provided and dump vikunja env variables
* *(mage)* Handle different types of errors
* *(mail)* Don't set a username by default
* *(mail)* Don't try to authenticate against the mail server when no credentials are provided
* *(mail)* Set server name in tls config so that sending mail works with skipTlsVerify set to false
* *(restore)* Properly decode notifications json data
* *(restore)* Make sure to reset sequences after importing a dump when using postgres
* *(restore)* Use the correct initial migration* Generate swagger docs ([4de8ec5](4de8ec56a62caef22c2061376383de1fe53ca4c3))
* Make sure the full task is available in notifications ([c2b6119](c2b6119434e6e806785d2c259c3ca3d25496ec75))
* Don't try to load the namespace of a list if it is a shared list ([d7e47a2](d7e47a28d4bb04d4c7c3ed85a263134180da447a))
* Correctly load and pass the user when deleting it ([50b65a5](50b65a517da6869dc6a48fec40323e254ba4c032))
* Updating a list might remove its background ([cf05de1](cf05de19b317bd99c30de4c6a149a0d8a4ff4f49))
* Sorting for saved filters ([57e5d10](57e5d10eee4c45a04e9e1aaeaf41dd44eb8ce788))
* Importing trello attachments ([c3e0e64](c3e0e6405a634894a30dbf9c0506d1691ae4d443))
* Lint ([0b77625](0b7762590f6a0a82090ef74e9e7e32b37142d343))
* Deleting users with no namespaces ([f8a0a7e](f8a0a7e9539a44b2f790a08eb1b03028b56eaac3))
* Importing tasks from todoist without a due time set ([fd0d462](fd0d462bf4dd8225c67ba34958e5148f6167d264))
* User deletion never happens ([72d3c54](72d3c54efd3dda6ae846a069415688391cb1c9ae))
* User deletion reminder emails counting up ([f581885](f581885e65ada15439ec02f1d18d825b03581523))
* User not actually deleted ([70e005e](70e005e7ce5cf1dd25ec9ddfde3cfbbd258fadb6))
* User deletion schedule ([5c88dfe](5c88dfe88eab442724f22c3b29741e78939deae2))
* Friendly name not getting synced on first login from openid ([190a9f2](190a9f2a4c1a59bc68b839c465bb2536532c0e96))
* Importing archived lists or namespaces ([8bb3f8d](8bb3f8d37c78dc704ff4316c750e143528151b48))
* Lint ([a31086a](a31086a7a9ca7723f61a826bccbea125243478f1))
* Microsoft todo migration not importing all tasks ([43f1daf](43f1daf40c388a0aa40f7fd6a8db4c78308d4efd))
* Clarify which config file is used on startup ([44aaf0a](44aaf0a4eccebb1d1a25f5563e928bd1bb82d351))
* Disabling logging completely now works ([22e3f24](22e3f242a396aa9cf54e9426077816f97a0da36f))
* Restoring dumps with no config file saved in them ([8bf2254](8bf2254f4b87446ab0a39080cb0b7d32ccec7c0a))
* Validate email address when creating a user via cli ([75f74b4](75f74b429eea7ae3a75cb10def1ca658af35086a))
* Checking for error types ([ac6818a](ac6818a4769a162c458553944509fe64357370f9))
* Lint ([7fa0865](7fa086518800243385d8cc4696eeea9bf093e5b3))
* Return BlurHash in unsplash search results ([6b51fae](6b51fae0931308464038f55b25e81e68d014c49c))
* Go mod tidy ([e19ad11](e19ad1184662dc9ac9aa89a44abdffc091e2a1b8))
* Decoding images for blurHash generation ([d3bdafb](d3bdafb717b1ad3e2165097ef0b0c2dd47e1502e))
* Lint ([de97fcb](de97fcbd121b1d56b74175fd79ef594ef34e71c8))
* Broken link (#27) ([96e519e](96e519ea96c9537222d0b455037e11fbe9660c31))
* Add more methods to figure out the current binary location ([9845fcc](9845fcc1708431f8f736d36e7e19a1067b0e0e52))
* Set derived default values only after reading config from file or env ([f5ebada](f5ebada91351faf1e5602f0260908defaaabd810))
* Sort tasks logically and consistent across dbms (#1177) ([e52c45d](e52c45d5aabb74ea7b472e8d5b44491cdd7e9489))
* VIKUNJA_SERVICE_JWT_SECRET should be VIKUNJA_SERVICE_JWTSECRET (#1184) ([172a621](172a6214d7c30278017129b950339c78a6ddb7bc))
* Add missing migration ([d837f8a](d837f8a6248b5ff2700a4bfc300d7f9d466cb918))
* Revert renaming Attachments to Embeds everywhere ([c62e26b](c62e26b6fe9d9f362fcfb1df2d5664d7f6854c31))
* Set the correct go version in go.mod ([bc7f6a8](bc7f6a858693b0e61fff7d03b5c2b40b6ae1a55d))
* Go mod tidy ([7a30294](7a30294407843693f6c3a7414b3b9d7093359194))
* Tests ([d0e09d6](d0e09d69d048e62ee7c5b666c2f56761b03e68e6))
* Go mod tidy ([951d74b](951d74b272b1e881faa10095f47b6598bb076273))
* Prevent logging openid provider errors twice ([25ffa1b](25ffa1bc2e2f1108f20b0336708d2410bb61c9e1))
* Remove credential escaping for postgres connections to allow for passwords with special characters ([230478a](230478aae947c86f4c6f1f251dcb30aeb1293283))
* Cycles in tasks array when memory caching was enabled ([f5a4c13](f5a4c136fbca6fc5770476e6de8d81173f007df2))
* Add missing error check ([5cc4927](5cc4927b9ef97667bf763772beb36225fdbeded8))
* Properly set tls config for mailer ([5743a4a](5743a4afe51de221beeeabe66552ae4d92eed1a6))
* Return 9:00 as default time for reminders if none was set ([79b3167](79b31673e2a79eaa124976840e85757d2bebb887))
* Reset id sequence when importing a dump from postgres ([0f555b7](0f555b7ec74ad493d2f70a4f4040db333943dc1c))
* Add validation for negative repeat after values ([dd46174](dd461746a655d716ef142d96a2bcef5615de3dd9))
* Lint ([1feb62c](1feb62cc458e939d46d16d24347557e7959ddfb9))
* Make sure to use user discoverability settings when searching list users ([382a788](382a7884be1f37da5c8f657c4b17316d8691dd59))
* Properly decode params in url ([8f27e7e](8f27e7e619ac73716211d838f52c73d7d97aead5))
* Return all users on a list when no search param was provided ([c51ee94](c51ee94ad1d552d69c71adfc2180c7ad0d23235d))
* Don't return email addresses from user search results ([3688bbd](3688bbde20e989397353ea4f7e872b00a53099c2))
* Lint ([77fafd5](77fafd5dc32aee464961be40d5d0ccf82490d02a))
* Increase test timeout ([26e2d0b](26e2d0bddeaea902dba055baf7a4c866a44ba7f1))
* Switch to buster for build image ([59796fd](59796fd4905fca74d26c5541878379cda143a30e))
* Use our own build image as base build image ([b6d7323](b6d7323cdfac958c9740feba1342114ab13a0afd))
* Use golang build image to test migrations ([84bcdbf](84bcdbf937c3be7823fcf8d5fef52e3cbb1c9bde))
* Switch back to alpine for everything, disable arm 32 docker builds ([7ffe9b6](7ffe9b625e441202a704db2774dd66fc38244c6d))
### Dependencies
* *(deps)* Update golang.org/x/sys commit hash to a851e7d (#972)
* *(deps)* Update golang.org/x/sys commit hash to aa78b53 (#973)
* *(deps)* Update golang.org/x/sys commit hash to 528a39c (#974)
* *(deps)* Update golang.org/x/sys commit hash to 437939a (#975)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.1 (#976)
* *(deps)* Update module github.com/coreos/go-oidc/v3 to v3.1.0 (#985)
* *(deps)* Update module github.com/spf13/viper to v1.9.0 (#987)
* *(deps)* Update golang.org/x/crypto commit hash to 089bfa5 (#979)
* *(deps)* Update golang.org/x/term commit hash to 140adaa (#983)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.6.0 (#988)
* *(deps)* Update golang.org/x/sys commit hash to b8560ed (#989)
* *(deps)* Update module github.com/golang-jwt/jwt/v4 to v4.1.0 (#991)
* *(deps)* Update golang.org/x/sys commit hash to 92d5a99 (#992)
* *(deps)* Update module github.com/swaggo/swag to v1.7.3 (#990)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.6.1 (#993)
* *(deps)* Update golang.org/x/sys commit hash to 1cf2251 (#994)
* *(deps)* Update golang.org/x/sys commit hash to 39ccf1d (#995)
* *(deps)* Update golang.org/x/term commit hash to 03fcf44 (#996)
* *(deps)* Update golang.org/x/oauth2 commit hash to 6b3c2da (#1000)
* *(deps)* Update golang.org/x/sys commit hash to 69063c4 (#1001)
* *(deps)* Update module github.com/gabriel-vasile/mimetype to v1.4.0 (#1004)
* *(deps)* Update postgres docker tag to v14 (#1005)
* *(deps)* Update module github.com/go-redis/redis/v8 to v8.11.4 (#1003)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.9 (#1008)
* *(deps)* Update golang.org/x/sys commit hash to 9d821ac (#1009)
* *(deps)* Update golang.org/x/sys commit hash to 0ec99a6 (#1010)
* *(deps)* Update golang.org/x/sys commit hash to 9d61738 (#1011)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.2 (#1012)
* *(deps)* Update golang.org/x/sys commit hash to 8e51046 (#1016)
* *(deps)* Update golang.org/x/sys commit hash to d6a326f (#1017)
* *(deps)* Update module github.com/swaggo/swag to v1.7.4 (#1018)
* *(deps)* Update golang.org/x/sys commit hash to 711f33c (#1019)
* *(deps)* Update golang.org/x/sys commit hash to 69cdffd (#1020)
* *(deps)* Update golang.org/x/oauth2 commit hash to ba495a6 (#1022)
* *(deps)* Update golang.org/x/image commit hash to 6944b10 (#1023)
* *(deps)* Update golang.org/x/sys commit hash to 6e78728 (#1024)
* *(deps)* Update golang.org/x/sys commit hash to b3129d9 (#1025)
* *(deps)* Update golang.org/x/sys commit hash to 611d5d6 (#1026)
* *(deps)* Update golang.org/x/sys commit hash to 39c9dd3 (#1027)
* *(deps)* Update golang.org/x/sys commit hash to a2f17f7 (#1028)
* *(deps)* Update golang.org/x/sys commit hash to 4dd7244 (#1029)
* *(deps)* Update golang.org/x/sys commit hash to ae416a5 (#1030)
* *(deps)* Update golang.org/x/sys commit hash to 7861aae (#1031)
* *(deps)* Update golang.org/x/oauth2 commit hash to d3ed0bb (#1032)
* *(deps)* Update module github.com/labstack/gommon to v0.3.1 (#1033)
* *(deps)* Update golang.org/x/sys commit hash to c75c477 (#1034)
* *(deps)* Update golang.org/x/sys commit hash to ebca88c (#1035)
* *(deps)* Update golang.org/x/sys commit hash to e0b2ad0 (#1037)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.3 (#1038)
* *(deps)* Update golang.org/x/crypto commit hash to ceb1ce7 (#1041)
* *(deps)* Update module github.com/lib/pq to v1.10.4 (#1040)
* *(deps)* Update golang.org/x/sys commit hash to 51b60fd (#1042)
* *(deps)* Update golang.org/x/sys commit hash to 99a5385 (#1043)
* *(deps)* Update golang.org/x/sys commit hash to f221eed (#1044)
* *(deps)* Update golang.org/x/sys commit hash to 0c823b9 (#1045)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.4 (#1046)
* *(deps)* Update golang.org/x/sys commit hash to 0a5406a (#1048)
* *(deps)* Update golang.org/x/crypto commit hash to b4de73f (#1047)
* *(deps)* Update module github.com/ulule/limiter/v3 to v3.9.0 (#1049)
* *(deps)* Update golang.org/x/crypto commit hash to ae814b3 (#1050)
* *(deps)* Update golang.org/x/sys commit hash to dee7805 (#1051)
* *(deps)* Update golang.org/x/sys commit hash to ef496fb (#1052)
* *(deps)* Update golang.org/x/sys commit hash to fe61309 (#1054)
* *(deps)* Update module github.com/swaggo/swag to v1.7.6 (#1055)
* *(deps)* Update golang.org/x/crypto commit hash to 5770296 (#1056)
* *(deps)* Update module github.com/golang-jwt/jwt/v4 to v4.2.0 (#1057)
* *(deps)* Update golang.org/x/sys commit hash to 94396e4 (#1058)
* *(deps)* Update golang.org/x/sys commit hash to 97ca703 (#1059)
* *(deps)* Update golang.org/x/crypto commit hash to 4570a08 (#1062)
* *(deps)* Update golang.org/x/sys commit hash to 798191b (#1061)
* *(deps)* Update golang.org/x/sys commit hash to af8b642 (#1063)
* *(deps)* Update module github.com/spf13/viper to v1.10.0 (#1064)
* *(deps)* Update golang.org/x/sys commit hash to 03aa0b5 (#1067)
* *(deps)* Update golang.org/x/sys commit hash to 3b038e5 (#1068)
* *(deps)* Update module github.com/spf13/cobra to v1.3.0 (#1070)
* *(deps)* Update golang.org/x/sys commit hash to 4825e8c (#1071)
* *(deps)* Update module github.com/spf13/viper to v1.10.1 (#1072)
* *(deps)* Update golang.org/x/crypto commit hash to e495a2d (#1073)
* *(deps)* Update golang.org/x/sys commit hash to 4abf325 (#1074)
* *(deps)* Update golang.org/x/sys commit hash to 1d35b9e (#1075)
* *(deps)* Update module github.com/magefile/mage to v1.12.0 (#1076)
* *(deps)* Update module github.com/magefile/mage to v1.12.1 (#1077)
* *(deps)* Update module github.com/getsentry/sentry-go to v0.12.0 (#1079)
* *(deps)* Update module github.com/swaggo/swag to v1.7.8 (#1080)
* *(deps)* Update module github.com/spf13/afero to v1.7.0 (#1078)
* *(deps)* Update module github.com/spf13/afero to v1.7.1 (#1081)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.10 (#1082)
* *(deps)* Update module github.com/spf13/afero to v1.8.0 (#1083)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.6.2 (#1084)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.6.3 (#1089)
* *(deps)* Update golang.org/x/sys commit hash to a018aaa (#1088)
* *(deps)* Update golang.org/x/sys commit hash to 5a964db (#1090)
* *(deps)* Update golang.org/x/crypto commit hash to 5e0467b (#1091)
* *(deps)* Update golang.org/x/sys commit hash to da31bd3 (#1093)
* *(deps)* Update module github.com/prometheus/client_golang to v1.12.0 (#1094)
* *(deps)* Update golang.org/x/crypto commit hash to e04a857 (#1097)
* *(deps)* Update golang.org/x/crypto commit hash to aa10faf (#1098)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.11 (#1099)
* *(deps)* Update golang.org/x/crypto commit hash to 198e437 (#1100)
* *(deps)* Update golang.org/x/sys commit hash to 99c3d69 (#1101)
* *(deps)* Update module github.com/prometheus/client_golang to v1.12.1 (#1102)
* *(deps)* Update klakegg/hugo docker tag to v0.92.0 (#1103)
* *(deps)* Update klakegg/hugo docker tag to v0.92.1 (#1104)
* *(deps)* Update golang.org/x/crypto commit hash to 30dcbda (#1105)
* *(deps)* Update module github.com/swaggo/swag to v1.7.9 (#1106)
* *(deps)* Update golang.org/x/sys commit hash to 1c1b9b1 (#1107)
* *(deps)* Update module github.com/spf13/afero to v1.8.1 (#1108)
* *(deps)* Update golang.org/x/sys commit hash to 5739886 (#1110)
* *(deps)* Update golang.org/x/crypto commit hash to 20e1d8d (#1111)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.5 (#1112)
* *(deps)* Update golang.org/x/crypto commit hash to bba287d (#1113)
* *(deps)* Update golang.org/x/crypto commit hash to dad3315 (#1114)
* *(deps)* Update module github.com/golang-jwt/jwt/v4 to v4.3.0 (#1117)
* *(deps)* Update golang.org/x/sys commit hash to 3681064 (#1116)
* *(deps)* Update golang.org/x/crypto commit hash to db63837 (#1115)
* *(deps)* Update golang.org/x/crypto commit hash to f4118a5 (#1118)
* *(deps)* Update golang.org/x/crypto commit hash to 8634188 (#1121)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.6 (#1122)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.7 (#1123)
* *(deps)* Update module github.com/swaggo/swag to v1.8.0 (#1124)
* *(deps)* Update golang.org/x/sys commit hash to 0005352 (#1125)
* *(deps)* Update golang.org/x/sys commit hash to f242548 (#1126)
* *(deps)* Update klakegg/hugo docker tag to v0.92.2 (#1127)
* *(deps)* Update golang.org/x/sys commit hash to dbe011f (#1129)
* *(deps)* Update golang.org/x/sys commit hash to 95c6836 (#1130)
* *(deps)* Update golang.org/x/oauth2 commit hash to ee48083 (#1128)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.12 (#1132)
* *(deps)* Update golang.org/x/sys commit hash to 4e6760a (#1131)
* *(deps)* Update golang.org/x/image commit hash to 723b81c (#1133)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.7.0 (#1134)
* *(deps)* Update klakegg/hugo docker tag to v0.93.0 (#1135)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.8 (#1136)
* *(deps)* Update klakegg/hugo docker tag to v0.93.2 (#1137)
* *(deps)* Update golang.org/x/sys commit hash to 22a9840 (#1138)
* *(deps)* Update golang.org/x/crypto commit hash to efcb850 (#1139)
* *(deps)* Update golang.org/x/oauth2 commit hash to 6242fa9 (#1140)
* *(deps)* Update golang.org/x/sys commit hash to b874c99 (#1141)
* *(deps)* Update klakegg/hugo docker tag to v0.93.3 (#1142)
* *(deps)* Update module github.com/labstack/echo/v4 to v4.7.1 (#1146)
* *(deps)* Update module github.com/stretchr/testify to v1.7.1 (#1148)
* *(deps)* Update module github.com/swaggo/swag to v1.8.1 (#1156)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.11 (#1143)
* *(deps)* Update module github.com/spf13/cobra to v1.4.0 (#1145)
* *(deps)* Update module github.com/lib/pq to v1.10.5 (#1157)
* *(deps)* Update module github.com/spf13/viper to v1.11.0 (#1159)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.12 (#1162)
* *(deps)* Update module github.com/prometheus/client_golang to v1.12.2 (#1166)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.13 (#1165)
* *(deps)* Update module github.com/coreos/go-oidc/v3 to v3.2.0 (#1164)
* *(deps)* Update module github.com/swaggo/swag to v1.8.2 (#1167)
* *(deps)* Update module github.com/lib/pq to v1.10.6 (#1169)
* *(deps)* Update module gopkg.in/yaml.v3 to v3.0.1 (#1179)
* *(deps)* Update module github.com/imdario/mergo to v0.3.13 (#1178)
* *(deps)* Update module github.com/stretchr/testify to v1.7.2 (#1182)
* *(deps)* Update module github.com/swaggo/swag to v1.8.3 (#1185)
* *(deps)* Update module github.com/spf13/cobra to v1.5.0 (#1192)
* *(deps)* Update module github.com/golang-jwt/jwt/v4 to v4.4.2 (#1193)
* *(deps)* Update module github.com/stretchr/testify to v1.8.0 (#1191)
* *(deps)* Update module github.com/go-testfixtures/testfixtures/v3 to v3.8.0 (#1168)
* *(deps)* Update module github.com/mattn/go-sqlite3 to v1.14.14 (#1194)
* *(deps)* Update golang.org/x/term digest to 065cf7b (#1207)
* *(deps)* Update golang.org/x/image digest to 41969df (#1203)
* *(deps)* Update module github.com/yuin/goldmark to v1.4.13 (#1209)
* *(deps)* Update golang.org/x/crypto digest to 0559593 (#1202)
* *(deps)* Update module github.com/spf13/afero to v1.9.0 (#1210)
* *(deps)* Update module github.com/gabriel-vasile/mimetype to v1.4.1 (#1208)
* *(deps)* Update golang.org/x/sync digest to 0de741c (#1205)
* *(deps)* Update github.com/c2h5oh/datasize digest to 859f65c (#1201)
* *(deps)* Update golang.org/x/oauth2 digest to 2104d58 (#1204)
* *(deps)* Update golang.org/x/sys digest to c0bba94 (#1206)
* *(deps)* Update golang.org/x/oauth2 digest to c8730f7 (#1214)
* *(deps)* Update module github.com/spf13/afero to v1.9.2 (#1215)
* *(deps)* Update module github.com/swaggo/swag to v1.8.4 (#1216)
* *(deps)* Update module github.com/spf13/viper to v1.12.0 (#1180)
* *(deps)* Update golang.org/x/sys digest to 1609e55 (#1217)
* *(deps)* Update module github.com/go-testfixtures/testfixtures/v3 to v3.8.1 (#1226)
* *(deps)* Update module go to 1.18 (#1225)
### Documentation
* Add docker-compose example with no proxy ([4255bc3](4255bc3a945b6fe4314e3cd3f62908dd1be1ff4a))
* Add another youtube tutorial ([dbd6f36](dbd6f36da6e56355993cc1411379997e26c88b36))
* Fix api url in docker examples without a proxy ([68998e9](68998e90a446569869fb150bd5fc0739f496b066))
* Make sure all links to vikunja pages are https ([cc612d5](cc612d505f22e5d895b6ebda61fe62498634cec5))
* Update backup instructions ([4829c89](4829c899400544ad27cacfb7d19b40988302a413))
* Add postgres to docker-compose examples ([2aea169](2aea1691cf33b7d9e03fbe2c711af7d8f76d9724))
* Improve development docs ([9bf32aa](9bf32aae99a7e69cce0cd4477e8fc8ddcaea25ea))
* Add another tutorial link ([1fa74cb](1fa74cba6407c2b694b14f8439f1492476433d62))
* Improve wording for systemd ([13561f2](13561f211493903b17c856b3010345ea9df725d4))
* Update testing ([da318e3](da318e3db15121ba864db8450a76ba9ed18b9fd5))
* Add guide for Synology NAS ([049ae39](049ae39c62079f77921b7a9fad5023b2c1c0c1c5))
### Features
* *(docs)* Add details of using NGINX Proxy Manager to the Reverse Proxy docs (#13)
* *(docs)* Add versions explanation
* *(mail)* Don't try to authenticate when no username and password was provided* Add better error logs for mage commands ([bb086eb](bb086eb9f87669f844c283d42ea9ca9f3f5a7877))
* Expose if task comments are enabled or not in /info ([ae8db17](ae8db176db57fa6176e00b87924f70352332ca66))
* Improve account deletion email grammar (#1006) ([dcb52c0](dcb52c00f1c6b3217e2b508d7799fc83adb3b055))
* Add more debug logging when deleting users ([8f55af0](8f55af07c936218487ec94e65c6673fbddd0cdb5))
* Don't require a password for data export from users authenticated with third-party auth ([9eca971](9eca971c938699d481915fb6e14c765aea1fa3b5))
* Expose if a user is a local user through its jwt token ([516c812](516c812043e77be7f834ae1326d13d39e156ef77))
* Expose if a user is a local user through the /user endpoint ([2683ef2](2683ef23d538eb846d5d799798fa82cca70dc017))
* Enable rate limit for unauthenticated routes ([093d0c6](093d0c65ca6338358dbd1df904daadd7808f2817))
* Use wallpaper topic for default unsplash background list ([88a2ced](88a2cede19f1844814530af948c3cc5a0b026419))
* Gravatar - Lowercase emails before MD5 hash (#10) ([36bf3d2](36bf3d216a7be28e917e2816a9e5da43439f2c20))
* Add marble avatar (#1060) ([73ee696](73ee696fc3cf941af2d2c2cf81224aa01f93234e))
* Save user language in the settings ([a98119f](a98119f2d670a11efab6008129b767f9208f8113))
* Add time zone setting for reminders (#1092) ([61d49c3](61d49c3a56a59e52ce407b858ddd4aa573dbee9d))
* Add long-lived api tokens (#1085) ([1322cb1](1322cb16d76a40ad90631e3e091da0f0d44957a9))
* Upgrade golangci-lint to 1.45.2 ([5cf263a](5cf263a86f954a38cbfafb6b0857bf591f82a811))
* Add date math for filters (#1086) ([0a1d8c9](0a1d8c940410b03a78016ac6110883ca05484816))
* Add migration to create BlurHash strings for all list backgrounds ([362706b](362706b38d52720b5a1615e185a985b7708168f7))
* Generate a BlurHash when uploading a new image ([f83b09a](f83b09af59ed25425a16824ccf48d903c81e861a))
* Save BlurHash from unsplash when selecting a photo from unsplash ([2ec7d7a](2ec7d7a8a85cc12c07d20cfab9b90a78a7857eb6))
* Return BlurHash for unsplash search results ([6df8658](6df865876df961f2bec476126bf6e7fbe5d43e0e))
* Add caldav tokens (#1065) ([e4b50e8](e4b50e84a44f809cc829c2fdb6f52b03b40a367b))
* Ability to serve static files (#1174) ([acaa850](acaa85083f2bebbc67608ae0f454ed5e9a3ef8a0))
* Restrict max avatar size ([2f25b48](2f25b48869f59256bf7d692c4486c64c30b85e5e))
* Send overdue tasks email notification at 9:00 in the user's time zone ([7eb3b96](7eb3b96a4465ca6648572b07c506c06f2c28c375))
* Add setting to change overdue tasks reminder email time ([8869adf](8869adfc276f674b686bf68f949d7efbb417e55b))
* Allow only the authors of task comments to edit them ([01271c4](01271c4c0111b3b040dcb9a0d502d31078ad6d4b))
* Migrate away from gomail ([30e0e98](30e0e98f7738e36698990523377f47edcbf6806c))
* Embed the vikunja logo as inline attachment ([f4f8450](f4f8450d166f1a836eea202dd0340d2156d3dfe9))
* Use embed fs directly to embed the logo in mails ([73c4c39](73c4c399e5d610bb713f1e9feab543e0425ee959))
* Use actual uuids for tasks ([62325de](62325de9cd5da5b70987081956a28e7baa907081))
* Add issue template ([117f6b3](117f6b38e1d35c09f2657975ea75dcfedcd8425d))
### Miscellaneous Tasks
* *(ci)* Use latest version of s3 plugin
* *(ci)* Sign drone config
* *(docs)* Update docs about compiling from source
* *(docs)* Redirect properly from /docs/docs
* *(docs)* Add new mailer option to docs
* *(docs)* Clarify openid setup with environment variables
* *(docs)* Add frontendurl to all example configs
* *(mage)* Don't set api packages when they are not used* Sign drone config ([1d8d0f1](1d8d0f140e4f2a59947167bd597e5f12b84b009d))
* Cleanup namespace creation ([b60c69c](b60c69c5a8c004a780b989cf0bb8ab6455086b0f))
* Generate swagger docs ([ba2bdff](ba2bdff39109db9ecc4b525e39e2642b41ac03b8))
* Go mod tidy ([726a517](726a517bec731f1af8e3186e280718fef02cadf7))
* Upgrade trello api wrapper and remove fork ([7e99618](7e99618319547c7e7dfa2cc063f654300f7074fb))
* Use our custom build image to build docker image ([251b877](251b877015761fdd2b8dbd18cd8ec696dc374103))
* Update golangci-lint ([430057a](430057a404b04e75c62a15693f479c6fc8e63189))
### Other
* *(other)* Healthcheck endpoint (#998)
* *(other)* Added the ability to configure the JWT expiry date using a new server.jwtttl config parameter. (#999)
* *(other)* Enable a list to be moved across namespaces (#1096)
* *(other)* A bunch of dependency updates at once (#1155)
* *(other)* Add client-cert parameters of the Go pq driver to the Vikunja config (#1161)
* *(other)* Add exec to run script to run app as PID 1 (#1200)
## [0.18.1] - 2021-09-08
### Fixed

View File

@ -1,29 +1,27 @@
##############
# Build stage
FROM golang:1-alpine3.12 AS build-env
FROM golang:1.18-alpine AS build-env
RUN apk --no-cache add build-base git && \
go install github.com/magefile/mage@latest && \
mv /go/bin/mage /usr/local/go/bin
ARG VIKUNJA_VERSION
ENV TAGS "sqlite"
ENV GO111MODULE=on
# Build deps
RUN apk --no-cache add build-base git
# Setup repo
COPY . ${GOPATH}/src/code.vikunja.io/api
WORKDIR ${GOPATH}/src/code.vikunja.io/api
COPY . /go/src/code.vikunja.io/api
WORKDIR /go/src/code.vikunja.io/api
# Checkout version if set
RUN if [ -n "${VIKUNJA_VERSION}" ]; then git checkout "${VIKUNJA_VERSION}"; fi \
&& go install github.com/magefile/mage \
&& mage build:clean build
###################
# The actual image
# Note: I wanted to use the scratch image here, but unfortunatly the go-sqlite bindings require cgo and
# because of this, the container would not start when I compiled the image without cgo.
FROM alpine:3.12
FROM alpine:3.16
LABEL maintainer="maintainers@vikunja.io"
WORKDIR /app/vikunja/
@ -39,7 +37,7 @@ RUN apk --no-cache add shadow && \
chown vikunja -R /app/vikunja
COPY run.sh /run.sh
# Fix time zone settings not working
# Add time zone data
RUN apk --no-cache add tzdata
# Files permissions

48
Dockerfile.arm32 Normal file
View File

@ -0,0 +1,48 @@
##############
# Build stage
FROM golang:1.18-buster AS build-env
RUN go install github.com/magefile/mage@latest && \
mv /go/bin/mage /usr/local/go/bin
ARG VIKUNJA_VERSION
# Setup repo
COPY . /go/src/code.vikunja.io/api
WORKDIR /go/src/code.vikunja.io/api
# Checkout version if set
RUN if [ -n "${VIKUNJA_VERSION}" ]; then git checkout "${VIKUNJA_VERSION}"; fi \
&& mage build:clean build
###################
# The actual image
# Note: I wanted to use the scratch image here, but unfortunatly the go-sqlite bindings require cgo and
# because of this, the container would not start when I compiled the image without cgo.
# We're using debian as a base image here because the latest alpine image does not work with arm.
FROM debian:buster-slim
LABEL maintainer="maintainers@vikunja.io"
WORKDIR /app/vikunja/
COPY --from=build-env /go/src/code.vikunja.io/api/vikunja .
ENV VIKUNJA_SERVICE_ROOTPATH=/app/vikunja/
# Dynamic permission changing stuff
ENV PUID 1000
ENV PGID 1000
RUN addgroup --gid ${PGID} vikunja && \
chown ${PUID} -R /app/vikunja && \
useradd --shell /bin/sh --gid vikunja --uid ${PUID} --home-dir /app/vikunja vikunja
COPY run.sh /run.sh
# Fix time zone settings not working
RUN apt-get update && apt-get install -y tzdata && apt-get clean
# Files permissions
RUN mkdir /app/vikunja/files && \
chown -R vikunja /app/vikunja/files
VOLUME /app/vikunja/files
CMD ["/run.sh"]
EXPOSE 3456

View File

@ -2,7 +2,7 @@
[![Build Status](https://drone.kolaente.de/api/badges/vikunja/api/status.svg)](https://drone.kolaente.de/vikunja/api)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](LICENSE)
[![Download](https://img.shields.io/badge/download-v0.18.1-brightgreen.svg)](https://dl.vikunja.io)
[![Download](https://img.shields.io/badge/download-v0.19.2-brightgreen.svg)](https://dl.vikunja.io)
[![Docker Pulls](https://img.shields.io/docker/pulls/vikunja/api.svg)](https://hub.docker.com/r/vikunja/api/)
[![Swagger Docs](https://img.shields.io/badge/swagger-docs-brightgreen.svg)](https://try.vikunja.io/api/v1/docs)
[![Go Report Card](https://goreportcard.com/badge/kolaente.dev/vikunja/api)](https://goreportcard.com/report/kolaente.dev/vikunja/api)
@ -56,6 +56,10 @@ See [the roadmap](https://my.vikunja.cloud/share/QFyzYEmEYfSyQfTOmIRSwLUpkFjboaB
Fork -> Push -> Pull-Request. Also see the [dev docs](https://vikunja.io/docs/development/) for more info.
## Sponsors
[![Relm](https://vikunja.io/images/sponsors/relm.png)](https://relm.us)
## License
This project is licensed under the AGPLv3 License. See the [LICENSE](LICENSE) file for the full license text.

59
cliff.toml Normal file
View File

@ -0,0 +1,59 @@
[changelog]
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits
| filter(attribute="scope")
| sort(attribute="scope") %}
* *({{commit.scope}})* {{ commit.message | upper_first }}
{%- if commit.breaking %}
{% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}}
{%- endif -%}
{%- endfor -%}
{%- for commit in commits %}
{%- if commit.scope -%}
{% else -%}
* {{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ commit.id }}))
{% if commit.breaking -%}
{% raw %} {% endraw %}- **BREAKING**: {{commit.breaking_description}}
{% endif -%}
{% endif -%}
{% endfor -%}
{% raw %}\n{% endraw %}\
{% endfor %}\n
"""
#{% for group, commits in commits | group_by(attribute="group") %}
# ### {{ group | upper_first }}
# {% for commit in commits %}\
# - {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }} ([{{ commit.id | truncate(length=7, end="") }}]({{ commit.id }}))
# {% endfor %}\
#{% endfor %}\n
# remove the leading and trailing whitespace from the template
trim = true
[git]
conventional_commits = true
filter_unconventional = false
commit_parsers = [
{ message = ".*(deps).*", group = "Dependencies"},
{ message = "^feat", group = "Features"},
{ message = "^fix", group = "Bug Fixes"},
{ message = "^doc", group = "Documentation"},
{ message = "^perf", group = "Performance"},
{ message = "^refactor", group = "Refactor"},
{ message = "^style", group = "Styling"},
{ message = "^test", group = "Testing"},
{ message = "^chore\\(release\\): prepare for", skip = true},
{ message = "^chore", group = "Miscellaneous Tasks"},
{ body = ".*security", group = "Security"},
{ message = ".*", group = "Other", default_scope = "other"}, # Everything that's not a conventional commit goes into the "Other" category
]

View File

@ -127,8 +127,11 @@ mailer:
enabled: false
# SMTP Host
host: ""
# SMTP Host port
# SMTP Host port.
# **NOTE:** If you're unable to send mail and the only error you see in the logs is an `EOF`, try setting the port to `25`.
port: 587
# SMTP Auth Type. Can be either `plain`, `login` or `cram-md5`.
authtype: "plain"
# SMTP username
username: "user"
# SMTP password
@ -299,6 +302,8 @@ auth:
enabled: false
# The url to redirect clients to. Defaults to the configured frontend url. If you're using Vikunja with the official
# frontend, you don't need to change this value.
# **Note:** The redirect url must exactly match the configured redirect url with the third party provider.
# This includes all slashes at the end or protocols.
redirecturl: <frontend url>
# A list of enabled providers
providers:

View File

@ -36,8 +36,9 @@ Make sure to check the other doc articles for specific development tasks like [t
## Frontend requirements
The code for the frontend is located at [code.vikunja.io/frontend](https://code.vikunja.io/frontend).
More instructions can be found in the repo's README.
You need to have yarn v1 and nodejs in version 16 installed.
You need to have [pnpm](https://pnpm.io/) and nodejs in version 16 or 18 installed.
## Git flow

View File

@ -98,12 +98,12 @@ Check out the docs [in the frontend repo](https://kolaente.dev/vikunja/frontend/
To run the frontend unit tests, run
{{< highlight bash >}}
yarn test:unit
pnpm test:unit
{{< /highlight >}}
The frontend also has a watcher available that re-runs all unit tests every time you change something.
To use it, simply run
{{< highlight bash >}}
yarn test:unit-watch
pnpm test:unit-watch
{{< /highlight >}}

View File

@ -38,9 +38,7 @@ More options are available, please refer to the [magefile docs]({{< ref "../deve
The code for the frontend is located at [code.vikunja.io/frontend](https://code.vikunja.io/frontend).
You need to have yarn v1 and nodejs in version 16 installed.
1. Make sure [yarn v1](https://yarnpkg.com/getting-started/install) is properly installed on your system.
3. Clone the repo with `git clone https://code.vikunja.io/frontend` and switch into the directory.
3. Install all dependencies with `yarn install`
4. Build the frontend with `yarn build`. This will result in a js bundle in the `dist/` folder which you can deploy.
1. Make sure you have [pnpm](https://pnpm.io/) properly installed on your system.
2. Clone the repo with `git clone https://code.vikunja.io/frontend` and switch into the directory.
3. Install all dependencies with `pnpm install`
4. Build the frontend with `pnpm build`. This will result in a static js bundle in the `dist/` folder which you can deploy.

View File

@ -10,8 +10,9 @@ menu:
# Configuration options
You can either use a `config.yml` file in the root directory of vikunja or set all config option with
You can either use a `config.yml` file in the root directory of vikunja or set almost all config option with
environment variables. If you have both, the value set in the config file is used.
Right now it is not possible to configure openid authentication via environment variables.
Variables are nested in the `config.yml`, these nested variables become `VIKUNJA_FIRST_CHILD` when configuring via
environment variables. So setting
@ -656,7 +657,8 @@ Environment path: `VIKUNJA_MAILER_HOST`
### port
SMTP Host port
SMTP Host port.
**NOTE:** If you're unable to send mail and the only error you see in the logs is an `EOF`, try setting the port to `25`.
Default: `587`
@ -665,6 +667,17 @@ Full path: `mailer.port`
Environment path: `VIKUNJA_MAILER_PORT`
### authtype
SMTP Auth Type. Can be either `plain`, `login` or `cram-md5`.
Default: `plain`
Full path: `mailer.authtype`
Environment path: `VIKUNJA_MAILER_AUTHTYPE`
### username
SMTP username

View File

@ -50,6 +50,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
volumes:
- ./files:/app/vikunja/files
depends_on:

View File

@ -103,6 +103,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: http://<your public frontend url with slash>/
ports:
- 3456:3456
volumes:
@ -141,6 +143,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
volumes:
- ./files:/app/vikunja/files
networks:
@ -199,6 +203,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
volumes:
- ./files:/app/vikunja/files
networks:
@ -292,6 +298,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
volumes:
- ./files:/app/vikunja/files
depends_on:
@ -350,6 +358,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
volumes:
- ./files:/app/vikunja/files
depends_on:
@ -379,7 +389,7 @@ you can prepare 2 proxy rules:
* a redirection rule for vikunja's api (see example screenshot using port 3456)
* a similar redirection rule for vikunja's frontend (using port 4321)
![Synology Proxy Settings](/synology-proxy-1.png)
![Synology Proxy Settings](/docs/synology-proxy-1.png)
You should also add 2 empty folders for mariadb and vikunja inside Synology's
docker main folders:
@ -399,7 +409,7 @@ To do that, you can
2. Give it the name Vikunja and paste the adapted docker compose file
3. Deploy the Stack with the "Delpoy Stack" button:
![Portainer Stack deploy](/synology-proxy-2.png)
![Portainer Stack deploy](/docs/synology-proxy-2.png)
The docker-compose file we're going to use is very similar to the [example without any proxy](#example-without-any-proxy) above:
@ -426,6 +436,8 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <a super secure random secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
ports:
- 3456:3456
volumes:

View File

@ -149,6 +149,7 @@ services:
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_SERVICE_JWTSECRET: <generated secret>
VIKUNJA_SERVICE_FRONTENDURL: https://<your public frontend url with slash>/
volumes:
- ./files:/app/vikunja/files
db:

View File

@ -11,16 +11,20 @@ menu:
# Installing
Vikunja consists of two parts: [Backend](https://code.vikunja.io/api) and [frontend](https://code.vikunja.io/frontend).
While the backend is required, the frontend is not.
You don't neccesarily need to have a web-frontend, using Vikunja via the [mobile app](https://code.vikunja.io/app) is totally fine.
Vikunja consists of two parts: [API](https://code.vikunja.io/api) and [frontend](https://code.vikunja.io/frontend).
However, using the web frontend is highly reccommended.
You will always need to install at least the API.
To actually use Vikunja you'll also need to somehow install a frontend to use it.
You can either:
Vikunja can be installed in various forms.
* [Install the web frontend]({{< ref "install-frontend.md">}})
* Use the desktop app, which is essentially a web frontend packaged for easy installation on desktop devices
* Use the mobile app only, but as of right now it only supports the very basic features of Vikunja
Vikunja can be installed in various ways.
This document provides an overview and instructions for the different methods.
* [Backend]({{< ref "install-backend.md">}})
* [API]({{< ref "install-backend.md">}})
* [Installing from binary]({{< ref "install-backend.md#install-from-binary">}})
* [Verify the GPG signature]({{< ref "install-backend.md#verify-the-gpg-signature">}})
* [Set it up]({{< ref "install-backend.md#set-it-up">}})

View File

@ -0,0 +1,15 @@
---
title: "Hosting Vikunja with k8s"
date: 2022-08-12T13:41:48+02:00
draft: false
type: "doc"
menu:
sidebar:
parent: "setup"
---
There are two third-party Helm-Charts which can be used to host Vikunja with k8s:
* [Truecharts](https://truecharts.org/docs/charts/stable/vikunja/)
* [k8s at Home](https://github.com/k8s-at-home/charts)

View File

@ -0,0 +1,45 @@
---
date: "2022-08-09:00:00+02:00"
title: "OpenID example configurations"
draft: false
type: "doc"
menu:
sidebar:
parent: "setup"
---
# OpenID example configurations
On this page you will find examples about how to set up Vikunja with a third-party OpenID provider.
To add another example, please [edit this document](https://kolaente.dev/vikunja/api/src/branch/main/docs/content/doc/setup/openid-examples.md) and send a PR.
{{< table_of_contents >}}
## Authelia
Vikunja Config:
```yaml
openid:
enabled: true
redirecturl: https://vikunja.mydomain.com/auth/openid/ <---- slash at the end is important
providers:
- name: Authelia
authurl: https://login.mydomain.com
clientid: <vikunja-id>
clientsecret: <vikunja secret>
```
Authelia config:
```yaml
- id: <vikunja-id>
description: Vikunja
secret: <vikunja secret>
redirect_uris:
- https://vikunja.mydomain.com/auth/openid/authelia
scopes:
- openid
- email
- profile
```

View File

@ -0,0 +1,39 @@
---
title: "Running Vikunja in a subdirectory"
date: 2022-09-23T12:15:04+02:00
draft: false
menu:
sidebar:
parent: "setup"
---
# Running Vikunja in a subdirectory
Running Vikunja in a subdirectory is not supported out of the box.
However, you can still run it in a subdirectory but need to build the frontend yourself.
## Frontend
First, make sure you're able to build the frontend from source.
Check [the guide about building from source]({{< ref "build-from-source.md">}}#frontend) about that.
Then, run
```
pnpm vite build --base=/SUBPATH
pnpm workbox copyLibraries dist/
```
Where `SUBPATH` is the subdirectory you want to run Vikunja on.
Once you have the build files you can deploy them as usual.
Note that when deploying in docker you'll need to put the files in a web container yourself, you
can't use the `Dockerfile` in the repo without modifications.
## API
If you're not using a reverse proxy you're good to go.
Simply configure the api url in the frontend as you normally would.
If you're using a reverse proxy you'll need to adjust the paths so that the api is available at `/SUBPATH/api/v1`.
You can check if everything is working correctly by opening `/SUBPATH/api/v1/info` in a browser.

View File

@ -0,0 +1,45 @@
---
date: "2022-07-07:00:00+02:00"
title: "Versions"
draft: false
type: "doc"
menu:
sidebar:
parent: "setup"
---
# Vikunja Versions
The Vikunja api and frontend are available in two different release flavors.
{{< table_of_contents >}}
## Stable
Stable releases have a fixed version number like `0.18.2` and are published at irregular intervals whenever a new version is ready.
They receive few bugfixes and security patches.
We use [Semantic Versioning](#) for these releases.
## Unstable
Unstable versions are build every time a PR is merged or a commit to the main development branch is made.
As such, they contain the current development code and are more likely to have bugs.
There might be multiple new such builds a day.
Versions contain the last stable version, the number of commits since then and the commit the currently running binary was built from.
They look like this: `v0.18.1+269-5cc4927b9e`
The demo instance at [try.vikunja.io](https://try.vikunja.io) automatically updates and always runs the last unstable build.
## Switching between versions
First you should create a backup of your current setup!
Switching between versions is the same process as [upgrading]({{< ref install-backend.md >}}#updating).
Simply replace the stable binary with an unstable one or vice-versa.
For installations using docker, it is as simple as using the `unstable` or `latest` tag to switch between versions.
**Note:** While switching from stable to unstable should work without any problem, switching back might work but is not recommended and might break your instance.
To switch from unstable back to stable the best way is to wait for the next stable release after the used unstable build and then upgrade to that.

View File

@ -4,8 +4,8 @@ title: "Errors"
draft: false
type: "doc"
menu:
sidebar:
parent: "usage"
sidebar:
parent: "usage"
---
# Errors
@ -52,14 +52,16 @@ This document describes the different errors Vikunja can return.
## List
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 3001 | 404 | The list does not exist. |
| 3004 | 403 | The user needs to have read permissions on that list to perform that action. |
| 3005 | 400 | The list title cannot be empty. |
| 3006 | 404 | The list share does not exist. |
| 3007 | 400 | A list with this identifier already exists. |
| 3008 | 412 | The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list. |
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------------------------------------------------------------------------------------------------------------------------|
| 3001 | 404 | The list does not exist. |
| 3004 | 403 | The user needs to have read permissions on that list to perform that action. |
| 3005 | 400 | The list title cannot be empty. |
| 3006 | 404 | The list share does not exist. |
| 3007 | 400 | A list with this identifier already exists. |
| 3008 | 412 | The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list. |
| 3009 | 412 | The list cannot belong to a dynamically generated namespace like "Favorites". |
| 3010 | 412 | The list must belong to a namespace. |
## Task

129
go.mod
View File

@ -20,66 +20,135 @@ require (
code.vikunja.io/web v0.0.0-20210706160506-d85def955bd3
gitea.com/xorm/xorm-redis-cache v0.2.0
github.com/ThreeDotsLabs/watermill v1.1.1
github.com/adlio/trello v1.9.0
github.com/adlio/trello v1.10.0
github.com/arran4/golang-ical v0.0.0-20220517104411-fd89fefb0182
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
github.com/bbrks/go-blurhash v1.1.1
github.com/beevik/etree v1.1.0 // indirect
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2
github.com/coreos/go-oidc/v3 v3.2.0
github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b
github.com/coreos/go-oidc/v3 v3.4.0
github.com/cweill/gotests v1.6.0
github.com/d4l3k/messagediff v1.2.1
github.com/disintegration/imaging v1.6.2
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
github.com/gabriel-vasile/mimetype v1.4.0
github.com/gabriel-vasile/mimetype v1.4.1
github.com/getsentry/sentry-go v0.13.0
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.6.0
github.com/go-testfixtures/testfixtures/v3 v3.6.1
github.com/go-testfixtures/testfixtures/v3 v3.8.1
github.com/golang-jwt/jwt/v4 v4.4.2
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.3.0
github.com/iancoleman/strcase v0.2.0
github.com/imdario/mergo v0.3.13
github.com/labstack/echo/v4 v4.7.2
github.com/jinzhu/copier v0.3.5
github.com/labstack/echo/v4 v4.9.0
github.com/labstack/gommon v0.3.1
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef
github.com/lib/pq v1.10.6
github.com/lib/pq v1.10.7
github.com/magefile/mage v1.13.0
github.com/mattn/go-sqlite3 v1.14.13
github.com/mattn/go-sqlite3 v1.14.15
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/prometheus/client_golang v1.12.2
github.com/prometheus/client_golang v1.13.0
github.com/robfig/cron/v3 v3.0.1
github.com/samedi/caldav-go v3.0.0+incompatible
github.com/spf13/afero v1.8.2
github.com/spf13/afero v1.9.2
github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.11.0
github.com/spf13/viper v1.13.0
github.com/stretchr/testify v1.8.0
github.com/swaggo/swag v1.8.3
github.com/swaggo/swag v1.8.4
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/yuin/goldmark v1.4.12
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/image v0.0.0-20220302094943-723b81ca9867
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
github.com/wneessen/go-mail v0.2.6
github.com/yuin/goldmark v1.4.13
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
golang.org/x/image v0.0.0-20220902085622-e7cb96979f69
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
golang.org/x/term v0.0.0-20220919170432-7a66f970e087
gopkg.in/d4l3k/messagediff.v1 v1.2.1
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/yaml.v3 v3.0.1
src.techknowlogick.com/xgo v1.4.1-0.20210311222705-d25c33fcd864
src.techknowlogick.com/xgo v1.5.1-0.20220906164532-735bfdfb90d9
src.techknowlogick.com/xormigrate v1.4.0
xorm.io/builder v0.3.9
xorm.io/xorm v1.1.2
xorm.io/builder v0.3.12
xorm.io/xorm v1.3.2
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beevik/etree v1.1.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/garyburd/redigo v1.6.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-chi/chi v4.0.2+incompatible // indirect
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef // indirect
github.com/lithammer/shortuuid/v3 v3.0.4 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
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
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220927171203-f486391704dc // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
replace (
github.com/adlio/trello => github.com/kolaente/trello v1.7.1-0.20201216234312-5c4ef79b531e
github.com/coreos/bbolt => go.etcd.io/bbolt v1.3.4
github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 v22.0.0
github.com/hpcloud/tail => github.com/jeffbean/tail v1.0.1 // See https://github.com/hpcloud/tail/pull/159
@ -87,4 +156,4 @@ replace (
gopkg.in/fsnotify.v1 => github.com/kolaente/fsnotify v1.4.10-0.20200411160148-1bc3c8ff4048 // See https://github.com/fsnotify/fsnotify/issues/328 and https://github.com/golang/go/issues/26904
)
go 1.15
go 1.19

715
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -79,8 +79,10 @@ func runCmdWithOutput(name string, arg ...string) (output []byte, err error) {
cmd := exec.Command(name, arg...)
output, err = cmd.Output()
if err != nil {
ee := err.(*exec.ExitError)
return nil, fmt.Errorf("error running command: %s, %s", string(ee.Stderr), err)
if ee, is := err.(*exec.ExitError); is {
return nil, fmt.Errorf("error running command: %s, %s", string(ee.Stderr), err)
}
return nil, fmt.Errorf("error running command: %s", err)
}
return output, nil
@ -350,7 +352,7 @@ func (Test) Unit() {
mg.Deps(initVars)
setApiPackages()
// We run everything sequentially and not in parallel to prevent issues with real test databases
args := append([]string{"test", Goflags[0], "-p", "1", "-coverprofile", "cover.out", "-timeout", "20m"}, ApiPackages...)
args := append([]string{"test", Goflags[0], "-p", "1", "-coverprofile", "cover.out", "-timeout", "45m"}, ApiPackages...)
runAndStreamOutput("go", args...)
}
@ -365,7 +367,7 @@ func (Test) Coverage() {
func (Test) Integration() {
mg.Deps(initVars)
// We run everything sequentially and not in parallel to prevent issues with real test databases
runAndStreamOutput("go", "test", Goflags[0], "-p", "1", "-timeout", "20m", PACKAGE+"/pkg/integrations")
runAndStreamOutput("go", "test", Goflags[0], "-p", "1", "-timeout", "45m", PACKAGE+"/pkg/integrations")
}
type Check mg.Namespace
@ -404,7 +406,7 @@ func checkGolangCiLintInstalled() {
mg.Deps(initVars)
if err := exec.Command("golangci-lint").Run(); err != nil && strings.Contains(err.Error(), "executable file not found") {
fmt.Println("Please manually install golangci-lint by running")
fmt.Println("curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.31.0")
fmt.Println("curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.47.3")
os.Exit(1)
}
}
@ -557,7 +559,9 @@ func (Release) Compress(ctx context.Context) error {
return nil
}
// No mips or s390x for you today
if strings.Contains(info.Name(), "mips") || strings.Contains(info.Name(), "s390x") {
if strings.Contains(info.Name(), "mips") ||
strings.Contains(info.Name(), "s390x") ||
strings.Contains(info.Name(), "riscv64") { // not supported by upx
return nil
}

View File

@ -17,7 +17,6 @@
package caldav
import (
"fmt"
"regexp"
"strconv"
"strings"
@ -150,6 +149,15 @@ END:VCALENDAR` // Need a line break
return
}
func formatDuration(duration time.Duration) string {
seconds := duration.Seconds() - duration.Minutes()*60
minutes := duration.Minutes() - duration.Hours()*60
return strconv.FormatFloat(duration.Hours(), 'f', 0, 64) + `H` +
strconv.FormatFloat(minutes, 'f', 0, 64) + `M` +
strconv.FormatFloat(seconds, 'f', 0, 64) + `S`
}
// ParseTodos returns a caldav vcalendar string with todos
func ParseTodos(config *Config, todos []*Todo) (caldavtodos string) {
caldavtodos = `BEGIN:VCALENDAR
@ -172,11 +180,15 @@ SUMMARY:` + t.Summary + getCaldavColor(t.Color)
if t.Start.Unix() > 0 {
caldavtodos += `
DTSTART: ` + makeCalDavTimeFromTimeStamp(t.Start)
DTSTART:` + makeCalDavTimeFromTimeStamp(t.Start)
if t.Duration != 0 && t.DueDate.Unix() == 0 {
caldavtodos += `
DURATION:PT` + formatDuration(t.Duration)
}
}
if t.End.Unix() > 0 {
caldavtodos += `
DTEND: ` + makeCalDavTimeFromTimeStamp(t.End)
DTEND:` + makeCalDavTimeFromTimeStamp(t.End)
}
if t.Description != "" {
re := regexp.MustCompile(`\r?\n`)
@ -209,11 +221,6 @@ DUE:` + makeCalDavTimeFromTimeStamp(t.DueDate)
CREATED:` + makeCalDavTimeFromTimeStamp(t.Created)
}
if t.Duration != 0 {
caldavtodos += `
DURATION:PT` + fmt.Sprintf("%.6f", t.Duration.Hours()) + `H` + fmt.Sprintf("%.6f", t.Duration.Minutes()) + `M` + fmt.Sprintf("%.6f", t.Duration.Seconds()) + `S`
}
if t.Priority != 0 {
caldavtodos += `
PRIORITY:` + strconv.Itoa(mapPriorityToCaldav(t.Priority))

View File

@ -23,7 +23,8 @@ import (
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"github.com/laurent22/ical-go"
ics "github.com/arran4/golang-ical"
)
func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*models.TaskWithComments) string {
@ -60,21 +61,15 @@ func GetCaldavTodosForTasks(list *models.ListWithTasksAndBuckets, listTasks []*m
}
func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) {
parsed, err := ical.ParseCalendar(content)
parsed, err := ics.ParseCalendar(strings.NewReader(content))
if err != nil {
return nil, err
}
// We put the task details in a map to be able to handle them more easily
task := make(map[string]string)
for _, c := range parsed.Children {
if c.Name == "VTODO" {
for _, entry := range c.Children {
task[entry.Name] = entry.Value
}
// Breaking, to only process the first task
break
}
for _, c := range parsed.Components[0].UnknownPropertiesIANAProperties() {
task[c.IANAToken] = c.Value
}
// Parse the priority
@ -91,10 +86,13 @@ func ParseTaskFromVTODO(content string) (vTask *models.Task, err error) {
// Parse the enddate
duration, _ := time.ParseDuration(task["DURATION"])
description := strings.ReplaceAll(task["DESCRIPTION"], "\\,", ",")
description = strings.ReplaceAll(description, "\\n", "\n")
vTask = &models.Task{
UID: task["UID"],
Title: task["SUMMARY"],
Description: task["DESCRIPTION"],
Description: description,
Priority: priority,
DueDate: caldavTimeToTimestamp(task["DUE"]),
Updated: caldavTimeToTimestamp(task["DTSTAMP"]),
@ -125,6 +123,10 @@ func caldavTimeToTimestamp(tstring string) time.Time {
format = `20060102T150405Z`
}
if len(tstring) == 8 {
format = `20060102`
}
t, err := time.Parse(format, tstring)
if err != nil {
log.Warningf("Error while parsing caldav time %s to TimeStamp: %s", tstring, err)

View File

@ -96,6 +96,7 @@ const (
MailerPort Key = `mailer.port`
MailerUsername Key = `mailer.username`
MailerPassword Key = `mailer.password`
MailerAuthType Key = `mailer.authtype`
MailerSkipTLSVerify Key = `mailer.skiptlsverify`
MailerFromEmail Key = `mailer.fromemail`
MailerQueuelength Key = `mailer.queuelength`
@ -318,13 +319,14 @@ func InitDefaultConfig() {
MailerEnabled.setDefault(false)
MailerHost.setDefault("")
MailerPort.setDefault("587")
MailerUsername.setDefault("user")
MailerUsername.setDefault("")
MailerPassword.setDefault("")
MailerSkipTLSVerify.setDefault(false)
MailerFromEmail.setDefault("mail@vikunja")
MailerQueuelength.setDefault(100)
MailerQueueTimeout.setDefault(30)
MailerForceSSL.setDefault(false)
MailerAuthType.setDefault("plain")
// Redis
RedisEnabled.setDefault(false)
RedisHost.setDefault("localhost:6379")

View File

@ -19,7 +19,6 @@ package db
import (
"encoding/gob"
"fmt"
"net/url"
"os"
"strconv"
"strings"
@ -153,8 +152,8 @@ func initPostgresEngine() (engine *xorm.Engine, err error) {
connStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s sslcert=%s sslkey=%s sslrootcert=%s",
host,
port,
url.PathEscape(config.DatabaseUser.GetString()),
url.PathEscape(config.DatabasePassword.GetString()),
config.DatabaseUser.GetString(),
config.DatabasePassword.GetString(),
config.DatabaseDatabase.GetString(),
config.DatabaseSslMode.GetString(),
config.DatabaseSslCert.GetString(),

View File

@ -19,6 +19,8 @@ package db
import (
"encoding/json"
"code.vikunja.io/api/pkg/log"
"xorm.io/xorm/schemas"
)
@ -57,6 +59,15 @@ func Restore(table string, contents []map[string]interface{}) (err error) {
}
}
if Type() == schemas.POSTGRES {
idSequence := table + "_id_seq"
_, err = x.Query("SELECT setval('" + idSequence + "', COALESCE(MAX(id), 1) )")
if err != nil {
log.Warningf("Could not reset id sequence for %s: %s", idSequence, err)
err = nil
}
}
return
}

View File

@ -227,7 +227,7 @@ func TestArchived(t *testing.T) {
assertHandlerErrorCode(t, err, models.ErrCodeListIsArchived)
})
t.Run("unarchivable", func(t *testing.T) {
rec, err := testListHandler.testUpdateWithUser(nil, map[string]string{"list": "22"}, `{"title":"LoremIpsum","is_archived":false}`)
rec, err := testListHandler.testUpdateWithUser(nil, map[string]string{"list": "22"}, `{"title":"LoremIpsum","is_archived":false,"namespace_id":1}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"is_archived":false`)
})

View File

@ -232,12 +232,12 @@ func TestLinkSharing(t *testing.T) {
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
})
t.Run("Shared write", func(t *testing.T) {
rec, err := testHandlerListWrite.testUpdateWithLinkShare(nil, map[string]string{"list": "2"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandlerListWrite.testUpdateWithLinkShare(nil, map[string]string{"list": "2"}, `{"title":"TestLoremIpsum","namespace_id":1}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
t.Run("Shared admin", func(t *testing.T) {
rec, err := testHandlerListAdmin.testUpdateWithLinkShare(nil, map[string]string{"list": "3"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandlerListAdmin.testUpdateWithLinkShare(nil, map[string]string{"list": "3"}, `{"title":"TestLoremIpsum","namespace_id":2}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})

View File

@ -171,7 +171,7 @@ func TestList(t *testing.T) {
t.Run("Update", func(t *testing.T) {
t.Run("Normal", func(t *testing.T) {
// Check the list was loaded successfully afterwards, see testReadOneWithUser
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "1"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "1"}, `{"title":"TestLoremIpsum","namespace_id":1}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
// The description should not be updated but returned correctly
@ -183,7 +183,7 @@ func TestList(t *testing.T) {
assertHandlerErrorCode(t, err, models.ErrCodeListDoesNotExist)
})
t.Run("Normal with updating the description", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "1"}, `{"title":"TestLoremIpsum","description":"Lorem Ipsum dolor sit amet"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "1"}, `{"title":"TestLoremIpsum","description":"Lorem Ipsum dolor sit amet","namespace_id":1}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
assert.Contains(t, rec.Body.String(), `"description":"Lorem Ipsum dolor sit amet`)
@ -211,12 +211,12 @@ func TestList(t *testing.T) {
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
})
t.Run("Shared Via Team write", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "7"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "7"}, `{"title":"TestLoremIpsum","namespace_id":6}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
t.Run("Shared Via Team admin", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "8"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "8"}, `{"title":"TestLoremIpsum","namespace_id":6}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
@ -227,12 +227,12 @@ func TestList(t *testing.T) {
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
})
t.Run("Shared Via User write", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "10"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "10"}, `{"title":"TestLoremIpsum","namespace_id":6}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
t.Run("Shared Via User admin", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "11"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "11"}, `{"title":"TestLoremIpsum","namespace_id":6}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
@ -243,12 +243,12 @@ func TestList(t *testing.T) {
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
})
t.Run("Shared Via NamespaceTeam write", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "13"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "13"}, `{"title":"TestLoremIpsum","namespace_id":8}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
t.Run("Shared Via NamespaceTeam admin", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "14"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "14"}, `{"title":"TestLoremIpsum","namespace_id":9}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
@ -259,12 +259,12 @@ func TestList(t *testing.T) {
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
})
t.Run("Shared Via NamespaceUser write", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "16"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "16"}, `{"title":"TestLoremIpsum","namespace_id":11}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})
t.Run("Shared Via NamespaceUser admin", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "17"}, `{"title":"TestLoremIpsum"}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"list": "17"}, `{"title":"TestLoremIpsum","namespace_id":12}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"title":"TestLoremIpsum"`)
})

View File

@ -17,31 +17,68 @@
package mail
import (
"context"
"crypto/tls"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"gopkg.in/gomail.v2"
"github.com/wneessen/go-mail"
)
// Queue is the mail queue
var Queue chan *gomail.Message
var Queue chan *mail.Msg
func getDialer() *gomail.Dialer {
d := gomail.NewDialer(config.MailerHost.GetString(), config.MailerPort.GetInt(), config.MailerUsername.GetString(), config.MailerPassword.GetString())
// #nosec
d.TLSConfig = &tls.Config{
InsecureSkipVerify: config.MailerSkipTLSVerify.GetBool(),
ServerName: config.MailerHost.GetString(),
func getClient() (*mail.Client, error) {
var authType mail.SMTPAuthType
switch config.MailerAuthType.GetString() {
case "plain":
authType = mail.SMTPAuthPlain
case "login":
authType = mail.SMTPAuthLogin
case "cram-md5":
authType = mail.SMTPAuthCramMD5
}
d.SSL = config.MailerForceSSL.GetBool()
return d
tlsPolicy := mail.TLSOpportunistic
if config.MailerForceSSL.GetBool() {
tlsPolicy = mail.TLSMandatory
}
opts := []mail.Option{
mail.WithPort(config.MailerPort.GetInt()),
mail.WithTLSPolicy(tlsPolicy),
//#nosec G402
mail.WithTLSConfig(&tls.Config{
InsecureSkipVerify: config.MailerSkipTLSVerify.GetBool(),
ServerName: config.MailerHost.GetString(),
}),
mail.WithTimeout((config.MailerQueueTimeout.GetDuration() + 3) * time.Second), // 3s more for us to close before mail server timeout
}
if config.MailerUsername.GetString() != "" && config.MailerPassword.GetString() != "" {
opts = append(opts, mail.WithSMTPAuth(authType))
}
if config.MailerUsername.GetString() != "" {
opts = append(opts, mail.WithUsername(config.MailerUsername.GetString()))
}
if config.MailerPassword.GetString() != "" {
opts = append(opts, mail.WithPassword(config.MailerPassword.GetString()))
}
return mail.NewClient(
config.MailerHost.GetString(),
opts...,
)
}
// StartMailDaemon starts the mail daemon
func StartMailDaemon() {
Queue = make(chan *gomail.Message, config.MailerQueuelength.GetInt())
Queue = make(chan *mail.Msg, config.MailerQueuelength.GetInt())
if !config.MailerEnabled.GetBool() {
return
@ -52,10 +89,12 @@ func StartMailDaemon() {
return
}
c, err := getClient()
if err != nil {
log.Errorf("Could not create mail client: %v", err)
return
}
go func() {
d := getDialer()
var s gomail.SendCloser
var err error
open := false
for {
@ -65,14 +104,16 @@ func StartMailDaemon() {
return
}
if !open {
if s, err = d.Dial(); err != nil {
log.Error("Error during connect to smtp server: %s", err)
err = c.DialWithContext(context.Background())
if err != nil {
log.Errorf("Error during connect to smtp server: %s", err)
break
}
open = true
}
if err := gomail.Send(s, m); err != nil {
log.Error("Error when sending mail: %s", err)
err = c.Send(m)
if err != nil {
log.Errorf("Error when sending mail: %s", err)
break
}
// Close the connection to the SMTP server if no email was sent in
@ -80,18 +121,14 @@ func StartMailDaemon() {
case <-time.After(config.MailerQueueTimeout.GetDuration() * time.Second):
if open {
open = false
if err := s.Close(); err != nil {
log.Error("Error closing the mail server connection: %s\n", err)
err = c.Close()
if err != nil {
log.Errorf("Error closing the mail server connection: %s\n", err)
break
}
log.Infof("Closed connection to mailserver")
log.Info("Closed connection to mail server")
}
}
}
}()
}
// StopMailDaemon closes the mail queue channel, aka stops the daemon
func StopMailDaemon() {
close(Queue)
}

View File

@ -17,9 +17,14 @@
package mail
import (
"embed"
"io"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"gopkg.in/gomail.v2"
"code.vikunja.io/api/pkg/version"
"github.com/wneessen/go-mail"
)
// Opts holds infos for a mail
@ -32,6 +37,8 @@ type Opts struct {
ContentType ContentType
Boundary string
Headers []*header
Embeds map[string]io.Reader
EmbedFS map[string]*embed.FS
}
// ContentType represents mail content types
@ -45,11 +52,11 @@ const (
)
type header struct {
Field string
Field mail.Header
Content string
}
// SendTestMail sends a test mail to a receipient.
// SendTestMail sends a test mail to a recipient.
// It works without a queue.
func SendTestMail(opts *Opts) error {
if config.MailerHost.GetString() == "" {
@ -57,39 +64,51 @@ func SendTestMail(opts *Opts) error {
return nil
}
d := getDialer()
s, err := d.Dial()
c, err := getClient()
if err != nil {
return err
}
defer s.Close()
m := sendMail(opts)
m := getMessage(opts)
return gomail.Send(s, m)
return c.DialAndSend(m)
}
func sendMail(opts *Opts) *gomail.Message {
m := gomail.NewMessage()
func getMessage(opts *Opts) *mail.Msg {
m := mail.NewMsg()
m.SetUserAgent("Vikunja " + version.Version)
if opts.From == "" {
opts.From = "Vikunja <" + config.MailerFromEmail.GetString() + ">"
}
m.SetHeader("From", opts.From)
m.SetHeader("To", opts.To)
m.SetHeader("Subject", opts.Subject)
_ = m.From(opts.From)
_ = m.To(opts.To)
m.Subject(opts.Subject)
for _, h := range opts.Headers {
m.SetHeader(h.Field, h.Content)
}
for name, content := range opts.Embeds {
m.EmbedReader(name, content)
}
for name, fs := range opts.EmbedFS {
err := m.EmbedFromEmbedFS(name, fs)
if err != nil {
log.Errorf("Error embedding %s via embed.FS into mail: %v", err)
}
}
switch opts.ContentType {
case ContentTypePlain:
m.SetBody("text/plain", opts.Message)
m.SetBodyString("text/plain", opts.Message)
case ContentTypeHTML:
m.SetBody("text/html", opts.Message)
m.SetBodyString("text/html", opts.Message)
case ContentTypeMultipart:
m.SetBody("text/plain", opts.Message)
m.AddAlternative("text/html", opts.HTMLMessage)
m.SetBodyString("text/plain", opts.Message)
m.AddAlternativeString("text/html", opts.HTMLMessage)
}
return m
}
@ -100,6 +119,6 @@ func SendMail(opts *Opts) {
return
}
m := sendMail(opts)
m := getMessage(opts)
Queue <- m
}

View File

@ -17,6 +17,7 @@
package migration
import (
"errors"
"image"
"code.vikunja.io/api/pkg/files"
@ -64,9 +65,12 @@ func init() {
}
src, _, err := image.Decode(bgFile.File)
if err != nil {
if err != nil && !errors.Is(err, image.ErrFormat) {
return err
}
if err != nil && errors.Is(err, image.ErrFormat) {
log.Warningf("Could not generate a blur hash of list %d's background image: %s", l.ID, err)
}
dst := image.NewRGBA(image.Rect(0, 0, 32, 32))
draw.NearestNeighbor.Scale(dst, dst.Rect, src, src.Bounds(), draw.Over, nil)

View File

@ -0,0 +1,108 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public Licensee as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"encoding/json"
"strconv"
"strings"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20220815200851",
Description: "Migrate saved assignee filter to usernames instead of IDs",
Migrate: func(tx *xorm.Engine) error {
filters := []map[string]interface{}{} // not using the type here so that the migration does not depend on it
err := tx.Select("*").
Table("saved_filters").
Find(&filters)
if err != nil {
return err
}
for _, f := range filters {
filter := map[string]interface{}{}
filterJSON, is := f["filters"].(string)
if !is {
continue
}
err = json.Unmarshal([]byte(filterJSON), &filter)
if err != nil {
return err
}
filterBy := filter["filter_by"].([]interface{})
filterValue := filter["filter_value"].([]interface{})
for p, fb := range filterBy {
if fb == "assignees" || fb == "user_id" {
userIDs := []int64{}
for _, sid := range strings.Split(filterValue[p].(string), ",") {
id, err := strconv.ParseInt(sid, 10, 64)
if err != nil {
return err
}
userIDs = append(userIDs, id)
}
usernames := []string{}
err := tx.Select("username").
Table("users").
In("id", userIDs).
Find(&usernames)
if err != nil {
return err
}
userfilter := ""
for i, username := range usernames {
if i > 0 {
userfilter += ","
}
userfilter += username
}
filterValue[p] = userfilter
}
}
filter["filter_value"] = filterValue
filtersJSON, err := json.Marshal(filter)
if err != nil {
return err
}
f["filters"] = string(filtersJSON)
_, err = tx.Where("id = ?", f["id"]).
Cols("filters").
NoAutoCondition().
Table("saved_filters").
Update(f)
if err != nil {
return err
}
}
return nil
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -237,7 +237,7 @@ type ErrListIsArchived struct {
ListID int64
}
// IsErrListIsArchived checks if an error is a .
// IsErrListIsArchived checks if an error is a list is archived error.
func IsErrListIsArchived(err error) bool {
_, ok := err.(ErrListIsArchived)
return ok
@ -255,6 +255,62 @@ func (err ErrListIsArchived) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeListIsArchived, Message: "This list is archived. Editing or creating new tasks is not possible."}
}
// ErrListCannotBelongToAPseudoNamespace represents an error where a list cannot belong to a pseudo namespace
type ErrListCannotBelongToAPseudoNamespace struct {
ListID int64
NamespaceID int64
}
// IsErrListCannotBelongToAPseudoNamespace checks if an error is a list is archived error.
func IsErrListCannotBelongToAPseudoNamespace(err error) bool {
_, ok := err.(*ErrListCannotBelongToAPseudoNamespace)
return ok
}
func (err *ErrListCannotBelongToAPseudoNamespace) Error() string {
return fmt.Sprintf("List cannot belong to a pseudo namespace [ListID: %d, NamespaceID: %d]", err.ListID, err.NamespaceID)
}
// ErrCodeListCannotBelongToAPseudoNamespace holds the unique world-error code of this error
const ErrCodeListCannotBelongToAPseudoNamespace = 3009
// HTTPError holds the http error description
func (err *ErrListCannotBelongToAPseudoNamespace) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeListCannotBelongToAPseudoNamespace,
Message: "This list cannot belong a dynamically generated namespace.",
}
}
// ErrListMustBelongToANamespace represents an error where a list must belong to a namespace
type ErrListMustBelongToANamespace struct {
ListID int64
NamespaceID int64
}
// IsErrListMustBelongToANamespace checks if an error is a list must belong to a namespace error.
func IsErrListMustBelongToANamespace(err error) bool {
_, ok := err.(*ErrListMustBelongToANamespace)
return ok
}
func (err *ErrListMustBelongToANamespace) Error() string {
return fmt.Sprintf("List must belong to a namespace [ListID: %d, NamespaceID: %d]", err.ListID, err.NamespaceID)
}
// ErrCodeListMustBelongToANamespace holds the unique world-error code of this error
const ErrCodeListMustBelongToANamespace = 3010
// HTTPError holds the http error description
func (err *ErrListMustBelongToANamespace) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeListMustBelongToANamespace,
Message: "This list must belong to a namespace.",
}
}
// ================
// List task errors
// ================

View File

@ -476,12 +476,22 @@ func addListDetails(s *xorm.Session, lists []*List, a web.Auth) (err error) {
return err
}
subscriptions, err := GetSubscriptions(s, SubscriptionEntityList, listIDs, a)
if err != nil {
log.Errorf("An error occurred while getting list subscriptions for a namespace item: %s", err.Error())
subscriptions = make(map[int64]*Subscription)
}
for _, list := range lists {
// Don't override the favorite state if it was already set from before (favorite saved filters do this)
if list.IsFavorite {
continue
}
list.IsFavorite = favs[list.ID]
if subscription, exists := subscriptions[list.ID]; exists {
list.Subscription = subscription
}
}
if len(fileIDs) == 0 {
@ -543,6 +553,10 @@ func (l *List) CheckIsArchived(s *xorm.Session) (err error) {
}
func checkListBeforeUpdateOrDelete(s *xorm.Session, list *List) error {
if list.NamespaceID < 0 {
return &ErrListCannotBelongToAPseudoNamespace{ListID: list.ID, NamespaceID: list.NamespaceID}
}
// Check if the namespace exists
if list.NamespaceID > 0 {
_, err := GetNamespaceByID(s, list.NamespaceID)
@ -626,6 +640,13 @@ func UpdateList(s *xorm.Session, list *List, auth web.Auth, updateListBackground
return
}
if list.NamespaceID == 0 {
return &ErrListMustBelongToANamespace{
ListID: list.ID,
NamespaceID: list.NamespaceID,
}
}
// We need to specify the cols we want to update here to be able to un-archive lists
colsToUpdate := []string{
"title",

View File

@ -140,8 +140,9 @@ func TestList_CreateOrUpdate(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
list := List{
ID: 99999999,
Title: "test",
ID: 99999999,
Title: "test",
NamespaceID: 1,
}
err := list.Update(s, usr)
assert.Error(t, err)
@ -221,6 +222,25 @@ func TestList_CreateOrUpdate(t *testing.T) {
assert.False(t, can) // namespace is not writeable by us
_ = s.Close()
})
t.Run("pseudo namespace", func(t *testing.T) {
usr := &user.User{
ID: 6,
Username: "user6",
Email: "user6@example.com",
}
db.LoadAndAssertFixtures(t)
s := db.NewSession()
list := List{
ID: 6,
Title: "Test6",
Description: "Lorem Ipsum",
NamespaceID: -1,
}
err := list.Update(s, usr)
assert.Error(t, err)
assert.True(t, IsErrListCannotBelongToAPseudoNamespace(err))
})
})
})
}

View File

@ -335,7 +335,7 @@ func getListsForNamespaces(s *xorm.Session, namespaceIDs []int64, archived bool)
func getSharedListsInNamespace(s *xorm.Session, archived bool, doer *user.User) (sharedListsNamespace *NamespaceWithLists, err error) {
// Create our pseudo namespace to hold the shared lists
sharedListsPseudonamespace := SharedListsPseudoNamespace
sharedListsPseudonamespace.Owner = doer
sharedListsPseudonamespace.OwnerID = doer.ID
sharedListsNamespace = &NamespaceWithLists{
sharedListsPseudonamespace,
[]*List{},
@ -385,12 +385,13 @@ func getSharedListsInNamespace(s *xorm.Session, archived bool, doer *user.User)
func getFavoriteLists(s *xorm.Session, lists []*List, namespaceIDs []int64, doer *user.User) (favoriteNamespace *NamespaceWithLists, err error) {
// Create our pseudo namespace with favorite lists
pseudoFavoriteNamespace := FavoritesPseudoNamespace
pseudoFavoriteNamespace.Owner = doer
pseudoFavoriteNamespace.OwnerID = doer.ID
favoriteNamespace = &NamespaceWithLists{
Namespace: pseudoFavoriteNamespace,
Lists: []*List{{}},
}
*favoriteNamespace.Lists[0] = FavoritesPseudoList // Copying the list to be able to modify it later
favoriteNamespace.Lists[0].Owner = doer
for _, list := range lists {
if !list.IsFavorite {
@ -448,7 +449,7 @@ func getSavedFilters(s *xorm.Session, doer *user.User) (savedFiltersNamespace *N
}
savedFiltersPseudoNamespace := SavedFiltersPseudoNamespace
savedFiltersPseudoNamespace.Owner = doer
savedFiltersPseudoNamespace.OwnerID = doer.ID
savedFiltersNamespace = &NamespaceWithLists{
Namespace: savedFiltersPseudoNamespace,
Lists: make([]*List, 0, len(savedFilters)),
@ -517,6 +518,7 @@ func (n *Namespace) ReadAll(s *xorm.Session, a web.Auth, search string, page int
if err != nil {
return nil, 0, 0, err
}
ownerMap[doer.ID] = doer
if n.NamespacesOnly {
all := makeNamespaceSlice(namespaces, ownerMap, subscriptionsMap)

View File

@ -18,6 +18,7 @@ package models
import (
"bufio"
"sort"
"strconv"
"strings"
"time"
@ -230,14 +231,23 @@ func (n *UndoneTaskOverdueNotification) Name() string {
// UndoneTasksOverdueNotification represents a UndoneTasksOverdueNotification notification
type UndoneTasksOverdueNotification struct {
User *user.User
Tasks []*Task
Tasks map[int64]*Task
}
// ToMail returns the mail notification for UndoneTasksOverdueNotification
func (n *UndoneTasksOverdueNotification) ToMail() *notifications.Mail {
overdueLine := ""
sortedTasks := make([]*Task, 0, len(n.Tasks))
for _, task := range n.Tasks {
sortedTasks = append(sortedTasks, task)
}
sort.Slice(sortedTasks, func(i, j int) bool {
return sortedTasks[i].DueDate.Before(sortedTasks[j].DueDate)
})
overdueLine := ""
for _, task := range sortedTasks {
until := time.Until(task.DueDate).Round(1*time.Hour) * -1
overdueLine += `* [` + task.Title + `](` + config.ServiceFrontendurl.GetString() + "tasks/" + strconv.FormatInt(task.ID, 10) + `), overdue since ` + utils.HumanizeDuration(until) + "\n"
}

View File

@ -228,28 +228,53 @@ func getSubscriberCondForEntity(entityType SubscriptionEntityType, entityID int6
// that task, if there is none it will look for a subscription on the list the task belongs to and if that also
// doesn't exist it will check for a subscription for the namespace the list is belonging to.
func GetSubscription(s *xorm.Session, entityType SubscriptionEntityType, entityID int64, a web.Auth) (subscription *Subscription, err error) {
subs, err := GetSubscriptions(s, entityType, []int64{entityID}, a)
if err != nil || len(subs) == 0 {
return nil, err
}
if sub, exists := subs[entityID]; exists {
return sub, nil // Take exact match first, if available
}
for _, sub := range subs {
return sub, nil // For parents, take next available
}
return nil, nil
}
// GetSubscriptions returns a map of subscriptions to a set of given entity IDs
func GetSubscriptions(s *xorm.Session, entityType SubscriptionEntityType, entityIDs []int64, a web.Auth) (listsToSubscriptions map[int64]*Subscription, err error) {
u, is := a.(*user.User)
if !is {
return
}
if err := entityType.validate(); err != nil {
return nil, err
}
subscription = &Subscription{}
cond := getSubscriberCondForEntity(entityType, entityID)
exists, err := s.
var entitiesFilter builder.Cond
for _, eID := range entityIDs {
if entitiesFilter == nil {
entitiesFilter = getSubscriberCondForEntity(entityType, eID)
continue
}
entitiesFilter = entitiesFilter.Or(getSubscriberCondForEntity(entityType, eID))
}
var subscriptions []*Subscription
err = s.
Where("user_id = ?", u.ID).
And(cond).
Get(subscription)
if !exists {
And(entitiesFilter).
Find(&subscriptions)
if err != nil {
return nil, err
}
subscription.Entity = subscription.EntityType.String()
return subscription, err
listsToSubscriptions = make(map[int64]*Subscription)
for _, sub := range subscriptions {
sub.Entity = sub.EntityType.String()
listsToSubscriptions[sub.EntityID] = sub
}
return listsToSubscriptions, nil
}
func getSubscribersForEntity(s *xorm.Session, entityType SubscriptionEntityType, entityID int64) (subscriptions []*Subscription, err error) {

View File

@ -214,6 +214,12 @@ func getNativeValueForTaskField(fieldName string, comparator taskFilterComparato
return
}
if realFieldName == "Assignees" {
vals := strings.Split(value, ",")
valueSlice := append([]string{}, vals...)
return valueSlice, nil
}
field, ok := reflect.TypeOf(&Task{}).Elem().FieldByName(realFieldName)
if !ok {
return nil, ErrInvalidTaskField{TaskField: fieldName}

View File

@ -934,10 +934,10 @@ func TestTaskCollection_ReadAll(t *testing.T) {
wantErr: false,
},
{
name: "filter assignees",
name: "filter assignees by username",
fields: fields{
FilterBy: []string{"assignees"},
FilterValue: []string{"1"},
FilterValue: []string{"user1"},
FilterComparator: []string{"equals"},
},
args: defaultArgs,
@ -947,12 +947,80 @@ func TestTaskCollection_ReadAll(t *testing.T) {
wantErr: false,
},
{
name: "filter assignees in",
name: "filter assignees by username with users field name",
fields: fields{
FilterBy: []string{"users"},
FilterValue: []string{"user1"},
FilterComparator: []string{"equals"},
},
args: defaultArgs,
want: nil,
wantErr: true,
},
{
name: "filter assignees by username with user_id field name",
fields: fields{
FilterBy: []string{"user_id"},
FilterValue: []string{"user1"},
FilterComparator: []string{"equals"},
},
args: defaultArgs,
want: nil,
wantErr: true,
},
{
name: "filter assignees by multiple username",
fields: fields{
FilterBy: []string{"assignees", "assignees"},
FilterValue: []string{"user1", "user2"},
FilterComparator: []string{"equals", "equals"},
},
args: defaultArgs,
want: []*Task{
task30,
},
wantErr: false,
},
{
name: "filter assignees by numbers",
fields: fields{
FilterBy: []string{"assignees"},
FilterValue: []string{"1"},
FilterComparator: []string{"equals"},
},
args: defaultArgs,
want: []*Task{},
wantErr: false,
},
{
name: "filter assignees by name with like",
fields: fields{
FilterBy: []string{"assignees"},
FilterValue: []string{"user"},
FilterComparator: []string{"like"},
},
args: defaultArgs,
want: []*Task{},
wantErr: true,
},
{
name: "filter assignees in by id",
fields: fields{
FilterBy: []string{"assignees"},
FilterValue: []string{"1,2"},
FilterComparator: []string{"in"},
},
args: defaultArgs,
want: []*Task{},
wantErr: false,
},
{
name: "filter assignees in by username",
fields: fields{
FilterBy: []string{"assignees"},
FilterValue: []string{"user1,user2"},
FilterComparator: []string{"in"},
},
args: defaultArgs,
want: []*Task{
task30,

View File

@ -92,10 +92,10 @@ func getUndoneOverdueTasks(s *xorm.Session, now time.Time) (usersWithTasks map[i
if !exists {
uts[t.User.ID] = &userWithTasks{
user: t.User,
tasks: []*Task{},
tasks: make(map[int64]*Task),
}
}
uts[t.User.ID].tasks = append(uts[t.User.ID].tasks, t.Task)
uts[t.User.ID].tasks[t.Task.ID] = t.Task
}
}
@ -104,7 +104,7 @@ func getUndoneOverdueTasks(s *xorm.Session, now time.Time) (usersWithTasks map[i
type userWithTasks struct {
user *user.User
tasks []*Task
tasks map[int64]*Task
}
// RegisterOverdueReminderCron registers a function which checks once a day for tasks that are overdue and not done.

View File

@ -29,9 +29,11 @@ import (
"code.vikunja.io/api/pkg/events"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"code.vikunja.io/web"
"github.com/google/uuid"
"github.com/imdario/mergo"
"github.com/jinzhu/copier"
"xorm.io/builder"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
@ -64,7 +66,7 @@ type Task struct {
// The list this task belongs to.
ListID int64 `xorm:"bigint INDEX not null" json:"list_id" param:"list"`
// An amount in seconds this task repeats itself. If this is set, when marking the task as done, it will mark itself as "undone" and then increase all remindes and the due date by its amount.
RepeatAfter int64 `xorm:"bigint INDEX null" json:"repeat_after"`
RepeatAfter int64 `xorm:"bigint INDEX null" json:"repeat_after" valid:"range(0|9223372036854775807)"`
// 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.
RepeatMode TaskRepeatMode `xorm:"not null default 0" json:"repeat_mode"`
// The task priority. Can be anything you want, it is possible to sort by this later.
@ -336,8 +338,11 @@ func getRawTasksForLists(s *xorm.Session, lists []*List, a web.Auth, opts *taskO
continue
}
if f.field == "assignees" || f.field == "user_id" {
f.field = "user_id"
if f.field == "assignees" {
if f.comparator == taskFilterComparatorLike {
return nil, 0, 0, ErrInvalidTaskFilterValue{Field: f.field, Value: f.value}
}
f.field = "username"
filter, err := getFilterCond(f, opts.filterIncludeNulls)
if err != nil {
return nil, 0, 0, err
@ -428,7 +433,13 @@ func getRawTasksForLists(s *xorm.Session, lists []*List, a web.Auth, opts *taskO
}
if len(assigneeFilters) > 0 {
filters = append(filters, getFilterCondForSeparateTable("task_assignees", opts.filterConcat, assigneeFilters))
assigneeFilter := []builder.Cond{
builder.In("user_id",
builder.Select("id").
From("users").
Where(builder.Or(assigneeFilters...)),
)}
filters = append(filters, getFilterCondForSeparateTable("task_assignees", opts.filterConcat, assigneeFilter))
}
if len(labelFilters) > 0 {
@ -676,7 +687,17 @@ func addRelatedTasksToTasks(s *xorm.Session, taskIDs []int64, taskMap map[int64]
continue
}
fullRelatedTasks[rt.OtherTaskID].IsFavorite = taskFavorites[rt.OtherTaskID]
taskMap[rt.TaskID].RelatedTasks[rt.RelationKind] = append(taskMap[rt.TaskID].RelatedTasks[rt.RelationKind], fullRelatedTasks[rt.OtherTaskID])
// We're duplicating the other task to avoid cycles as these can't be represented properly in json
// and would thus fail with an error.
otherTask := &Task{}
err = copier.Copy(otherTask, fullRelatedTasks[rt.OtherTaskID])
if err != nil {
log.Errorf("Could not duplicate task object: %v", err)
continue
}
otherTask.RelatedTasks = nil
taskMap[rt.TaskID].RelatedTasks[rt.RelationKind] = append(taskMap[rt.TaskID].RelatedTasks[rt.RelationKind], otherTask)
}
return
@ -886,7 +907,7 @@ func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err
// Generate a uuid if we don't already have one
if t.UID == "" {
t.UID = utils.MakeRandomString(40)
t.UID = uuid.NewString()
}
// Get the default bucket and move the task there
@ -1268,18 +1289,39 @@ func setTaskDatesFromCurrentDateRepeat(oldTask, newTask *Task) {
}
}
// If a task has a start and end date, the end date should keep the difference to the start date when setting them as new
if !oldTask.StartDate.IsZero() && !oldTask.EndDate.IsZero() {
diff := oldTask.EndDate.Sub(oldTask.StartDate)
newTask.StartDate = now.Add(repeatDuration)
newTask.EndDate = now.Add(repeatDuration + diff)
} else {
if !oldTask.StartDate.IsZero() {
// We want to preserve intervals among the due, start and end dates.
// The due date is used as a reference point for all new dates, so the
// behaviour depends on whether the due date is set at all.
if oldTask.DueDate.IsZero() {
// If a task has no due date, but does have a start and end date, the
// end date should keep the difference to the start date when setting
// them as new
if !oldTask.StartDate.IsZero() && !oldTask.EndDate.IsZero() {
diff := oldTask.EndDate.Sub(oldTask.StartDate)
newTask.StartDate = now.Add(repeatDuration)
newTask.EndDate = now.Add(repeatDuration + diff)
} else {
if !oldTask.StartDate.IsZero() {
newTask.StartDate = now.Add(repeatDuration)
}
if !oldTask.EndDate.IsZero() {
newTask.EndDate = now.Add(repeatDuration)
}
}
} else {
// If the old task has a start and due date, we set the new start date
// to preserve the interval between them.
if !oldTask.StartDate.IsZero() {
diff := oldTask.DueDate.Sub(oldTask.StartDate)
newTask.StartDate = newTask.DueDate.Add(-diff)
}
// If the old task has an end and due date, we set the new end date
// to preserve the interval between them.
if !oldTask.EndDate.IsZero() {
newTask.EndDate = now.Add(repeatDuration)
diff := oldTask.DueDate.Sub(oldTask.EndDate)
newTask.EndDate = newTask.DueDate.Add(-diff)
}
}

View File

@ -96,28 +96,15 @@ func ListUsersFromList(s *xorm.Session, l *List, search string) (users []*user.U
uids = append(uids, id)
}
var cond builder.Cond = builder.Like{"username", "%" + search + "%"}
var cond builder.Cond
if len(uids) > 0 {
cond = builder.And(
builder.In("id", uids),
cond,
)
}
// Get all users
err = s.
Table("users").
Select("*").
Where(cond).
GroupBy("id").
OrderBy("id").
Find(&users)
// Obfuscate all user emails
for _, u := range users {
u.Email = ""
cond = builder.In("id", uids)
}
users, err = user.ListUsers(s, search, &user.ListUserOpts{
AdditionalCond: cond,
ReturnAllIfNoSearchProvided: true,
})
return
}

View File

@ -214,6 +214,13 @@ func TestListUsersFromList(t *testing.T) {
testuser13, // Shared Via NamespaceUser admin
},
},
{
name: "search for user1",
args: args{l: &List{ID: 19, OwnerID: 7}, search: "user1"},
wantUsers: []*user.User{
testuser1, // Shared Via Team readonly
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -63,6 +63,7 @@ func GetAllProviders() (providers []*Provider, err error) {
if err != nil {
if provider != nil {
log.Errorf("Error while getting openid provider %s: %s", provider.Name, err)
continue
}
log.Errorf("Error while getting openid provider: %s", err)
continue

View File

@ -17,10 +17,15 @@
package handler
import (
"image"
_ "image/gif" // To make sure the decoder used for generating blurHashes recognizes gifs
_ "image/jpeg" // To make sure the decoder used for generating blurHashes recognizes jpgs
_ "image/png" // To make sure the decoder used for generating blurHashes recognizes pngs
_ "golang.org/x/image/bmp" // To make sure the decoder used for generating blurHashes recognizes bmps
_ "golang.org/x/image/tiff" // To make sure the decoder used for generating blurHashes recognizes tiffs
_ "golang.org/x/image/webp" // To make sure the decoder used for generating blurHashes recognizes tiffs
"image"
"io"
"net/http"
"strconv"

View File

@ -20,6 +20,7 @@ import (
"archive/zip"
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
@ -122,20 +123,36 @@ func Restore(filename string) error {
return fmt.Errorf("could not read migrations: %w", err)
}
sort.Slice(ms, func(i, j int) bool {
return ms[i].ID > ms[j].ID
return ms[i].ID < ms[j].ID
})
lastMigration := ms[len(ms)-1]
lastMigration := ms[len(ms)-2]
log.Debugf("Last migration: %s", lastMigration.ID)
if err := migration.MigrateTo(lastMigration.ID, nil); err != nil {
return fmt.Errorf("could not create db structure: %w", err)
}
delete(dbfiles, "migration")
// Restore all db data
for table, d := range dbfiles {
content, err := unmarshalFileToJSON(d)
if err != nil {
return fmt.Errorf("could not read table %s: %w", table, err)
}
// 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 {
return fmt.Errorf("could not decode notification %s: %w", content[i]["notification"], err)
}
content[i]["notification"] = string(decoded)
}
}
if err := db.Restore(table, content); err != nil {
return fmt.Errorf("could not restore table data for table %s: %w", table, err)
}

BIN
pkg/notifications/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -18,6 +18,8 @@ package notifications
import (
"bytes"
"embed"
_ "embed"
templatehtml "html/template"
templatetext "text/template"
@ -49,7 +51,7 @@ const mailTemplateHTML = `
<div style="width: 100%; font-family: 'Open Sans', sans-serif; text-rendering: optimizeLegibility">
<div style="width: 600px; margin: 0 auto; text-align: justify;">
<h1 style="font-size: 30px; text-align: center;">
<img src="{{.FrontendURL}}images/logo-full.svg" style="height: 75px;" alt="Vikunja"/>
<img src="cid:logo.png" style="height: 75px;" alt="Vikunja"/>
</h1>
<div style="border: 1px solid #dbdbdb; -webkit-box-shadow: 0.3em 0.3em 0.8em #e6e6e6; box-shadow: 0.3em 0.3em 0.8em #e6e6e6; color: #4a4a4a; padding: 5px 25px; border-radius: 3px; background: #fff;">
<p>
@ -84,6 +86,9 @@ const mailTemplateHTML = `
</html>
`
//go:embed logo.png
var logo embed.FS
// RenderMail takes a precomposed mail message and renders it into a ready to send mail.Opts object
func RenderMail(m *Mail) (mailOpts *mail.Opts, err error) {
@ -155,6 +160,9 @@ func RenderMail(m *Mail) (mailOpts *mail.Opts, err error) {
Message: plainContent.String(),
HTMLMessage: htmlContent.String(),
Boundary: boundary,
EmbedFS: map[string]*embed.FS{
"logo.png": &logo,
},
}
return mailOpts, nil

View File

@ -127,7 +127,7 @@ And one more, because why not?
<div style="width: 100%; font-family: 'Open Sans', sans-serif; text-rendering: optimizeLegibility">
<div style="width: 600px; margin: 0 auto; text-align: justify;">
<h1 style="font-size: 30px; text-align: center;">
<img src="images/logo-full.svg" style="height: 75px;" alt="Vikunja"/>
<img src="cid:logo.png" style="height: 75px;" alt="Vikunja"/>
</h1>
<div style="border: 1px solid #dbdbdb; -webkit-box-shadow: 0.3em 0.3em 0.8em #e6e6e6; box-shadow: 0.3em 0.3em 0.8em #e6e6e6; color: #4a4a4a; padding: 5px 25px; border-radius: 3px; background: #fff;">
<p>

View File

@ -47,7 +47,7 @@ func UserList(c echo.Context) error {
s := db.NewSession()
defer s.Close()
users, err := user.ListUsers(s, search)
users, err := user.ListUsers(s, search, nil)
if err != nil {
_ = s.Rollback()
return handler.HandleHTTPError(err, c)

View File

@ -22,49 +22,61 @@ import (
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
"xorm.io/xorm"
"github.com/labstack/echo/v4"
"golang.org/x/crypto/bcrypt"
)
func BasicAuth(username, password string, c echo.Context) (bool, error) {
creds := &user.Login{
s := db.NewSession()
defer s.Close()
credentials := &user.Login{
Username: username,
Password: password,
}
s := db.NewSession()
defer s.Close()
u, err := user.CheckUserCredentials(s, creds)
if err != nil && !user.IsErrWrongUsernameOrPassword(err) {
log.Errorf("Error during basic auth for caldav: %v", err)
var err error
u, err := checkUserCaldavTokens(s, credentials)
if user.IsErrUserDoesNotExist(err) {
return false, nil
}
if err == nil {
if u == nil {
u, err = user.CheckUserCredentials(s, credentials)
if err != nil {
log.Errorf("Error during basic auth for caldav: %v", err)
return false, nil
}
}
if u != nil && err == nil {
c.Set("userBasicAuth", u)
return true, nil
}
return false, nil
}
tokens, err := user.GetCaldavTokens(u)
func checkUserCaldavTokens(s *xorm.Session, login *user.Login) (*user.User, error) {
usr, err := user.GetUserByUsername(s, login.Username)
if err != nil || usr == nil {
log.Warningf("Error while retrieving users from database: %v", err)
return nil, err
}
tokens, err := user.GetCaldavTokens(usr)
if err != nil {
log.Errorf("Error while getting tokens for caldav auth: %v", err)
return false, nil
return nil, err
}
// Looping over all tokens until we find one that matches
for _, token := range tokens {
err = bcrypt.CompareHashAndPassword([]byte(token.Token), []byte(password))
err = bcrypt.CompareHashAndPassword([]byte(token.Token), []byte(login.Password))
if err != nil {
if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
continue
}
log.Errorf("Error while verifying tokens for caldav auth: %v", err)
return false, nil
return nil, nil
}
c.Set("userBasicAuth", u)
return true, nil
return usr, nil
}
return false, nil
return nil, nil
}

View File

@ -49,6 +49,7 @@ package routes
import (
"errors"
"fmt"
"net/url"
"strings"
"time"
@ -209,6 +210,25 @@ func registerAPIRoutes(a *echo.Group) {
n := a.Group("")
setupRateLimit(n, "ip")
// Echo does not unescape url path params by default. To make sure values bound as :param in urls are passed
// properly to handlers, we use this middleware to unescape them.
// See https://kolaente.dev/vikunja/api/issues/1224
// See https://github.com/labstack/echo/issues/766
a.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
params := make([]string, 0, len(c.ParamValues()))
for _, param := range c.ParamValues() {
p, err := url.PathUnescape(param)
if err != nil {
return err
}
params = append(params, p)
}
c.SetParamValues(params...)
return next(c)
}
})
// Docs
n.GET("/docs.json", apiv1.DocsJSON)
n.GET("/docs", apiv1.RedocUI)

View File

@ -452,3 +452,30 @@ func (err *ErrAccountDisabled) HTTPError() web.HTTPError {
Message: "This account is disabled. Check your emails or ask your administrator.",
}
}
// ErrAccountIsNotLocal represents a "AccountIsNotLocal" kind of error.
type ErrAccountIsNotLocal struct {
UserID int64
}
// IsErrAccountIsNotLocal checks if an error is a ErrAccountIsNotLocal.
func IsErrAccountIsNotLocal(err error) bool {
_, ok := err.(*ErrAccountIsNotLocal)
return ok
}
func (err *ErrAccountIsNotLocal) Error() string {
return "Account is not local"
}
// ErrCodeAccountIsNotLocal holds the unique world-error code of this error
const ErrCodeAccountIsNotLocal = 1021
// HTTPError holds the http error description
func (err *ErrAccountIsNotLocal) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeAccountIsNotLocal,
Message: "This account is managed by a third-party authentication provider.",
}
}

View File

@ -200,7 +200,7 @@ func (apiUser *APIUserPassword) APIFormat() *User {
// GetUserByID gets informations about a user by its ID
func GetUserByID(s *xorm.Session, id int64) (user *User, err error) {
// Apparently xorm does otherwise look for all users but return only one, which leads to returing one even if the ID is 0
// Apparently xorm does otherwise look for all users but return only one, which leads to returning one even if the ID is 0
if id < 1 {
return &User{}, ErrUserDoesNotExist{}
}
@ -280,6 +280,10 @@ func getUser(s *xorm.Session, user *User, withEmail bool) (userOut *User, err er
userOut.Email = ""
}
if userOut.OverdueTasksRemindersTime == "" {
userOut.OverdueTasksRemindersTime = "9:00"
}
return userOut, err
}
@ -314,6 +318,10 @@ func CheckUserCredentials(s *xorm.Session, u *Login) (*User, error) {
return nil, ErrWrongUsernameOrPassword{}
}
if user.Issuer != IssuerLocal {
return user, &ErrAccountIsNotLocal{UserID: user.ID}
}
// The user is invalid if they need to verify their email address
if user.Status == StatusEmailConfirmationRequired {
return &User{}, ErrEmailNotConfirmed{UserID: user.ID}

View File

@ -20,7 +20,9 @@ import (
"testing"
"code.vikunja.io/api/pkg/db"
"github.com/stretchr/testify/assert"
"xorm.io/builder"
)
func TestCreateUser(t *testing.T) {
@ -362,7 +364,7 @@ func TestListUsers(t *testing.T) {
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "user1")
all, err := ListUsers(s, "user1", nil)
assert.NoError(t, err)
assert.True(t, len(all) > 0)
assert.Equal(t, all[0].Username, "user1")
@ -381,7 +383,7 @@ func TestListUsers(t *testing.T) {
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "")
all, err := ListUsers(s, "", nil)
assert.NoError(t, err)
assert.Len(t, all, 0)
})
@ -390,11 +392,12 @@ func TestListUsers(t *testing.T) {
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "user1@example.com")
all, err := ListUsers(s, "user1@example.com", nil)
assert.NoError(t, err)
assert.Len(t, all, 0)
db.AssertExists(t, "users", map[string]interface{}{
"email": "user1@example.com",
"email": "user1@example.com",
"discoverable_by_email": false,
}, false)
})
t.Run("not discoverable by name", func(t *testing.T) {
@ -402,11 +405,12 @@ func TestListUsers(t *testing.T) {
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "one else")
all, err := ListUsers(s, "one else", nil)
assert.NoError(t, err)
assert.Len(t, all, 0)
db.AssertExists(t, "users", map[string]interface{}{
"name": "Some one else",
"name": "Some one else",
"discoverable_by_name": false,
}, false)
})
t.Run("discoverable by email", func(t *testing.T) {
@ -414,20 +418,67 @@ func TestListUsers(t *testing.T) {
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "user7@example.com")
all, err := ListUsers(s, "user7@example.com", nil)
assert.NoError(t, err)
assert.Len(t, all, 1)
assert.Equal(t, int64(7), all[0].ID)
db.AssertExists(t, "users", map[string]interface{}{
"email": "user7@example.com",
"discoverable_by_email": true,
}, false)
})
t.Run("discoverable by partial name", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "with space")
all, err := ListUsers(s, "with space", nil)
assert.NoError(t, err)
assert.Len(t, all, 1)
assert.Equal(t, int64(12), all[0].ID)
db.AssertExists(t, "users", map[string]interface{}{
"name": "Name with spaces",
"discoverable_by_name": true,
}, false)
})
t.Run("discoverable by email with extra condition", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "user7@example.com", &ListUserOpts{AdditionalCond: builder.In("id", 7)})
assert.NoError(t, err)
assert.Len(t, all, 1)
assert.Equal(t, int64(7), all[0].ID)
db.AssertExists(t, "users", map[string]interface{}{
"email": "user7@example.com",
"discoverable_by_email": true,
}, false)
})
t.Run("discoverable by exact username", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "user7", nil)
assert.NoError(t, err)
assert.Len(t, all, 1)
assert.Equal(t, int64(7), all[0].ID)
db.AssertExists(t, "users", map[string]interface{}{
"username": "user7",
}, false)
})
t.Run("not discoverable by partial username", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
defer s.Close()
all, err := ListUsers(s, "user", nil)
assert.NoError(t, err)
assert.Len(t, all, 0)
db.AssertExists(t, "users", map[string]interface{}{
"username": "user7",
}, false)
})
}

View File

@ -23,29 +23,58 @@ import (
"xorm.io/xorm"
)
// ListUsers returns a list with all users, filtered by an optional searchstring
func ListUsers(s *xorm.Session, search string) (users []*User, err error) {
type ListUserOpts struct {
AdditionalCond builder.Cond
ReturnAllIfNoSearchProvided bool
}
// ListUsers returns a list with all users, filtered by an optional search string
func ListUsers(s *xorm.Session, search string, opts *ListUserOpts) (users []*User, err error) {
if opts == nil {
opts = &ListUserOpts{}
}
// Prevent searching for placeholders
search = strings.ReplaceAll(search, "%", "")
if search == "" || strings.ReplaceAll(search, " ", "") == "" {
if (search == "" || strings.ReplaceAll(search, " ", "") == "") && !opts.ReturnAllIfNoSearchProvided {
return
}
conds := []builder.Cond{}
if search != "" {
for _, queryPart := range strings.Split(search, ",") {
conds = append(conds,
builder.Eq{"username": queryPart},
builder.And(
builder.Eq{"email": queryPart},
builder.Eq{"discoverable_by_email": true},
),
builder.And(
builder.Like{"name", "%" + queryPart + "%"},
builder.Eq{"discoverable_by_name": true},
),
)
}
}
cond := builder.Or(conds...)
if opts.AdditionalCond != nil {
cond = builder.And(
cond,
opts.AdditionalCond,
)
}
err = s.
Where(builder.Or(
builder.Like{"username", "%" + search + "%"},
builder.And(
builder.Eq{"email": search},
builder.Eq{"discoverable_by_email": true},
),
builder.And(
builder.Like{"name", "%" + search + "%"},
builder.Eq{"discoverable_by_name": true},
),
)).
Where(cond).
Find(&users)
for _, u := range users {
u.Email = ""
}
return
}

2
run.sh
View File

@ -4,4 +4,4 @@
usermod --non-unique --uid ${PUID} vikunja
groupmod --non-unique --gid ${PGID} vikunja
su vikunja -c '/app/vikunja/vikunja'
exec su vikunja -c '/app/vikunja/vikunja'