Compare commits

..

96 Commits

Author SHA1 Message Date
kolaente ff780f3526
chore: generate swagger docs
continuous-integration/drone/pr Build is passing Details
2022-03-27 17:56:23 +02:00
kolaente 036428c788
feat: return full token when creating one 2022-03-27 17:56:23 +02:00
kolaente be19bc5b90
fix: create token method 2022-03-27 17:56:21 +02:00
kolaente 5a79e52324
feat: add method to remove a token 2022-03-27 17:56:05 +02:00
kolaente f0a1b8c71d
fix: lint 2022-03-27 17:56:05 +02:00
kolaente 245e5d80ba
feat: use caldav tokens for caldav basic auth 2022-03-27 17:56:05 +02:00
kolaente a825dc21e9
chore: generate swagger docs 2022-03-27 17:56:05 +02:00
kolaente 38521dedf1
fix: lint 2022-03-27 17:56:04 +02:00
kolaente 882d4c9d6f
feat: add user caldav token generation 2022-03-27 17:56:03 +02:00
kolaente ac6818a476
fix: checking for error types
continuous-integration/drone/push Build is passing Details
2022-03-27 17:52:33 +02:00
kolaente 5cf263a86f
feat: upgrade golangci-lint to 1.45.2
continuous-integration/drone/push Build is failing Details
2022-03-27 16:55:37 +02:00
renovate 09c0d14444 fix(deps): update module github.com/stretchr/testify to v1.7.1 (#1148)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1148
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-15 22:21:40 +00:00
renovate da0bcc6322 fix(deps): update module github.com/labstack/echo/v4 to v4.7.1 (#1146)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1146
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-13 19:17:28 +00:00
renovate f5b0c603a3 chore(deps): update klakegg/hugo docker tag to v0.93.3 (#1142)
continuous-integration/drone/push Build is failing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1142
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-13 15:59:41 +00:00
renovate aa30baf1bc fix(deps): update golang.org/x/sys commit hash to b874c99 (#1141)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1141
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-10 06:54:02 +00:00
renovate 581dcd41f1 fix(deps): update golang.org/x/oauth2 commit hash to 6242fa9 (#1140)
continuous-integration/drone/push Build is passing Details
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [golang.org/x/oauth2](https://github.com/golang/oauth2) | require | digest | `ee48083` -> `6242fa9` |

---

### Configuration

📅 **Schedule**: At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).

Reviewed-on: vikunja/api#1140
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-09 16:26:50 +00:00
renovate d013020268 fix(deps): update golang.org/x/crypto commit hash to efcb850 (#1139)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1139
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-07 22:27:03 +00:00
renovate bc8a02d794 fix(deps): update golang.org/x/sys commit hash to 22a9840 (#1138)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1138
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-07 21:56:23 +00:00
kolaente b60c69c5a8
chore: cleanup namespace creation
continuous-integration/drone/push Build is passing Details
2022-03-06 17:09:05 +01:00
renovate 9d816205da chore(deps): update klakegg/hugo docker tag to v0.93.2 (#1137)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1137
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-06 13:14:51 +00:00
kolaente 8aa646e4d9
chore(docs): redirect properly from /docs/docs
continuous-integration/drone/push Build is passing Details
2022-03-06 13:42:07 +01:00
renovate b167aac624 fix(deps): update module github.com/yuin/goldmark to v1.4.8 (#1136)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1136
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-05 11:09:10 +00:00
kolaente 75f74b429e
fix: validate email address when creating a user via cli
continuous-integration/drone/push Build is passing Details
2022-03-04 19:58:40 +01:00
renovate 21541bc118 chore(deps): update klakegg/hugo docker tag to v0.93.0 (#1135)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1135
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-04 14:06:12 +00:00
renovate 72ee84d43d fix(deps): update module github.com/labstack/echo/v4 to v4.7.0 (#1134)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1134
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-03 08:23:42 +00:00
renovate f2f6cc68d9 fix(deps): update golang.org/x/image commit hash to 723b81c (#1133)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1133
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-03-02 10:37:17 +00:00
renovate c870627644 fix(deps): update golang.org/x/sys commit hash to 4e6760a (#1131)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1131
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-28 06:51:29 +00:00
renovate edc5084278 fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.12 (#1132)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1132
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-28 06:51:08 +00:00
kolaente 82158d7718
fix(docs): don't use cannonify url
continuous-integration/drone/push Build is passing Details
2022-02-25 14:25:03 +01:00
renovate 16a98a5c70 fix(deps): update golang.org/x/oauth2 commit hash to ee48083 (#1128)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1128
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-24 15:17:36 +00:00
renovate f77f2387b6 fix(deps): update golang.org/x/sys commit hash to 95c6836 (#1130)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1130
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-24 14:03:30 +00:00
renovate a423e111e9 fix(deps): update golang.org/x/sys commit hash to dbe011f (#1129)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1129
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-24 07:36:49 +00:00
renovate f96c2fe23f chore(deps): update klakegg/hugo docker tag to v0.92.2 (#1127)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1127
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-23 08:00:21 +00:00
renovate 81ab23385f fix(deps): update golang.org/x/sys commit hash to f242548 (#1126)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1126
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-23 07:12:52 +00:00
renovate 325ba622e0 fix(deps): update golang.org/x/sys commit hash to 0005352 (#1125)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1125
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-22 20:52:32 +00:00
renovate cda78ea702 fix(deps): update module github.com/swaggo/swag to v1.8.0 (#1124)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1124
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-22 13:56:36 +00:00
kolaente 8bf2254f4b
fix: restoring dumps with no config file saved in them
continuous-integration/drone/push Build is passing Details
2022-02-19 17:46:10 +01:00
kolaente 22e3f242a3
fix: disabling logging completely now works
continuous-integration/drone/push Build is failing Details
2022-02-19 17:42:32 +01:00
kolaente 8cb92b3924
fix(dump): don't try to save a config file if none was provided and dump vikunja env variables
continuous-integration/drone/push Build is passing Details
2022-02-19 11:32:30 +01:00
kolaente 44aaf0a4ec
fix: clarify which config file is used on startup 2022-02-19 11:32:30 +01:00
renovate 2bc82bc1a0 fix(deps): update module github.com/yuin/goldmark to v1.4.7 (#1123)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1123
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-18 20:25:20 +00:00
kolaente 43f1daf40c
fix: microsoft todo migration not importing all tasks
continuous-integration/drone/push Build is passing Details
Previously, we did not check if a list has more tasks than the ones returned. By default, the Microsoft Graph API only returns 10 tasks. If the user had more they would not get imported.
Now we check if there are more pages with tasks and pull them all in until we have everything.
2022-02-18 20:00:42 +01:00
renovate 545999cf5e fix(deps): update module github.com/yuin/goldmark to v1.4.6 (#1122)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1122
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-17 22:35:36 +00:00
renovate c8aab8a8ad fix(deps): update golang.org/x/crypto commit hash to 8634188 (#1121)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1121
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-17 12:04:47 +00:00
renovate 7978c91d09 fix(deps): update golang.org/x/crypto commit hash to f4118a5 (#1118)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1118
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-10 19:16:06 +00:00
renovate 519675ab23 fix(deps): update golang.org/x/crypto commit hash to db63837 (#1115)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1115
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-10 10:38:08 +00:00
renovate 4e257b82a3 fix(deps): update golang.org/x/sys commit hash to 3681064 (#1116)
continuous-integration/drone/push Build was killed Details
Reviewed-on: vikunja/api#1116
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-10 10:37:49 +00:00
renovate 386412caca fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.3.0 (#1117)
continuous-integration/drone/push Build was killed Details
Reviewed-on: vikunja/api#1117
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-10 10:37:26 +00:00
renovate 8f10a852c2 fix(deps): update golang.org/x/crypto commit hash to dad3315 (#1114)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1114
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-09 16:32:41 +00:00
renovate d056d2df51 fix(deps): update golang.org/x/crypto commit hash to bba287d (#1113)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1113
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-09 06:47:42 +00:00
renovate 4432ebf4a5 fix(deps): update module github.com/yuin/goldmark to v1.4.5 (#1112)
continuous-integration/drone/push Build is passing Details
://community.spotify.com/t5/Content-Questions/How-to-disable-all-podcasts/td-p/5180261 PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [github.com/yuin/goldmark](https://github.com/yuin/goldmark) | require | patch | `v1.4.4` -> `v1.4.5` |

---

### Release Notes

<details>
<summary>yuin/goldmark</summary>

### [`v1.4.5`](https://github.com/yuin/goldmark/compare/v1.4.4...v1.4.5)

[Compare Source](https://github.com/yuin/goldmark/compare/v1.4.4...v1.4.5)

</details>

---

### Configuration

📅 **Schedule**: At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).

Reviewed-on: vikunja/api#1112
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-08 10:39:26 +00:00
renovate c5611f79ea fix(deps): update golang.org/x/crypto commit hash to 20e1d8d (#1111)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1111
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-08 06:39:35 +00:00
renovate d2adf00790 fix(deps): update golang.org/x/sys commit hash to 5739886 (#1110)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1110
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-08 06:38:51 +00:00
konrad 1322cb16d7 feat: add long-lived api tokens (#1085)
continuous-integration/drone/push Build was killed Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1085
Co-authored-by: konrad <k@knt.li>
Co-committed-by: konrad <k@knt.li>
2022-02-06 13:18:08 +00:00
renovate 2598550e49 fix(deps): update module github.com/spf13/afero to v1.8.1 (#1108)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1108
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-05 12:10:39 +00:00
renovate 9196826390 fix(deps): update golang.org/x/sys commit hash to 1c1b9b1 (#1107)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1107
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-04 14:36:59 +00:00
renovate 6cbad9546a fix(deps): update module github.com/swaggo/swag to v1.7.9 (#1106)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1106
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-03 22:54:32 +00:00
renovate df35531e70 fix(deps): update golang.org/x/crypto commit hash to 30dcbda (#1105)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1105
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-02-01 06:54:10 +00:00
renovate daa7d26b3d chore(deps): update klakegg/hugo docker tag to v0.92.1 (#1104)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1104
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-30 13:29:54 +00:00
renovate 272fd6dabf chore(deps): update klakegg/hugo docker tag to v0.92.0 (#1103)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1103
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-30 11:06:12 +00:00
kolaente 1d8d0f140e
chore: sign drone config
continuous-integration/drone/push Build is passing Details
2022-01-29 23:31:58 +01:00
kolaente 7af4761cc3
fix(docs): use up-to-date hugo image for building
continuous-integration/drone/push Build was killed Details
2022-01-29 23:31:14 +01:00
renovate 7a27e1317f fix(deps): update module github.com/prometheus/client_golang to v1.12.1 (#1102)
continuous-integration/drone/push Build was killed Details
Reviewed-on: vikunja/api#1102
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-29 16:11:35 +00:00
renovate 59a1e8d0a9 fix(deps): update golang.org/x/sys commit hash to 99c3d69 (#1101)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1101
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-28 22:45:06 +00:00
renovate 4e7ceb22dd fix(deps): update golang.org/x/crypto commit hash to 198e437 (#1100)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1100
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-28 22:44:53 +00:00
renovate b615f06da3 fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.11 (#1099)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1099
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-28 20:04:24 +00:00
renovate 7c6fc41543 fix(deps): update golang.org/x/crypto commit hash to aa10faf (#1098)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1098
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-27 09:27:55 +00:00
renovate 230c784f55 fix(deps): update golang.org/x/crypto commit hash to e04a857 (#1097)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1097
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-26 19:26:28 +00:00
kolaente 049ae39c62
docs: add guide for Synology NAS
continuous-integration/drone/push Build is failing Details
2022-01-25 22:40:19 +01:00
shilch f7a06e4644 Enable a list to be moved across namespaces (#1096)
continuous-integration/drone/push Build is failing Details
Co-authored-by: Simon Hilchenbach <simon@hilchenba.ch>
Reviewed-on: vikunja/api#1096
Reviewed-by: konrad <k@knt.li>
Co-authored-by: shilch <simon@hilchenba.ch>
Co-committed-by: shilch <simon@hilchenba.ch>
2022-01-23 12:59:43 +00:00
kolaente da318e3db1
docs: update testing
continuous-integration/drone/push Build is failing Details
2022-01-23 11:49:03 +01:00
renovate bb88beb417 fix(deps): update module github.com/prometheus/client_golang to v1.12.0 (#1094)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1094
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-19 09:29:02 +00:00
konrad 61d49c3a56 feat: add time zone setting for reminders (#1092)
continuous-integration/drone/push Build is passing Details
Instead of naeveily checking for all reminders due in the next minute, we now check all reminders in all time zones in the next minutes. This essentially means checking for reminders due in the next 14 or past 12 hours. We then check for each user who would receive a reminder from that result if it is actually due in their time zone.

This should prevent issues where users would get the reminder in the time zone of their server, not in their own.

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1092
Co-authored-by: konrad <k@knt.li>
Co-committed-by: konrad <k@knt.li>
2022-01-16 11:05:56 +00:00
renovate e116fbad79 fix(deps): update golang.org/x/sys commit hash to da31bd3 (#1093)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1093
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-15 20:28:17 +00:00
renovate f255fb2d5c fix(deps): update golang.org/x/crypto commit hash to 5e0467b (#1091)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1091
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-12 19:40:20 +00:00
renovate 4aa045d710 fix(deps): update golang.org/x/sys commit hash to 5a964db (#1090)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1090
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-11 10:34:09 +00:00
renovate b316a412ed fix(deps): update golang.org/x/sys commit hash to a018aaa (#1088)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1088
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-10 21:25:18 +00:00
renovate a9296d807f fix(deps): update module github.com/labstack/echo/v4 to v4.6.3 (#1089)
continuous-integration/drone/push Build is passing Details
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [github.com/labstack/echo/v4](https://github.com/labstack/echo) | require | patch | `v4.6.2` -> `v4.6.3` |

---

### Release Notes

<details>
<summary>labstack/echo</summary>

### [`v4.6.3`](https://github.com/labstack/echo/blob/master/CHANGELOG.md#v463---2022-01-10)

[Compare Source](https://github.com/labstack/echo/compare/v4.6.2...v4.6.3)

**Fixes**

-   Fixed Echo version number in greeting message which was not incremented to `4.6.2` [#&#8203;2066](https://github.com/labstack/echo/issues/2066)

</details>

---

### Configuration

📅 **Schedule**: At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box.

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).

Reviewed-on: vikunja/api#1089
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-10 21:24:23 +00:00
renovate 614dcaeb9d fix(deps): update module github.com/labstack/echo/v4 to v4.6.2 (#1084)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1084
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-08 10:54:46 +00:00
renovate 832b7184f3 fix(deps): update module github.com/spf13/afero to v1.8.0 (#1083)
continuous-integration/drone/push Build was killed Details
Reviewed-on: vikunja/api#1083
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2022-01-05 11:44:50 +00:00
renovate 8fb597cae2 fix(deps): update module github.com/mattn/go-sqlite3 to v1.14.10 (#1082)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1082
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-29 16:05:22 +00:00
renovate 64cc299fb1 fix(deps): update module github.com/spf13/afero to v1.7.1 (#1081)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1081
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-29 13:33:59 +00:00
renovate fbf271978d fix(deps): update module github.com/spf13/afero to v1.7.0 (#1078)
continuous-integration/drone/push Build is passing Details
Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#1078
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-25 20:56:04 +00:00
renovate 514c11d342 fix(deps): update module github.com/swaggo/swag to v1.7.8 (#1080)
continuous-integration/drone/push Build is failing Details
Reviewed-on: vikunja/api#1080
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-25 20:21:36 +00:00
renovate 7b2fe5db50 fix(deps): update module github.com/getsentry/sentry-go to v0.12.0 (#1079)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1079
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-23 08:51:14 +00:00
Mike a4c85fed55
feat(docs): add details of using NGINX Proxy Manager to the Reverse Proxy docs (#13)
continuous-integration/drone/push Build is passing Details
2021-12-19 19:54:18 +01:00
renovate 9d8f9d9de9 fix(deps): update module github.com/magefile/mage to v1.12.1 (#1077)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1077
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-19 17:30:08 +00:00
renovate c2e8a8ad98 fix(deps): update module github.com/magefile/mage to v1.12.0 (#1076)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1076
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-17 06:52:28 +00:00
renovate 5e4d632e79 fix(deps): update golang.org/x/sys commit hash to 1d35b9e (#1075)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1075
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-16 12:30:20 +00:00
renovate 402c34fb12 fix(deps): update golang.org/x/sys commit hash to 4abf325 (#1074)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1074
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-15 22:30:24 +00:00
renovate 94fff0ac88 fix(deps): update golang.org/x/crypto commit hash to e495a2d (#1073)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1073
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-15 16:14:35 +00:00
renovate 62c3dec6e3 fix(deps): update module github.com/spf13/viper to v1.10.1 (#1072)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1072
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-15 14:47:10 +00:00
renovate c5d831ec7c fix(deps): update golang.org/x/sys commit hash to 4825e8c (#1071)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1071
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-15 07:46:53 +00:00
renovate 351d72f02d fix(deps): update module github.com/spf13/cobra to v1.3.0 (#1070)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1070
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-14 20:39:53 +00:00
renovate 4752888c06 fix(deps): update golang.org/x/sys commit hash to 3b038e5 (#1068)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1068
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-14 19:33:50 +00:00
renovate d31c0dfeac fix(deps): update golang.org/x/sys commit hash to 03aa0b5 (#1067)
continuous-integration/drone/push Build is passing Details
Reviewed-on: vikunja/api#1067
Co-authored-by: renovate <renovatebot@kolaente.de>
Co-committed-by: renovate <renovatebot@kolaente.de>
2021-12-14 08:31:37 +00:00
54 changed files with 1006 additions and 283 deletions

View File

@ -138,7 +138,7 @@ steps:
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.31.0
- wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.45.2
- ./mage-static check:all
when:
event: [ push, tag, pull_request ]
@ -621,7 +621,7 @@ steps:
- tar -xzf vikunja-theme.tar.gz
- name: build
image: monachus/hugo:v0.75.1
image: klakegg/hugo:0.93.3
pull: true
commands:
- cd docs
@ -874,6 +874,6 @@ steps:
- failure
---
kind: signature
hmac: 4b36351eaff966fb0e28775059a8a4e091eca7a3ef4c52df2a050fd6c59d409e
hmac: 1c4c211e66e4b6eddd2a1c1bad31e5c960d4f67d6033f4d5c4de7896dfae6c30
...

View File

@ -13,10 +13,11 @@ linters:
- goheader
- gofmt
- goimports
- golint
- revive
- misspell
disable:
- scopelint # Obsolete, using exportloopref instead
- durationcheck
presets:
- bugs
- unused
@ -35,6 +36,7 @@ issues:
linters:
- gocyclo
- deadcode
- errorlint
- path: pkg/integrations/*
linters:
- gocyclo
@ -80,3 +82,9 @@ issues:
- text: "Missed string"
linters:
- goheader
- path: pkg/.*/error.go
linters:
- errorlint
- path: pkg/models/favorites\.go
linters:
- nilerr

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"go.testEnvVars": {
"VIKUNJA_SERVICE_ROOTPATH": "${workspaceRoot}"
}
}

View File

@ -6,6 +6,10 @@ service:
# The duration of the issed JWT tokens in seconds.
# The default is 259200 seconds (3 Days).
jwtttl: 259200
# The duration of the "remember me" time in seconds. When the login request is made with
# the long param set, the token returned will be valid for this period.
# The default is 2592000 seconds (30 Days).
jwtttllong: 2592000
# The interface on which to run the webserver
interface: ":3456"
# Path to Unix socket. If set, it will be created and used instead of tcp

View File

@ -2,7 +2,7 @@ baseurl: https://vikunja.io/docs/
title: Vikunja
theme: vikunja
enableRobotsTXT: true
canonifyURLs: true
canonifyURLs: false
pygmentsUseClasses: true

View File

@ -11,9 +11,9 @@ menu:
# Mage
Vikunja uses [Mage](https://magefile.org/) to script common development tasks and even releasing.
Mage is a pure go solution which allows for greater flexibility and things like better paralelization.
Mage is a pure go solution which allows for greater flexibility and things like better parallelization.
This document explains what taks are available and what they do.
This document explains what tasks are available and what they do.
{{< table_of_contents >}}

View File

@ -10,32 +10,31 @@ menu:
# Testing
You can run unit tests with [mage]({{< ref "mage.md">}}) with
{{< table_of_contents >}}
## API Tests
The following parts are about the kinds of tests in the API package and how to run them.
### Prerequesites
To run any kind of test, you need to specify Vikunja's [root path](https://vikunja.io/docs/config-options/#rootpath).
This is required to make sure all test fixtures are correctly loaded.
The easies way to do that is to set the environment variable `VIKUNJA_SERVICE_ROOTPATH` to the path where you cloned the working directory.
### Unit tests
To run unit tests with [mage]({{< ref "mage.md">}}), execute
{{< highlight bash >}}
mage test:unit
{{< /highlight >}}
{{< table_of_contents >}}
In Vikunja, everything that is not an integration test counts as unit test - even if it accesses the db.
This definition is a bit blurry, but we haven't found a better one yet.
## Running tests with config
You can run tests with all available config variables if you want, enabeling you to run tests for a lot of scenarios.
To use the normal config set the enviroment variable `VIKUNJA_TESTS_USE_CONFIG=1`.
## Show sql queries
When `UNIT_TESTS_VERBOSE=1` is set, all sql queries will be shown when tests are run.
## Fixtures
All tests are run against a set of db fixtures.
These fixtures are defined in `pkg/models/fixtures` in YAML-Files which represent the database structure.
When you add a new test case which requires new database entries to test against, update these files.
## Integration tests
### Integration tests
All integration tests live in `pkg/integrations`.
You can run them by executing `mage test:integration`.
@ -45,7 +44,25 @@ see at the beginning of this document.
To run integration tests, use `mage test:integration`.
## Initializing db fixtures when writing tests
### Running tests with config
You can run tests with all available config variables if you want, enabeling you to run tests for a lot of scenarios.
We use this in CI to run all tests with different databases.
To use the normal config set the enviroment variable `VIKUNJA_TESTS_USE_CONFIG=1`.
### Showing sql queries
When the environment variable `UNIT_TESTS_VERBOSE=1` is set, all sql queries will be shown during the test run.
### Fixtures
All tests are run against a set of db fixtures.
These fixtures are defined in `pkg/models/fixtures` in YAML-Files which represent the database structure.
When you add a new test case which requires new database entries to test against, update these files.
#### Initializing db fixtures when writing tests
All db fixtures for all tests live in the `pkg/db/fixtures/` folder as yaml files.
Each file has the same name as the table the fixtures are for.
@ -54,19 +71,39 @@ You should put new fixtures in this folder.
When initializing db fixtures, you are responsible for defining which tables your package needs in your test init function.
Usually, this is done as follows (this code snippet is taken from the `user` package):
```go
{{< highlight go >}}
err = db.InitTestFixtures("users")
if err != nil {
log.Fatal(err)
}
```
{{< /highlight >}}
In your actual tests, you then load the fixtures into the in-memory db like so:
```go
{{< highlight go >}}
db.LoadAndAssertFixtures(t)
```
{{< /highlight >}}
This will load all fixtures you defined in your test init method.
You should always use this method to load fixtures, the only exception is when your package tests require extra test
fixtures other than db fixtures (like files).
## Frontend tests
The frontend has end to end tests with Cypress that use a Vikunja instance and drive a browser against it.
Check out the docs [in the frontend repo](https://kolaente.dev/vikunja/frontend/src/branch/main/cypress/README.md) about how they work and how to get them running.
### Unit Tests
To run the frontend unit tests, run
{{< highlight bash >}}
yarn 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
{{< /highlight >}}

View File

@ -91,6 +91,19 @@ Full path: `service.jwtttl`
Environment path: `VIKUNJA_SERVICE_JWTTTL`
### jwtttllong
The duration of the "remember me" time in seconds. When the login request is made with
the long param set, the token returned will be valid for this period.
The default is 2592000 seconds (30 Days).
Default: `2592000`
Full path: `service.jwtttllong`
Environment path: `VIKUNJA_SERVICE_JWTTTLLONG`
### interface
The interface on which to run the webserver

View File

@ -370,3 +370,81 @@ services:
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
{{< /highlight >}}
## Setup on a Synology NAS
There is a proxy preinstalled in DSM, so if you want to access vikunja from outside,
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)
You should also add 2 empty folders for mariadb and vikunja inside Synology's
docker main folders:
* Docker
* vikunja
* mariadb
Synology has it's own GUI for managing Docker containers... But it's easier via docker compose.
To do that, you can
* either activate SSH and paste the adapted compose file in a terminal (using Putty or similar)
* without activating SSH as a "custom script" (go to Control Panel / Task Scheduler / Create / Scheduled Task / User-defined script)
* without activating SSH, by using Portainer (you have to install first, check out [this tutorial](https://www.portainer.io/blog/how-to-install-portainer-on-a-synology-nas) for exmple):
1. Go to **Dashboard / Stacks** click the button **"Add Stack"**
2. Give it the name Vikunja and paste the adapted docker compose file
3. Deploy the Stack with the "Delpoy Stack" button:
![Portainer Stack deploy](/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:
{{< highlight yaml >}}
version: '3'
services:
db:
image: mariadb:10
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: supersecret
MYSQL_USER: vikunja
MYSQL_PASSWORD: secret
MYSQL_DATABASE: vikunja
volumes:
- ./db:/var/lib/mysql
restart: unless-stopped
api:
image: vikunja/api
environment:
VIKUNJA_DATABASE_HOST: db
VIKUNJA_DATABASE_PASSWORD: secret
VIKUNJA_DATABASE_TYPE: mysql
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
ports:
- 3456:3456
volumes:
- ./files:/app/vikunja/files
depends_on:
- db
restart: unless-stopped
frontend:
image: vikunja/frontend
ports:
- 4321:80
environment:
VIKUNJA_API_URL: http://vikunja-api-domain.tld/api/v1
restart: unless-stopped
{{< /highlight >}}
You may want to change the volumes to match the rest of your setup.
Once deployed, you might want to change the [`PUID` and `GUID` settings]({{< ref "install-backend.md">}}#setting-user-and-group-id-of-the-user-running-vikunja) or [set the time zone]({{< ref "config.md">}}#timezone).
After registering all your users, you might also want to [disable the user registration]({{<ref "config.md">}}#enableregistration).

View File

@ -80,6 +80,22 @@ server {
<b>NOTE:</b> If you change the max upload size in Vikunja's settings, you'll need to also change the <code>client_max_body_size</code> in the nginx proxy config.
</div>
## NGINX Proxy Manager (NPM)
1. Create a standard Proxy Host for the Vikunja Frontend within NPM and point it to the URL you plan to use. The next several steps will enable the Proxy Host to successfully navigate to the API (on port 3456).
2. Verify that the page will pull up in your browser. (Do not bother trying to log in. It won't work. Trust me.)
3. Now, we'll work with the NPM container, so you need to identify the container name for your NPM installation. e.g. NGINX-PM
4. From the command line, enter `sudo docker exec -it [NGINX-PM container name] /bin/bash` and navigate to the proxy hosts folder where the `.conf` files are stashed. Probably `/data/nginx/proxy_host`. (This folder is a persistent folder created in the NPM container and mounted by NPM.)
5. Locate the `.conf` file where the server_name inside the file matches your Vikunja Proxy Host. Once found, add the following code, unchanged, just above the existing location block in that file. (They are listed by number, not name.)
```
location ~* ^/(api|dav|\.well-known)/ {
proxy_pass http://api:3456;
client_max_body_size 20M;
}
```
6. After saving the edited file, return to NPM's UI browser window and refresh the page to verify your Proxy Host for Vikunja is still online.
7. Now, switch over to your Vikunja browswer window and hit refresh. If you configured your URL correctly in original Vikunja container, you should be all set and the browser will correctly show Vikunja. If not, you'll need to adjust the address in the top of the login subscreen to match your proxy address.
## Apache
Put the following config in `cat /etc/apache2/sites-available/vikunja.conf`:
@ -108,4 +124,4 @@ Put the following config in `cat /etc/apache2/sites-available/vikunja.conf`:
**Note:** The apache modules `proxy`, `proxy_http` and `rewrite` must be enabled for this.
For more details see the [frontend apache configuration]({{< ref "install-frontend.md#apache">}}).
For more details see the [frontend apache configuration]({{< ref "install-frontend.md#apache">}}).

View File

@ -18,4 +18,8 @@ server {
location /docs/contact {
return 301 $scheme://vikunja.io/en/contact;
}
location /docs/docs {
return 301 $scheme://vikunja.io/docs;
}
}

BIN
docs/static/synology-proxy-1.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
docs/static/synology-proxy-2.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

33
go.mod
View File

@ -30,40 +30,41 @@ require (
github.com/disintegration/imaging v1.6.2
github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
github.com/gabriel-vasile/mimetype v1.4.0
github.com/getsentry/sentry-go v0.11.0
github.com/getsentry/sentry-go v0.12.0
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-redis/redis/v8 v8.11.4
github.com/go-sql-driver/mysql v1.6.0
github.com/go-testfixtures/testfixtures/v3 v3.6.1
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang-jwt/jwt/v4 v4.3.0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/golang/snappy v0.0.4 // indirect
github.com/iancoleman/strcase v0.2.0
github.com/imdario/mergo v0.3.12
github.com/labstack/echo/v4 v4.6.1
github.com/labstack/echo/v4 v4.7.1
github.com/labstack/gommon v0.3.1
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef
github.com/lib/pq v1.10.4
github.com/magefile/mage v1.11.0
github.com/mattn/go-sqlite3 v1.14.9
github.com/magefile/mage v1.12.1
github.com/mattn/go-sqlite3 v1.14.12
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.11.0
github.com/prometheus/client_golang v1.12.1
github.com/robfig/cron/v3 v3.0.1
github.com/samedi/caldav-go v3.0.0+incompatible
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.10.0
github.com/stretchr/testify v1.7.0
github.com/swaggo/swag v1.7.6
github.com/spf13/afero v1.8.1
github.com/spf13/cobra v1.3.0
github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.1
github.com/swaggo/swag v1.8.0
github.com/tkuchiki/go-timezone v0.2.2
github.com/ulule/limiter/v3 v3.9.0
github.com/yuin/goldmark v1.4.4
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
github.com/yuin/goldmark v1.4.8
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
golang.org/x/image v0.0.0-20220302094943-723b81ca9867
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20211210111614-af8b64212486
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/d4l3k/messagediff.v1 v1.2.1

227
go.sum
View File

@ -4,6 +4,7 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@ -16,6 +17,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
@ -36,8 +38,6 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU=
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
@ -48,6 +48,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
code.vikunja.io/web v0.0.0-20210706160506-d85def955bd3 h1:MXl7Ff9a/ndTpuEmQKIGhqReE9hWhD4T/+AzK4AXUYc=
code.vikunja.io/web v0.0.0-20210706160506-d85def955bd3/go.mod h1:OgFO06HN1KpA4S7Dw/QAIeygiUPSeGJJn1ykz/sjZdU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
@ -105,7 +106,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak=
@ -149,8 +149,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cweill/gotests v1.6.0 h1:KJx+/p4EweijYzqPb4Y/8umDCip1Cv6hEVyOx0mE9W8=
@ -207,8 +207,8 @@ github.com/gabriel-vasile/mimetype v1.4.0/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmx
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8=
github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo=
github.com/getsentry/sentry-go v0.12.0 h1:era7g0re5iY13bHSdN/xMkyV+5zZppjRVQhZrXCaEIk=
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
@ -234,13 +234,13 @@ github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AE
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
@ -270,6 +270,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog=
github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
@ -342,6 +344,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@ -355,15 +358,14 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@ -379,27 +381,22 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
@ -468,7 +465,6 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
@ -509,10 +505,14 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
github.com/labstack/echo/v4 v4.6.1 h1:OMVsrnNFzYlGSdaiYGHbgWQnr+JM7NG+B9suCPie14M=
github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k=
github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
github.com/labstack/echo/v4 v4.6.3 h1:VhPuIZYxsbPmo4m9KAkMU/el2442eB7EBFFhNTTT9ac=
github.com/labstack/echo/v4 v4.6.3/go.mod h1:Hk5OiHj0kDqmFq7aHe7eDqI7CUhuCrfpupQtLGGLm7A=
github.com/labstack/echo/v4 v4.7.0 h1:8wHgZhoE9OT1NSLw6sfrX7ZGpWMtO5Zlfr68+BIo180=
github.com/labstack/echo/v4 v4.7.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/echo/v4 v4.7.1 h1:7Z5z97gRAiTVimeA5Kt2maIudKB52XJNGoYm7bK4cUk=
github.com/labstack/echo/v4 v4.7.1/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
@ -530,8 +530,8 @@ github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lithammer/shortuuid/v3 v3.0.4 h1:uj4xhotfY92Y1Oa6n6HUiFn87CdoEHYUlTy0+IgbLrs=
github.com/lithammer/shortuuid/v3 v3.0.4/go.mod h1:RviRjexKqIzx/7r1peoAITm6m7gnif/h+0zmolKJjzw=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magefile/mage v1.11.0 h1:C/55Ywp9BpgVVclD3lRnSYCwXTYxmSppIgLeDYlNuls=
github.com/magefile/mage v1.11.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/magefile/mage v1.12.1 h1:oGdAbhIUd6iKamKlDGVtU6XGdy5SgNuCWn7gCTgHDtU=
github.com/magefile/mage v1.12.1/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
@ -547,7 +547,6 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
@ -569,8 +568,12 @@ github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71
github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=
github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.11 h1:gt+cp9c0XGqe9S/wAHTL3n/7MqY+siPWgWJgqdsFrzQ=
github.com/mattn/go-sqlite3 v1.14.11/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -579,25 +582,17 @@ github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/le
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
@ -642,7 +637,6 @@ github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
@ -653,6 +647,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
@ -666,6 +661,10 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -678,6 +677,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -685,6 +686,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@ -697,12 +700,13 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@ -710,7 +714,6 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v0.0.0-20191009025716-f1972eb1d1f5 h1:Gojs/hac/DoYEM7WEICT45+hNWczIeuL5D21e5/HPAw=
github.com/shopspring/decimal v0.0.0-20191009025716-f1972eb1d1f5/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@ -721,15 +724,17 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60=
github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/afero v1.8.1 h1:izYHOT71f9iZ7iq37Uqjael60/vYC6vMtzedudZ0zEk=
github.com/spf13/afero v1.8.1/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -737,11 +742,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk=
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@ -752,12 +755,20 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/swaggo/swag v1.7.6 h1:UbAqHyXkW2J+cDjs5S43MkuYR7a6stB7Am7SK8NBmRg=
github.com/swaggo/swag v1.7.6/go.mod h1:7vLqNYEtYoIsD14wXgy9oDS65MNiDANrPtbk9rnLuj0=
github.com/swaggo/swag v1.7.8 h1:w249t0l/kc/DKMGlS0fppNJQxKyJ8heNaUWB6nsH3zc=
github.com/swaggo/swag v1.7.8/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
github.com/swaggo/swag v1.7.9 h1:6vCG5mm43ebDzGlZPMGYrYI4zKFfOr5kicQX8qjeDwc=
github.com/swaggo/swag v1.7.9/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
github.com/swaggo/swag v1.8.0 h1:80NNhvpJcuItNpBDqgJwDuKlMmaZ/OATOzhG3bhcM3w=
github.com/swaggo/swag v1.8.0/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tkuchiki/go-timezone v0.2.2 h1:MdHR65KwgVTwWFQrota4SKzc4L5EfuH5SdZZGtk/P2Q=
github.com/tkuchiki/go-timezone v0.2.2/go.mod h1:oFweWxYl35C/s7HMVZXiA19Jr9Y0qJHMaG/J2TES4LY=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@ -792,15 +803,21 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.4 h1:zNWRjYUW32G9KirMXYHQHVNFkXvMI7LpgNW2AgYAoIs=
github.com/yuin/goldmark v1.4.4/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.5 h1:4OEQwtW2uLXjEdgnGM3Vg652Pq37X7NOIRzFWb3BzIc=
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.6 h1:EQ1OkiNq/eMbQxs/2O/A8VDIHERXGH14s19ednd4XIw=
github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.7 h1:KHHlQL4EKBZ43vpA1KBEQHfodk4JeIgeb0xJLg7rvDI=
github.com/yuin/goldmark v1.4.7/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.8 h1:zHPiabbIRssZOI0MAzJDHsyvG4MXCGqVaMOwR+HeoQQ=
github.com/yuin/goldmark v1.4.8/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@ -836,12 +853,36 @@ golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b h1:QAqMVf3pSa6eeTsuklijukjXBlj7Es2QQplab+/RbQ4=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220126173729-e04a8579fee6 h1:8ZK1PPFZfmuQq6F/bjLKoKOODiEqGvMCh63FG6V8IbY=
golang.org/x/crypto v0.0.0-20220126173729-e04a8579fee6/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8 h1:kACShD3qhmr/3rLmg1yXyt+N4HcwutKyPRB93s54TIU=
golang.org/x/crypto v0.0.0-20220126234351-aa10faf2a1f8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA=
golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab h1:lnZ4LoV0UMdibeCUfIB2a4uFwRu491WX/VB2reB8xNc=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA=
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220209155544-dad33157f4bf h1:gdgmgieTI2lLaGI2N+xEiaCMUgo2XFmAS0rlF8HZoso=
golang.org/x/crypto v0.0.0-20220209155544-dad33157f4bf/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220209195652-db638375bc3a h1:atOEWVSedO4ksXBe/UrlbSLVxQQ9RxM/tT2Jy10IaHo=
golang.org/x/crypto v0.0.0-20220209195652-db638375bc3a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2 h1:XdAboW3BNMv9ocSCOk/u1MFioZGzCNkiJZ19v9Oe3Ig=
golang.org/x/crypto v0.0.0-20220210151621-f4118a5b28e2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -857,6 +898,8 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/image v0.0.0-20220302094943-723b81ca9867 h1:TcHcE0vrmgzNH1v3ppjcMGbhG5+9fMuvOmUYwNEF4q4=
golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -879,7 +922,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
@ -889,7 +931,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -927,19 +968,27 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -951,7 +1000,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
@ -959,6 +1007,10 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1032,13 +1084,16 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -1047,22 +1102,43 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211204120058-94396e421777 h1:QAkhGVjOxMa+n4mlsAWeAU+BMZmimQAaNiMu+iUi94E=
golang.org/x/sys v0.0.0-20211204120058-94396e421777/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211209171907-798191bca915 h1:P+8mCzuEpyszAT6T42q0sxU+eveBAF/cJ2Kp0x6/8+0=
golang.org/x/sys v0.0.0-20211209171907-798191bca915/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc=
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220222172238-00053529121e h1:AGLQ2aegkB2Y9RY8YdQk+7MDCW9da7YmizIwNIt8NtQ=
golang.org/x/sys v0.0.0-20220222172238-00053529121e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220222200937-f2425489ef4c h1:sSIdNI2Dd6vGv47bKc/xArpfxVmEz2+3j0E6I484xC4=
golang.org/x/sys v0.0.0-20220222200937-f2425489ef4c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220224003255-dbe011f71a99 h1:Us899Z5PCfOrSgeCYWobI1/bSigAz9Rhf8+fz5Grkzc=
golang.org/x/sys v0.0.0-20220224003255-dbe011f71a99/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00=
golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 h1:8IVLkfbr2cLhv0a/vKq4UFUcJym8RmDoDboxCFWEjYE=
golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -1106,7 +1182,6 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -1141,13 +1216,15 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1177,7 +1254,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
@ -1189,6 +1265,7 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1234,7 +1311,9 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@ -1290,6 +1369,7 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -1322,9 +1402,6 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=

View File

@ -14,6 +14,7 @@
// 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/>.
//go:build mage
// +build mage
package main
@ -349,7 +350,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", "-timeout", "20m"}, ApiPackages...)
args := append([]string{"test", Goflags[0], "-p", "1", "-coverprofile", "cover.out", "-timeout", "20m"}, ApiPackages...)
runAndStreamOutput("go", args...)
}

View File

@ -24,6 +24,8 @@ import (
"strings"
"time"
"github.com/asaskevich/govalidator"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
@ -175,6 +177,11 @@ var userCreateCmd = &cobra.Command{
Email: userFlagEmail,
Password: getPasswordFromFlagOrInput(),
}
if !govalidator.IsEmail(userFlagEmail) {
log.Fatalf("Provided email is invalid.")
}
newUser, err := user.CreateUser(s, u)
if err != nil {
_ = s.Rollback()

View File

@ -38,6 +38,7 @@ const (
// #nosec
ServiceJWTSecret Key = `service.JWTSecret`
ServiceJWTTTL Key = `service.jwtttl`
ServiceJWTTTLLong Key = `service.jwtttllong`
ServiceInterface Key = `service.interface`
ServiceUnixSocket Key = `service.unixsocket`
ServiceUnixSocketMode Key = `service.unixsocketmode`
@ -45,7 +46,7 @@ const (
ServiceEnableCaldav Key = `service.enablecaldav`
ServiceRootpath Key = `service.rootpath`
ServiceMaxItemsPerPage Key = `service.maxitemsperpage`
// Deprecated. Use metrics.enabled
// Deprecated: Use metrics.enabled
ServiceEnableMetrics Key = `service.enablemetrics`
ServiceMotd Key = `service.motd`
ServiceEnableLinkSharing Key = `service.enablelinksharing`
@ -227,7 +228,8 @@ func InitDefaultConfig() {
// Service
ServiceJWTSecret.setDefault(random)
ServiceJWTTTL.setDefault(259200)
ServiceJWTTTL.setDefault(259200) // 72 hours
ServiceJWTTTLLong.setDefault(2592000) // 30 days
ServiceInterface.setDefault(":3456")
ServiceUnixSocket.setDefault("")
ServiceFrontendurl.setDefault("")
@ -353,12 +355,6 @@ func InitConfig() {
viper.AddConfigPath(".")
viper.SetConfigName("config")
err = viper.ReadInConfig()
if err != nil {
log.Println(err.Error())
log.Println("Using default config.")
return
}
if CacheType.GetString() == "keyvalue" {
CacheType.Set(KeyvalueType.GetString())
@ -393,7 +389,18 @@ func InitConfig() {
MetricsEnabled.Set(true)
}
log.Printf("Using config file: %s", viper.ConfigFileUsed())
err = viper.ReadInConfig()
if viper.ConfigFileUsed() != "" {
log.Printf("Using config file: %s", viper.ConfigFileUsed())
if err != nil {
log.Println(err.Error())
log.Println("Using default config.")
return
}
} else {
log.Println("No config file found, using default or config from environment variables.")
}
}
func random(length int) (string, error) {

View File

@ -186,7 +186,7 @@ func initSqliteEngine() (engine *xorm.Engine, err error) {
}
file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0)
if err != nil {
return nil, fmt.Errorf("could not open database file [uid=%d, gid=%d]: %s", os.Getuid(), os.Getgid(), err)
return nil, fmt.Errorf("could not open database file [uid=%d, gid=%d]: %w", os.Getuid(), os.Getgid(), err)
}
_ = file.Close() // We directly close the file because we only want to check if it is writable. It will be reopened lazily later by xorm.

View File

@ -17,6 +17,7 @@
package files
import (
"errors"
"io"
"os"
"strconv"
@ -136,9 +137,10 @@ func (f *File) Delete() (err error) {
err = afs.Remove(f.getFileName())
if err != nil {
if e, is := err.(*os.PathError); is {
var perr *os.PathError
if errors.As(err, &perr) {
// Don't fail when removing the file failed
log.Errorf("Error deleting file %d: %s", e.Error())
log.Errorf("Error deleting file %d: %w", err)
return s.Commit()
}

View File

@ -17,6 +17,7 @@
package integrations
import (
"errors"
"net/http"
"net/http/httptest"
"net/url"
@ -119,7 +120,7 @@ func newTestRequest(t *testing.T, method string, handler func(ctx echo.Context)
func addUserTokenToContext(t *testing.T, user *user.User, c echo.Context) {
// Get the token as a string
token, err := auth.NewUserJWTAuthtoken(user)
token, err := auth.NewUserJWTAuthtoken(user, false)
assert.NoError(t, err)
// We send the string token through the parsing function to get a valid jwt.Token
tken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
@ -174,8 +175,8 @@ func assertHandlerErrorCode(t *testing.T, err error, expectedErrorCode int) {
t.Error("Error is nil")
t.FailNow()
}
httperr, ok := err.(*echo.HTTPError)
if !ok {
var httperr *echo.HTTPError
if !errors.As(err, &httperr) {
t.Error("Error is not *echo.HTTPError")
t.FailNow()
}

View File

@ -63,23 +63,26 @@ func InitLogger() {
}
}
// We define our two backends
if config.LogStandard.GetString() != "off" {
// The backend is the part which actually handles logging the log entries somewhere.
cf := config.LogStandard.GetString()
var backend logging.Backend
backend = &NoopBackend{}
if cf != "off" && cf != "false" {
stdWriter := GetLogWriter("standard")
level, err := logging.LogLevel(strings.ToUpper(config.LogLevel.GetString()))
if err != nil {
Fatalf("Error setting database log level: %s", err.Error())
}
logBackend := logging.NewLogBackend(stdWriter, "", 0)
backend := logging.NewBackendFormatter(logBackend, logging.MustStringFormatter(Fmt+"\n"))
backendLeveled := logging.AddModuleLevel(backend)
backendLeveled.SetLevel(level, logModule)
logInstance.SetBackend(backendLeveled)
backend = logging.NewBackendFormatter(logBackend, logging.MustStringFormatter(Fmt+"\n"))
}
level, err := logging.LogLevel(strings.ToUpper(config.LogLevel.GetString()))
if err != nil {
Fatalf("Error setting database log level: %s", err.Error())
}
backendLeveled := logging.AddModuleLevel(backend)
backendLeveled.SetLevel(level, logModule)
logInstance.SetBackend(backendLeveled)
}
// GetLogWriter returns the writer to where the normal log goes, depending on the config

28
pkg/log/noop.go Normal file
View File

@ -0,0 +1,28 @@
// 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 log
import (
"github.com/op/go-logging"
)
// NoopBackend doesn't log anything. Used in cases where we want to disable logging completely.
type NoopBackend struct{}
func (n *NoopBackend) Log(level logging.Level, i int, record *logging.Record) error {
return nil
}

View File

@ -45,8 +45,13 @@ func NewWatermillLogger() *WatermillLogger {
logger: logging.MustGetLogger(watermillLogModule),
}
logBackend := logging.NewLogBackend(GetLogWriter("events"), "", 0)
backend := logging.NewBackendFormatter(logBackend, logging.MustStringFormatter(watermillFmt+"\n"))
cf := config.LogEvents.GetString()
var backend logging.Backend
backend = &NoopBackend{}
if cf != "off" && cf != "false" {
logBackend := logging.NewLogBackend(GetLogWriter("events"), "", 0)
backend = logging.NewBackendFormatter(logBackend, logging.MustStringFormatter(watermillFmt+"\n"))
}
backendLeveled := logging.AddModuleLevel(backend)
backendLeveled.SetLevel(level, watermillLogModule)

View File

@ -683,17 +683,17 @@ create unique index UQE_users_namespace_id
sess := tx.NewSession()
if err := sess.Begin(); err != nil {
return fmt.Errorf("unable to open session: %s", err)
return fmt.Errorf("unable to open session: %w", err)
}
for _, s := range sql {
_, err := sess.Exec(s)
if err != nil {
_ = sess.Rollback()
return fmt.Errorf("error executing update data for table %s, column %s: %s", table, column, err)
return fmt.Errorf("error executing update data for table %s, column %s: %w", table, column, err)
}
}
if err := sess.Commit(); err != nil {
return fmt.Errorf("error committing data change: %s", err)
return fmt.Errorf("error committing data change: %w", err)
}
return nil
}

View File

@ -0,0 +1,50 @@
// 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 (
"code.vikunja.io/api/pkg/config"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type users20220112211537 struct {
Timezone string `xorm:"varchar(255) null" json:"-"`
}
func (users20220112211537) TableName() string {
return "users"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20220112211537",
Description: "Add time zone setting for users",
Migrate: func(tx *xorm.Engine) error {
err := tx.Sync2(users20220112211537{})
if err != nil {
return err
}
_, err = tx.Update(&users20220112211537{Timezone: config.GetTimeZone().String()})
return err
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -49,7 +49,7 @@ func ExportUserData(s *xorm.Session, u *user.User) (err error) {
// Open zip
dumpFile, err := os.Create(tmpFilename)
if err != nil {
return fmt.Errorf("error opening dump file: %s", err)
return fmt.Errorf("error opening dump file: %w", err)
}
defer dumpFile.Close()

View File

@ -630,6 +630,7 @@ func UpdateList(s *xorm.Session, list *List, auth web.Auth, updateListBackground
"is_archived",
"identifier",
"hex_color",
"namespace_id",
"position",
}
if list.Description != "" {

View File

@ -216,7 +216,7 @@ func duplicateTasks(s *xorm.Session, doer web.Auth, ld *ListDuplicate, bucketMap
// It is used to map old task items to new ones.
taskMap := make(map[int64]int64)
// Create + update all tasks (includes reminders)
oldTaskIDs := make([]int64, len(tasks))
oldTaskIDs := make([]int64, 0, len(tasks))
for _, t := range tasks {
oldID := t.ID
t.ID = 0

View File

@ -116,6 +116,25 @@ func (l *List) CanUpdate(s *xorm.Session, a web.Auth) (canUpdate bool, err error
return false, nil
}
// Get the list
ol, err := GetListSimpleByID(s, l.ID)
if err != nil {
return false, err
}
// Check if we're moving the list into a different namespace.
// If that is the case, we need to verify permissions to do so.
if l.NamespaceID != 0 && l.NamespaceID != ol.NamespaceID {
newNamespace := &Namespace{ID: l.NamespaceID}
can, err := newNamespace.CanWrite(s, a)
if err != nil {
return false, err
}
if !can {
return false, ErrGenericForbidden{}
}
}
fid := getSavedFilterIDFromListID(l.ID)
if fid > 0 {
sf, err := getSavedFilterSimpleByID(s, fid)

View File

@ -163,6 +163,65 @@ func TestList_CreateOrUpdate(t *testing.T) {
assert.True(t, IsErrListIdentifierIsNotUnique(err))
_ = s.Close()
})
t.Run("change namespace", func(t *testing.T) {
t.Run("own", 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: 7, // from 6
}
can, err := list.CanUpdate(s, usr)
assert.NoError(t, err)
assert.True(t, can)
err = list.Update(s, usr)
assert.NoError(t, err)
err = s.Commit()
assert.NoError(t, err)
db.AssertExists(t, "lists", map[string]interface{}{
"id": list.ID,
"title": list.Title,
"description": list.Description,
"namespace_id": list.NamespaceID,
}, false)
})
// FIXME: The check for whether the namespace is archived is missing in namespace.CanWrite
// t.Run("archived own", func(t *testing.T) {
// db.LoadAndAssertFixtures(t)
// s := db.NewSession()
// list := List{
// ID: 1,
// Title: "Test1",
// Description: "Lorem Ipsum",
// NamespaceID: 16, // from 1
// }
// can, err := list.CanUpdate(s, usr)
// assert.NoError(t, err)
// assert.False(t, can) // namespace is archived and thus not writeable
// _ = s.Close()
// })
t.Run("others", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := db.NewSession()
list := List{
ID: 1,
Title: "Test1",
Description: "Lorem Ipsum",
NamespaceID: 2, // from 1
}
can, _ := list.CanUpdate(s, usr)
assert.False(t, can) // namespace is not writeable by us
_ = s.Close()
})
})
})
}

View File

@ -603,20 +603,17 @@ func (n *Namespace) ReadAll(s *xorm.Session, a web.Auth, search string, page int
// @Failure 500 {object} models.Message "Internal error"
// @Router /namespaces [put]
func (n *Namespace) Create(s *xorm.Session, a web.Auth) (err error) {
// Check if we have at least a name
// Check if we have at least a title
if n.Title == "" {
return ErrNamespaceNameCannotBeEmpty{NamespaceID: 0, UserID: a.GetID()}
}
n.ID = 0 // This would otherwise prevent the creation of new lists after one was created
// Check if the User exists
n.Owner, err = user.GetUserByID(s, a.GetID())
if err != nil {
return
}
n.OwnerID = n.Owner.ID
// Insert
if _, err = s.Insert(n); err != nil {
return err
}

View File

@ -61,11 +61,11 @@ func getTaskUsersForTasks(s *xorm.Session, taskIDs []int64, cond builder.Cond) (
// Get all creators of tasks
creators := make(map[int64]*user.User, len(taskIDs))
err = s.
Select("users.id, users.username, users.email, users.name").
Select("users.id, users.username, users.email, users.name, users.timezone").
Join("LEFT", "tasks", "tasks.created_by_id = users.id").
In("tasks.id", taskIDs).
Where(cond).
GroupBy("tasks.id, users.id, users.username, users.email, users.name").
GroupBy("tasks.id, users.id, users.username, users.email, users.name, users.timezone").
Find(&creators)
if err != nil {
return
@ -77,14 +77,14 @@ func getTaskUsersForTasks(s *xorm.Session, taskIDs []int64, cond builder.Cond) (
return
}
for _, taskID := range taskIDs {
u, exists := creators[taskMap[taskID].CreatedByID]
for _, task := range taskMap {
u, exists := creators[task.CreatedByID]
if !exists {
continue
}
taskUsers = append(taskUsers, &taskUser{
Task: taskMap[taskID],
Task: taskMap[task.ID],
User: u,
})
}
@ -110,8 +110,9 @@ func getTaskUsersForTasks(s *xorm.Session, taskIDs []int64, cond builder.Cond) (
return
}
func getTasksWithRemindersInTheNextMinute(s *xorm.Session, now time.Time) (taskIDs []int64, err error) {
func getTasksWithRemindersDueAndTheirUsers(s *xorm.Session, now time.Time) (reminderNotifications []*ReminderDueNotification, err error) {
now = utils.GetTimeWithoutNanoSeconds(now)
reminderNotifications = []*ReminderDueNotification{}
nextMinute := now.Add(1 * time.Minute)
@ -120,7 +121,8 @@ func getTasksWithRemindersInTheNextMinute(s *xorm.Session, now time.Time) (taskI
reminders := []*TaskReminder{}
err = s.
Join("INNER", "tasks", "tasks.id = task_reminders.task_id").
Where("reminder >= ? and reminder < ?", now.Format(dbTimeFormat), nextMinute.Format(dbTimeFormat)).
// All reminders from -12h to +14h to include all time zones
Where("reminder >= ? and reminder < ?", now.Add(time.Hour*-12).Format(dbTimeFormat), nextMinute.Add(time.Hour*14).Format(dbTimeFormat)).
And("tasks.done = false").
Find(&reminders)
if err != nil {
@ -133,11 +135,56 @@ func getTasksWithRemindersInTheNextMinute(s *xorm.Session, now time.Time) (taskI
return
}
// We're sending a reminder to everyone who is assigned to the task or has created it.
var taskIDs []int64
for _, r := range reminders {
taskIDs = append(taskIDs, r.TaskID)
}
if len(taskIDs) == 0 {
return
}
usersWithReminders, err := getTaskUsersForTasks(s, taskIDs, builder.Eq{"users.email_reminders_enabled": true})
if err != nil {
return
}
usersPerTask := make(map[int64][]*taskUser, len(usersWithReminders))
for _, ur := range usersWithReminders {
usersPerTask[ur.Task.ID] = append(usersPerTask[ur.Task.ID], ur)
}
// Time zone cache per time zone string to avoid parsing the same time zone over and over again
tzs := make(map[string]*time.Location)
// Figure out which reminders are actually due in the time zone of the users
for _, r := range reminders {
for _, u := range usersPerTask[r.TaskID] {
if u.User.Timezone == "" {
u.User.Timezone = config.GetTimeZone().String()
}
// I think this will break once there's more reminders than what we can handle in one minute
tz, exists := tzs[u.User.Timezone]
if !exists {
tz, err = time.LoadLocation(u.User.Timezone)
if err != nil {
return
}
tzs[u.User.Timezone] = tz
}
actualReminder := r.Reminder.In(tz)
if (actualReminder.After(now) && actualReminder.Before(now.Add(time.Minute))) || actualReminder.Equal(now) {
reminderNotifications = append(reminderNotifications, &ReminderDueNotification{
User: u.User,
Task: u.Task,
})
}
}
}
return
}
@ -162,37 +209,26 @@ func RegisterReminderCron() {
defer s.Close()
now := time.Now()
taskIDs, err := getTasksWithRemindersInTheNextMinute(s, now)
reminders, err := getTasksWithRemindersDueAndTheirUsers(s, now)
if err != nil {
log.Errorf("[Task Reminder Cron] Could not get tasks with reminders in the next minute: %s", err)
return
}
if len(taskIDs) == 0 {
if len(reminders) == 0 {
return
}
users, err := getTaskUsersForTasks(s, taskIDs, builder.Eq{"users.email_reminders_enabled": true})
if err != nil {
log.Errorf("[Task Reminder Cron] Could not get task users to send them reminders: %s", err)
return
}
log.Debugf("[Task Reminder Cron] Sending %d reminders", len(reminders))
log.Debugf("[Task Reminder Cron] Sending reminders to %d users", len(users))
for _, u := range users {
n := &ReminderDueNotification{
User: u.User,
Task: u.Task,
}
err = notifications.Notify(u.User, n)
for _, n := range reminders {
err = notifications.Notify(n.User, n)
if err != nil {
log.Errorf("[Task Reminder Cron] Could not notify user %d: %s", u.User.ID, err)
log.Errorf("[Task Reminder Cron] Could not notify user %d: %s", n.User.ID, err)
return
}
log.Debugf("[Task Reminder Cron] Sent reminder email for task %d to user %d", u.Task.ID, u.User.ID)
log.Debugf("[Task Reminder Cron] Sent reminder email for task %d to user %d", n.Task.ID, n.User.ID)
}
})
if err != nil {

View File

@ -32,10 +32,10 @@ func TestReminderGetTasksInTheNextMinute(t *testing.T) {
now, err := time.Parse(time.RFC3339Nano, "2018-12-01T01:13:00Z")
assert.NoError(t, err)
taskIDs, err := getTasksWithRemindersInTheNextMinute(s, now)
notifications, err := getTasksWithRemindersDueAndTheirUsers(s, now)
assert.NoError(t, err)
assert.Len(t, taskIDs, 1)
assert.Equal(t, int64(27), taskIDs[0])
assert.Len(t, notifications, 1)
assert.Equal(t, int64(27), notifications[0].Task.ID)
})
t.Run("Found No Tasks", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
@ -44,7 +44,7 @@ func TestReminderGetTasksInTheNextMinute(t *testing.T) {
now, err := time.Parse(time.RFC3339Nano, "2018-12-02T01:13:00Z")
assert.NoError(t, err)
taskIDs, err := getTasksWithRemindersInTheNextMinute(s, now)
taskIDs, err := getTasksWithRemindersDueAndTheirUsers(s, now)
assert.NoError(t, err)
assert.Len(t, taskIDs, 0)
})

View File

@ -402,7 +402,7 @@ func getRawTasksForLists(s *xorm.Session, lists []*List, a web.Auth, opts *taskO
return nil, 0, 0, err
}
userListIDs := make([]int64, len(userLists))
userListIDs := make([]int64, 0, len(userLists))
for _, l := range userLists {
userListIDs = append(userListIDs, l.ID)
}

View File

@ -91,7 +91,7 @@ func ListUsersFromList(s *xorm.Session, l *List, search string) (users []*user.U
uidmap[u.TeamNamespaceUserID] = true
}
uids := make([]int64, len(uidmap))
uids := make([]int64, 0, len(uidmap))
for id := range uidmap {
uids = append(uids, id)
}

View File

@ -42,8 +42,8 @@ type Token struct {
}
// NewUserAuthTokenResponse creates a new user auth token response from a user object.
func NewUserAuthTokenResponse(u *user.User, c echo.Context) error {
t, err := NewUserJWTAuthtoken(u)
func NewUserAuthTokenResponse(u *user.User, c echo.Context, long bool) error {
t, err := NewUserJWTAuthtoken(u, long)
if err != nil {
return err
}
@ -52,10 +52,13 @@ func NewUserAuthTokenResponse(u *user.User, c echo.Context) error {
}
// NewUserJWTAuthtoken generates and signes a new jwt token for a user. This is a global function to be able to call it from integration tests.
func NewUserJWTAuthtoken(u *user.User) (token string, err error) {
func NewUserJWTAuthtoken(u *user.User, long bool) (token string, err error) {
t := jwt.New(jwt.SigningMethodHS256)
var ttl = time.Duration(config.ServiceJWTTTL.GetInt64())
if long {
ttl = time.Duration(config.ServiceJWTTTLLong.GetInt64())
}
var exp = time.Now().Add(time.Second * ttl).Unix()
// Set claims
@ -68,6 +71,7 @@ func NewUserJWTAuthtoken(u *user.User) (token string, err error) {
claims["name"] = u.Name
claims["emailRemindersEnabled"] = u.EmailRemindersEnabled
claims["isLocalUser"] = u.Issuer == user.IssuerLocal
claims["long"] = long
// Generate encoded token and send it as response.
return t.SignedString([]byte(config.ServiceJWTSecret.GetString()))

View File

@ -19,6 +19,7 @@ package openid
import (
"context"
"encoding/json"
"errors"
"math/rand"
"net/http"
"time"
@ -104,12 +105,13 @@ func HandleCallback(c echo.Context) error {
// Parse the access & ID token
oauth2Token, err := provider.Oauth2Config.Exchange(context.Background(), cb.Code)
if err != nil {
if rerr, is := err.(*oauth2.RetrieveError); is {
var rerr *oauth2.RetrieveError
if errors.As(err, &rerr) {
log.Error(err)
details := make(map[string]interface{})
if err := json.Unmarshal(rerr.Body, &details); err != nil {
log.Errorf("Error unmarshaling token for provider %s: %v", provider.Name, err)
log.Errorf("Error unmarshalling token for provider %s: %v", provider.Name, err)
return handler.HandleHTTPError(err, c)
}
@ -198,7 +200,7 @@ func HandleCallback(c echo.Context) error {
}
// Create token
return auth.NewUserAuthTokenResponse(u, c)
return auth.NewUserAuthTokenResponse(u, c, false)
}
func getOrCreateUser(s *xorm.Session, cl *claims, issuer, subject string) (u *user.User, err error) {

View File

@ -21,6 +21,7 @@ import (
"fmt"
"io"
"os"
"strings"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/files"
@ -34,7 +35,7 @@ import (
func Dump(filename string) error {
dumpFile, err := os.Create(filename)
if err != nil {
return fmt.Errorf("error opening dump file: %s", err)
return fmt.Errorf("error opening dump file: %w", err)
}
defer dumpFile.Close()
@ -43,17 +44,36 @@ func Dump(filename string) error {
// Config
log.Info("Start dumping config file...")
err = writeFileToZip(viper.ConfigFileUsed(), dumpWriter)
if err != nil {
return fmt.Errorf("error saving config file: %s", err)
if viper.ConfigFileUsed() != "" {
err = writeFileToZip(viper.ConfigFileUsed(), dumpWriter)
if err != nil {
return fmt.Errorf("error saving config file: %w", err)
}
} else {
log.Warning("No config file found, not including one in the dump. This usually happens when environment variables are used for configuration.")
}
log.Info("Dumped config file")
env := os.Environ()
dotEnv := ""
for _, e := range env {
if strings.Contains(e, "VIKUNJA_") {
dotEnv += e + "\n"
}
}
if dotEnv != "" {
err = utils.WriteBytesToZip(".env", []byte(dotEnv), dumpWriter)
if err != nil {
return fmt.Errorf("error saving env file: %w", err)
}
log.Info("Dumped .env file")
}
// Version
log.Info("Start dumping version file...")
err = utils.WriteBytesToZip("VERSION", []byte(version.Version), dumpWriter)
if err != nil {
return fmt.Errorf("error saving version: %s", err)
return fmt.Errorf("error saving version: %w", err)
}
log.Info("Dumped version")
@ -61,12 +81,12 @@ func Dump(filename string) error {
log.Info("Start dumping database...")
data, err := db.Dump()
if err != nil {
return fmt.Errorf("error saving database data: %s", err)
return fmt.Errorf("error saving database data: %w", err)
}
for t, d := range data {
err = utils.WriteBytesToZip("database/"+t+".json", d, dumpWriter)
if err != nil {
return fmt.Errorf("error writing database table %s: %s", t, err)
return fmt.Errorf("error writing database table %s: %w", t, err)
}
}
log.Info("Dumped database")
@ -75,7 +95,7 @@ func Dump(filename string) error {
log.Info("Start dumping files...")
allFiles, err := files.Dump()
if err != nil {
return fmt.Errorf("error saving file: %s", err)
return fmt.Errorf("error saving file: %w", err)
}
err = utils.WriteFilesToZip(allFiles, dumpWriter)

View File

@ -44,7 +44,7 @@ func Restore(filename string) error {
r, err := zip.OpenReader(filename)
if err != nil {
return fmt.Errorf("could not open zip file: %s", err)
return fmt.Errorf("could not open zip file: %w", err)
}
log.Warning("Restoring a dump will wipe your current installation!")
@ -52,7 +52,7 @@ func Restore(filename string) error {
cr := bufio.NewReader(os.Stdin)
text, err := cr.ReadString('\n')
if err != nil {
return fmt.Errorf("could not read confirmation message: %s", err)
return fmt.Errorf("could not read confirmation message: %w", err)
}
if text != "Yes, I understand\n" {
return fmt.Errorf("invalid confirmation message")
@ -60,6 +60,7 @@ func Restore(filename string) error {
// Find the configFile, database and files files
var configFile *zip.File
var dotEnvFile *zip.File
dbfiles := make(map[string]*zip.File)
filesFiles := make(map[string]*zip.File)
for _, file := range r.File {
@ -72,44 +73,21 @@ func Restore(filename string) error {
dbfiles[fname[:len(fname)-5]] = file
continue
}
if file.Name == ".env" {
dotEnvFile = file
continue
}
if strings.HasPrefix(file.Name, "files/") {
filesFiles[strings.ReplaceAll(file.Name, "files/", "")] = file
}
}
if configFile == nil {
return fmt.Errorf("dump does not contain a config file")
}
///////
// Restore the config file
if configFile.UncompressedSize64 > maxConfigSize {
return fmt.Errorf("config file too large, is %d, max size is %d", configFile.UncompressedSize64, maxConfigSize)
}
outFile, err := os.OpenFile(configFile.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, configFile.Mode())
if err != nil {
return fmt.Errorf("could not open config file for writing: %s", err)
}
cfgr, err := configFile.Open()
err = restoreConfig(configFile, dotEnvFile)
if err != nil {
return err
}
// #nosec - We eliminated the potential decompression bomb by erroring out above if the file is larger than a threshold.
_, err = io.Copy(outFile, cfgr)
if err != nil {
return fmt.Errorf("could not create config file: %s", err)
}
_ = cfgr.Close()
_ = outFile.Close()
log.Infof("The config file has been restored to '%s'.", configFile.Name)
log.Infof("You can now make changes to it, hit enter when you're done.")
if _, err := bufio.NewReader(os.Stdin).ReadString('\n'); err != nil {
return fmt.Errorf("could not read from stdin: %s", err)
}
log.Info("Restoring...")
// Init the configFile again since the restored configuration is most likely different from the one before
@ -121,7 +99,7 @@ func Restore(filename string) error {
// Restore the db
// Start by wiping everything
if err := db.WipeEverything(); err != nil {
return fmt.Errorf("could not wipe database: %s", err)
return fmt.Errorf("could not wipe database: %w", err)
}
log.Info("Wiped database.")
@ -130,18 +108,18 @@ func Restore(filename string) error {
migrations := dbfiles["migration"]
rc, err := migrations.Open()
if err != nil {
return fmt.Errorf("could not open migrations: %s", err)
return fmt.Errorf("could not open migrations: %w", err)
}
defer rc.Close()
var buf bytes.Buffer
if _, err := buf.ReadFrom(rc); err != nil {
return fmt.Errorf("could not read migrations: %s", err)
return fmt.Errorf("could not read migrations: %w", err)
}
ms := []*xormigrate.Migration{}
if err := json.Unmarshal(buf.Bytes(), &ms); err != nil {
return fmt.Errorf("could not read migrations: %s", err)
return fmt.Errorf("could not read migrations: %w", err)
}
sort.Slice(ms, func(i, j int) bool {
return ms[i].ID > ms[j].ID
@ -149,17 +127,17 @@ func Restore(filename string) error {
lastMigration := ms[len(ms)-1]
if err := migration.MigrateTo(lastMigration.ID, nil); err != nil {
return fmt.Errorf("could not create db structure: %s", err)
return fmt.Errorf("could not create db structure: %w", err)
}
// Restore all db data
for table, d := range dbfiles {
content, err := unmarshalFileToJSON(d)
if err != nil {
return fmt.Errorf("could not read table %s: %s", table, err)
return fmt.Errorf("could not read table %s: %w", table, err)
}
if err := db.Restore(table, content); err != nil {
return fmt.Errorf("could not restore table data for table %s: %s", table, err)
return fmt.Errorf("could not restore table data for table %s: %w", table, err)
}
log.Infof("Restored table %s", table)
}
@ -173,18 +151,18 @@ func Restore(filename string) error {
for i, file := range filesFiles {
id, err := strconv.ParseInt(i, 10, 64)
if err != nil {
return fmt.Errorf("could not parse file id %s: %s", i, err)
return fmt.Errorf("could not parse file id %s: %w", i, err)
}
f := &files.File{ID: id}
fc, err := file.Open()
if err != nil {
return fmt.Errorf("could not open file %s: %s", i, err)
return fmt.Errorf("could not open file %s: %w", i, err)
}
if err := f.Save(fc); err != nil {
return fmt.Errorf("could not save file: %s", err)
return fmt.Errorf("could not save file: %w", err)
}
_ = fc.Close()
@ -218,3 +196,62 @@ func unmarshalFileToJSON(file *zip.File) (contents []map[string]interface{}, err
}
return
}
func restoreConfig(configFile, dotEnvFile *zip.File) error {
if configFile != nil {
if configFile.UncompressedSize64 > maxConfigSize {
return fmt.Errorf("config file too large, is %d, max size is %d", configFile.UncompressedSize64, maxConfigSize)
}
outFile, err := os.OpenFile(configFile.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, configFile.Mode())
if err != nil {
return fmt.Errorf("could not open config file for writing: %w", err)
}
cfgr, err := configFile.Open()
if err != nil {
return err
}
// #nosec - We eliminated the potential decompression bomb by erroring out above if the file is larger than a threshold.
_, err = io.Copy(outFile, cfgr)
if err != nil {
return fmt.Errorf("could not create config file: %w", err)
}
_ = cfgr.Close()
_ = outFile.Close()
log.Infof("The config file has been restored to '%s'.", configFile.Name)
log.Infof("You can now make changes to it, hit enter when you're done.")
if _, err := bufio.NewReader(os.Stdin).ReadString('\n'); err != nil {
return fmt.Errorf("could not read from stdin: %w", err)
}
return nil
}
log.Warning("No config file found, not restoring one.")
log.Warning("You'll likely have had Vikunja configured through environment variables.")
if dotEnvFile != nil {
dotenv, err := dotEnvFile.Open()
if err != nil {
return err
}
buf := bytes.Buffer{}
_, err = buf.ReadFrom(dotenv)
if err != nil {
return err
}
log.Warningf("Please make sure the following settings are properly configured in your instance:\n%s", buf.String())
log.Warning("Make sure your current config matches the following env variables, confirm by pressing enter when done.")
log.Warning("If your config does not match, you'll have to make the changes and restart the restoring process afterwards.")
if _, err := bufio.NewReader(os.Stdin).ReadString('\n'); err != nil {
return fmt.Errorf("could not read from stdin: %w", err)
}
}
return nil
}

View File

@ -23,6 +23,7 @@ import (
"fmt"
"net/http"
"net/url"
"strings"
"time"
"code.vikunja.io/api/pkg/config"
@ -33,6 +34,7 @@ import (
)
const apiScopes = `tasks.read tasks.read.shared`
const apiPrefix = `https://graph.microsoft.com/v1.0/me/todo/`
type Migration struct {
Code string `json:"code"`
@ -92,6 +94,7 @@ type recurrence struct {
type tasksResponse struct {
OdataContext string `json:"@odata.context"`
Nextlink string `json:"@odata.nextLink"`
Value []*task `json:"value"`
}
@ -178,7 +181,7 @@ func getMicrosoftGraphAuthToken(code string) (accessToken string, err error) {
}
func makeAuthenticatedGetRequest(token, urlPart string, v interface{}) error {
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, "https://graph.microsoft.com/v1.0/me/todo/"+urlPart, nil)
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, apiPrefix+urlPart, nil)
if err != nil {
return err
}
@ -224,17 +227,30 @@ func getMicrosoftTodoData(token string) (microsoftTodoData []*list, err error) {
log.Debugf("[Microsoft Todo Migration] Got %d lists", len(lists.Value))
for _, list := range lists.Value {
tasksResponse := &tasksResponse{}
err = makeAuthenticatedGetRequest(token, "lists/"+list.ID+"/tasks", tasksResponse)
if err != nil {
log.Errorf("[Microsoft Todo Migration] Could not get tasks for list %s: %s", list.ID, err)
return
link := "lists/" + list.ID + "/tasks"
list.Tasks = []*task{}
// Microsoft's Graph API has pagination, so we're going through all pages to get all tasks
for {
tr := &tasksResponse{}
err = makeAuthenticatedGetRequest(token, link, tr)
if err != nil {
log.Errorf("[Microsoft Todo Migration] Could not get tasks for list %s: %s", list.ID, err)
return
}
log.Debugf("[Microsoft Todo Migration] Got %d tasks for list %s", len(tr.Value), list.ID)
list.Tasks = append(list.Tasks, tr.Value...)
if tr.Nextlink == "" {
break
}
link = strings.ReplaceAll(tr.Nextlink, apiPrefix, "")
}
log.Debugf("[Microsoft Todo Migration] Got %d tasks for list %s", len(tasksResponse.Value), list.ID)
list.Tasks = tasksResponse.Value
microsoftTodoData = append(microsoftTodoData, list)
}

View File

@ -64,7 +64,7 @@ func (v *FileMigrator) Name() string {
func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) error {
r, err := zip.NewReader(file, size)
if err != nil {
return fmt.Errorf("could not open import file: %s", err)
return fmt.Errorf("could not open import file: %w", err)
}
log.Debugf(logPrefix+"Importing a zip file containing %d files", len(r.File))
@ -77,7 +77,7 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
fname := strings.ReplaceAll(f.Name, "files/", "")
id, err := strconv.ParseInt(fname, 10, 64)
if err != nil {
return fmt.Errorf("could not convert file id: %s", err)
return fmt.Errorf("could not convert file id: %w", err)
}
storedFiles[id] = f
log.Debugf(logPrefix + "Found a blob file")
@ -104,18 +104,18 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
// Import the bulk of Vikunja data
df, err := dataFile.Open()
if err != nil {
return fmt.Errorf("could not open data file: %s", err)
return fmt.Errorf("could not open data file: %w", err)
}
defer df.Close()
var bufData bytes.Buffer
if _, err := bufData.ReadFrom(df); err != nil {
return fmt.Errorf("could not read data file: %s", err)
return fmt.Errorf("could not read data file: %w", err)
}
namespaces := []*models.NamespaceWithListsAndTasks{}
if err := json.Unmarshal(bufData.Bytes(), &namespaces); err != nil {
return fmt.Errorf("could not read data: %s", err)
return fmt.Errorf("could not read data: %w", err)
}
for _, n := range namespaces {
@ -123,11 +123,11 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
if b, exists := storedFiles[l.BackgroundFileID]; exists {
bf, err := b.Open()
if err != nil {
return fmt.Errorf("could not open list background file %d for reading: %s", l.BackgroundFileID, err)
return fmt.Errorf("could not open list background file %d for reading: %w", l.BackgroundFileID, err)
}
var buf bytes.Buffer
if _, err := buf.ReadFrom(bf); err != nil {
return fmt.Errorf("could not read list background file %d: %s", l.BackgroundFileID, err)
return fmt.Errorf("could not read list background file %d: %w", l.BackgroundFileID, err)
}
l.BackgroundInformation = &buf
@ -143,11 +143,11 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
for _, attachment := range t.Attachments {
af, err := storedFiles[attachment.File.ID].Open()
if err != nil {
return fmt.Errorf("could not open attachment %d for reading: %s", attachment.ID, err)
return fmt.Errorf("could not open attachment %d for reading: %w", attachment.ID, err)
}
var buf bytes.Buffer
if _, err := buf.ReadFrom(af); err != nil {
return fmt.Errorf("could not read attachment %d: %s", attachment.ID, err)
return fmt.Errorf("could not read attachment %d: %w", attachment.ID, err)
}
attachment.ID = 0
@ -160,7 +160,7 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
err = migration.InsertFromStructure(namespaces, user)
if err != nil {
return fmt.Errorf("could not insert data: %s", err)
return fmt.Errorf("could not insert data: %w", err)
}
if filterFile == nil {
@ -172,18 +172,18 @@ func (v *FileMigrator) Migrate(user *user.User, file io.ReaderAt, size int64) er
// Import filters
ff, err := filterFile.Open()
if err != nil {
return fmt.Errorf("could not open filters file: %s", err)
return fmt.Errorf("could not open filters file: %w", err)
}
defer ff.Close()
var bufFilter bytes.Buffer
if _, err := bufFilter.ReadFrom(ff); err != nil {
return fmt.Errorf("could not read filters file: %s", err)
return fmt.Errorf("could not read filters file: %w", err)
}
filters := []*models.SavedFilter{}
if err := json.Unmarshal(bufFilter.Bytes(), &filters); err != nil {
return fmt.Errorf("could not read filter data: %s", err)
return fmt.Errorf("could not read filter data: %w", err)
}
log.Debugf(logPrefix+"Importing %d saved filters", len(filters))

View File

@ -102,7 +102,7 @@ func Login(c echo.Context) error {
}
// Create token
return auth.NewUserAuthTokenResponse(user, c)
return auth.NewUserAuthTokenResponse(user, c, u.LongToken)
}
// RenewToken gives a new token to every user with a valid token
@ -156,6 +156,12 @@ func RenewToken(c echo.Context) (err error) {
return handler.HandleHTTPError(err, c)
}
var long bool
lng, has := claims["long"]
if has {
long = lng.(bool)
}
// Create token
return auth.NewUserAuthTokenResponse(user, c)
return auth.NewUserAuthTokenResponse(user, c, long)
}

View File

@ -19,12 +19,13 @@ package v1
import (
"net/http"
"code.vikunja.io/api/pkg/db"
"github.com/labstack/echo/v4"
"github.com/tkuchiki/go-timezone"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/models"
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
)
// UserAvatarProvider holds the user avatar provider type
@ -52,6 +53,8 @@ type UserSettings struct {
WeekStart int `json:"week_start"`
// The user's language
Language string `json:"language"`
// The user's time zone. Used to send task reminders in the time zone of the user.
Timezone string `json:"timezone"`
}
// GetUserAvatarProvider returns the currently set user avatar
@ -180,6 +183,7 @@ func UpdateGeneralUserSettings(c echo.Context) error {
user.DefaultListID = us.DefaultListID
user.WeekStart = us.WeekStart
user.Language = us.Language
user.Timezone = us.Timezone
_, err = user2.UpdateUser(s, user)
if err != nil {
@ -194,3 +198,31 @@ func UpdateGeneralUserSettings(c echo.Context) error {
return c.JSON(http.StatusOK, &models.Message{Message: "The settings were updated successfully."})
}
// GetAvailableTimezones
// @Summary Get all available time zones on this vikunja instance
// @Description Because available time zones depend on the system Vikunja is running on, this endpoint returns a list of all valid time zones this particular Vikunja instance can handle. The list of time zones is not sorted, you should sort it on the client.
// @tags user
// @Accept json
// @Produce json
// @Security JWTKeyAuth
// @Success 200 {array} string "All available time zones."
// @Failure 500 {object} models.Message "Internal server error."
// @Router /user/timezones [get]
func GetAvailableTimezones(c echo.Context) error {
allTimezones := timezone.New().Timezones()
timezoneMap := make(map[string]bool) // to filter all duplicates
for _, s := range allTimezones {
for _, t := range s {
timezoneMap[t] = true
}
}
ts := []string{}
for s := range timezoneMap {
ts = append(ts, s)
}
return c.JSON(http.StatusOK, ts)
}

View File

@ -74,6 +74,7 @@ func UserShow(c echo.Context) error {
DefaultListID: u.DefaultListID,
WeekStart: u.WeekStart,
Language: u.Language,
Timezone: u.Timezone,
},
DeletionScheduledAt: u.DeletionScheduledAt,
IsLocalUser: u.Issuer == user.IssuerLocal,

View File

@ -18,6 +18,7 @@ package v1
import (
"bytes"
"errors"
"fmt"
"image/jpeg"
"net/http"
@ -91,7 +92,8 @@ func UserTOTPEnable(c echo.Context) error {
}
if err := c.Bind(passcode); err != nil {
log.Debugf("Invalid model error. Internal error was: %s", err.Error())
if he, is := err.(*echo.HTTPError); is {
var he *echo.HTTPError
if errors.As(err, &he) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid model provided. Error was: %s", he.Message))
}
return echo.NewHTTPError(http.StatusBadRequest, "Invalid model provided.")
@ -131,7 +133,8 @@ func UserTOTPDisable(c echo.Context) error {
login := &user.Login{}
if err := c.Bind(login); err != nil {
log.Debugf("Invalid model error. Internal error was: %s", err.Error())
if he, is := err.(*echo.HTTPError); is {
var he *echo.HTTPError
if errors.As(err, &he) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid model provided. Error was: %s", he.Message))
}
return echo.NewHTTPError(http.StatusBadRequest, "Invalid model provided.")

View File

@ -17,6 +17,7 @@
package v1
import (
"errors"
"fmt"
"net/http"
@ -47,7 +48,8 @@ func UpdateUserEmail(c echo.Context) (err error) {
var emailUpdate = &user.EmailUpdate{}
if err := c.Bind(emailUpdate); err != nil {
log.Debugf("Invalid model error. Internal error was: %s", err.Error())
if he, is := err.(*echo.HTTPError); is {
var he *echo.HTTPError
if errors.As(err, &he) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid model provided. Error was: %s", he.Message))
}
return echo.NewHTTPError(http.StatusBadRequest, "Invalid model provided.")

View File

@ -155,7 +155,8 @@ func NewEcho() *echo.Echo {
e.HTTPErrorHandler = func(err error, c echo.Context) {
// Only capture errors not already handled by echo
if _, ok := err.(*echo.HTTPError); !ok {
var herr *echo.HTTPError
if errors.As(err, &herr) {
hub := sentryecho.GetHubFromContext(c)
if hub != nil {
hub.WithScope(func(scope *sentry.Scope) {
@ -320,6 +321,7 @@ func registerAPIRoutes(a *echo.Group) {
u.POST("/settings/general", apiv1.UpdateGeneralUserSettings)
u.POST("/export/request", apiv1.RequestUserDataExport)
u.POST("/export/download", apiv1.DownloadUserDataExport)
u.GET("/timezones", apiv1.GetAvailableTimezones)
u.PUT("/settings/token/caldav", apiv1.GenerateCaldavToken)
u.GET("/settings/token/caldav", apiv1.GetCaldavTokens)
u.DELETE("/settings/token/caldav/:id", apiv1.DeleteCaldavToken)

View File

@ -7407,6 +7407,43 @@ var doc = `{
}
}
},
"/user/timezones": {
"get": {
"security": [
{
"JWTKeyAuth": []
}
],
"description": "Because available time zones depend on the system Vikunja is running on, this endpoint returns a list of all valid time zones this particular Vikunja instance can handle. The list of time zones is not sorted, you should sort it on the client.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Get all available time zones on this vikunja instance",
"responses": {
"200": {
"description": "All available time zones.",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
"500": {
"description": "Internal server error.",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/user/token": {
"post": {
"description": "Returns a new valid jwt user token with an extended length.",
@ -8957,6 +8994,10 @@ var doc = `{
"user.Login": {
"type": "object",
"properties": {
"long_token": {
"description": "If true, the token returned will be valid a lot longer than default. Useful for \"remember me\" style logins.",
"type": "boolean"
},
"password": {
"description": "The password for the user.",
"type": "string"
@ -9139,6 +9180,10 @@ var doc = `{
"description": "If enabled, the user will get an email for their overdue tasks each morning.",
"type": "boolean"
},
"timezone": {
"description": "The user's time zone. Used to send task reminders in the time zone of the user.",
"type": "string"
},
"week_start": {
"description": "The day when the week starts for this user. 0 = sunday, 1 = monday, etc.",
"type": "integer"
@ -9335,5 +9380,5 @@ func (s *s) ReadDoc() string {
}
func init() {
swag.Register(swag.Name, &s{})
swag.Register("swagger", &s{})
}

View File

@ -7391,6 +7391,43 @@
}
}
},
"/user/timezones": {
"get": {
"security": [
{
"JWTKeyAuth": []
}
],
"description": "Because available time zones depend on the system Vikunja is running on, this endpoint returns a list of all valid time zones this particular Vikunja instance can handle. The list of time zones is not sorted, you should sort it on the client.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Get all available time zones on this vikunja instance",
"responses": {
"200": {
"description": "All available time zones.",
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
},
"500": {
"description": "Internal server error.",
"schema": {
"$ref": "#/definitions/models.Message"
}
}
}
}
},
"/user/token": {
"post": {
"description": "Returns a new valid jwt user token with an extended length.",
@ -8941,6 +8978,10 @@
"user.Login": {
"type": "object",
"properties": {
"long_token": {
"description": "If true, the token returned will be valid a lot longer than default. Useful for \"remember me\" style logins.",
"type": "boolean"
},
"password": {
"description": "The password for the user.",
"type": "string"
@ -9123,6 +9164,10 @@
"description": "If enabled, the user will get an email for their overdue tasks each morning.",
"type": "boolean"
},
"timezone": {
"description": "The user's time zone. Used to send task reminders in the time zone of the user.",
"type": "string"
},
"week_start": {
"description": "The day when the week starts for this user. 0 = sunday, 1 = monday, etc.",
"type": "integer"

View File

@ -1157,6 +1157,10 @@ definitions:
type: object
user.Login:
properties:
long_token:
description: If true, the token returned will be valid a lot longer than default.
Useful for "remember me" style logins.
type: boolean
password:
description: The password for the user.
type: string
@ -1293,6 +1297,10 @@ definitions:
description: If enabled, the user will get an email for their overdue tasks
each morning.
type: boolean
timezone:
description: The user's time zone. Used to send task reminders in the time
zone of the user.
type: string
week_start:
description: The day when the week starts for this user. 0 = sunday, 1 = monday,
etc.
@ -6316,6 +6324,32 @@ paths:
summary: Totp QR Code
tags:
- user
/user/timezones:
get:
consumes:
- application/json
description: Because available time zones depend on the system Vikunja is running
on, this endpoint returns a list of all valid time zones this particular Vikunja
instance can handle. The list of time zones is not sorted, you should sort
it on the client.
produces:
- application/json
responses:
"200":
description: All available time zones.
schema:
items:
type: string
type: array
"500":
description: Internal server error.
schema:
$ref: '#/definitions/models.Message'
security:
- JWTKeyAuth: []
summary: Get all available time zones on this vikunja instance
tags:
- user
/user/token:
post:
consumes:

View File

@ -44,6 +44,8 @@ type Login struct {
Password string `json:"password"`
// The totp passcode of a user. Only needs to be provided when enabled.
TOTPPasscode string `json:"totp_passcode"`
// If true, the token returned will be valid a lot longer than default. Useful for "remember me" style logins.
LongToken bool `json:"long_token"`
}
type Status int
@ -95,6 +97,7 @@ type User struct {
DefaultListID int64 `xorm:"bigint null index" json:"-"`
WeekStart int `xorm:"null" json:"-"`
Language string `xorm:"varchar(50) null" json:"-"`
Timezone string `xorm:"varchar(255) null" json:"-"`
DeletionScheduledAt time.Time `xorm:"datetime null" json:"-"`
DeletionLastReminderSent time.Time `xorm:"datetime null" json:"-"`
@ -462,6 +465,16 @@ func UpdateUser(s *xorm.Session, user *User) (updatedUser *User, err error) {
}
}
// Check if we have a valid time zone
if user.Timezone == "" {
user.Timezone = config.GetTimeZone().String()
}
_, err = time.LoadLocation(user.Timezone)
if err != nil {
return
}
// Update it
_, err = s.
ID(user.ID).
@ -479,6 +492,7 @@ func UpdateUser(s *xorm.Session, user *User) (updatedUser *User, err error) {
"default_list_id",
"week_start",
"language",
"timezone",
).
Update(user)
if err != nil {

View File

@ -14,6 +14,7 @@
// 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/>.
//go:build !windows
// +build !windows
package utils

View File

@ -54,7 +54,7 @@ func WriteFilesToZip(files map[int64]io.ReadCloser, wr *zip.Writer) (err error)
}
_, err = io.Copy(w, file)
if err != nil {
return fmt.Errorf("error writing file %d: %s", fid, err)
return fmt.Errorf("error writing file %d: %w", fid, err)
}
_ = file.Close()
}