Compare commits

...

73 Commits

Author SHA1 Message Date
freaktechnik 214f2f008e Support absolute iCal timestamps in CalDAV requests (#691)
no need to export from there I think

parse absolute ical timestamps

Co-authored-by: konrad <konrad@kola-entertainments.de>
Co-authored-by: Martin Giger <martin@humanoids.be>
Reviewed-on: vikunja/api#691
Co-Authored-By: freaktechnik <martin@humanoids.be>
Co-Committed-By: freaktechnik <martin@humanoids.be>
2020-10-19 09:11:15 +00:00
kolaente 004e432e7c
Fix nfpm command in drone 2020-10-19 07:58:24 +02:00
renovate 47486af06d Update module spf13/cobra to v1.1.1 (#690)
Update module spf13/cobra to v1.1.1

Reviewed-on: vikunja/api#690
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-18 20:16:25 +00:00
kolaente 8b9b1984fc
Make sure we have go installed when building os packages (for build step dependencies) 2020-10-18 21:28:33 +02:00
kolaente 6dd7bcb0fe
Make sure we have git installed when building os packages 2020-10-18 20:29:54 +02:00
kolaente b94950d7c2
Fix trigger for pushing release artifacts to drone 2020-10-18 13:59:26 +02:00
konrad 618353bf95 Use nfpm to build deb, rpm and apk packages (#689)
Cleanup

Update docs for deb

Add building os packages to drone

Add apk packages

Replace version and binlocation strings in nfpm config

Make nfpm config replacable

Fix nfpm config

Add nfpm config

go mod tidy

Add nfpm mage target

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#689
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
2020-10-18 11:41:27 +00:00
freaktechnik 1555081939 fetch tasks for caldav lists (#641)
Fix shadowed error

Panic if a TaskCollection.ReadAll does not return []*models.Task

Fetch tasks for caldav lists

Co-authored-by: kolaente <k@knt.li>
Co-authored-by: konrad <konrad@kola-entertainments.de>
Co-authored-by: Martin Giger <martin@humanoids.be>
Reviewed-on: vikunja/api#641
Co-Authored-By: freaktechnik <martin@humanoids.be>
Co-Committed-By: freaktechnik <martin@humanoids.be>
2020-10-18 10:40:50 +00:00
renovate 7fe9e6d3f6 Update module swaggo/swag to v1.6.8 (#680)
Regenerate swagger docs with new swaggo

Update module swaggo/swag to v1.6.8

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#680
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-17 18:03:05 +00:00
renovate cbba0695a8 Update module fzipp/gocyclo to v0.3.0 (#687)
Update module fzipp/gocyclo to v0.3.0

Reviewed-on: vikunja/api#687
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-17 10:26:52 +00:00
renovate 921526e086 Update golang.org/x/crypto commit hash to 9e8e0b3 (#685)
Update golang.org/x/crypto commit hash to 9e8e0b3

Co-authored-by: konrad <konrad@kola-entertainments.de>
Reviewed-on: vikunja/api#685
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-17 09:34:23 +00:00
konrad 1b21339bf8 Generate config docs from sample config (#684)
Add docs todo to PR template

Clarify docs

Fix parsing of descriptions and multi-level values

Add method to write out the file

Only render default value for non-top-level values

Remove comment headings from yaml comments

Add printing config

Add basic parsing of sample config with comments

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#684
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
2020-10-17 08:07:39 +00:00
renovate e9d6daa1a3 Update module fzipp/gocyclo to v0.2.0 (#686)
Update module fzipp/gocyclo to v0.2.0

Reviewed-on: vikunja/api#686
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-17 08:06:20 +00:00
renovate 8b001313f4 Update golang.org/x/crypto commit hash to 84dcc77 (#678)
Update golang.org/x/crypto commit hash to 84dcc77

Reviewed-on: vikunja/api#678
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-16 19:55:20 +00:00
renovate e0c8eca669 Update module prometheus/client_golang to v1.8.0 (#681)
Update module prometheus/client_golang to v1.8.0

Reviewed-on: vikunja/api#681
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-15 20:24:03 +00:00
renovate c629130b3b Update module spf13/cobra to v1.1.0 (#679)
Update module spf13/cobra to v1.1.0

Reviewed-on: vikunja/api#679
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-14 19:16:18 +00:00
kolaente 9252225d7f
Disable gocyclo for migration modules
Signed-off-by: kolaente <k@knt.li>
2020-10-13 08:05:55 +02:00
kolaente 38b5c7fb6c
Add checks if tasks exist in maps before trying to access them
Signed-off-by: kolaente <k@knt.li>
2020-10-12 19:33:17 +02:00
kolaente e26df26f78
Fix migrating items with large items from todoist
see #266
2020-10-12 08:08:52 +02:00
renovate 158e07e581 Update module go-errors/errors to v1.1.1 (#677)
Update module go-errors/errors to v1.1.1

Reviewed-on: vikunja/api#677
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-11 21:27:42 +00:00
konrad 699d3d6060 Add Golangci Lint (#676)
Increase golangci timeout

Fix installing golangci-lint in ci

Remove mage targets replaced by golangci

Run golint in ci

Add goheader linter

Enable & fix more linters

Fix lint issues

Add mage target to automagically fix issues found by golangci

golangci-lint run --fix

Add golangci config

Add golangci mage target

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#676
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
2020-10-11 20:10:03 +00:00
konrad d56a611be7 Key-Value Storages (#674)
Fix lint

Add docs for keyvalue config options

Use keyvalue store to cache unsplash photo results

Cleanup

Use keyvalue store for upload avatar

Use keyvalue store for initials avatar

Fix initializing metrics

Use keyvalue for metrics

Add IncryBy and DecrBy methods to increase or decrease a value

Fix lint

Return custom error if a key does not exist

Init keyvalue storage

Follow the keyvalue storage setting for things like cache and other

Add docs

Add configuration of the storage backend

Add redis keyvalue storage implementation

Add doc comments

Add methods to use storage through the package itself

Add memory implementation for keyvalue store

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#674
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
2020-10-10 16:53:59 +00:00
kolaente bf5d8af3f6
Fix docs index links 2020-10-10 12:12:54 +02:00
renovate 0769098357 Update golang.org/x/sync commit hash to b3e1573 (#675)
Update golang.org/x/sync commit hash to b3e1573

Reviewed-on: vikunja/api#675
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-10 07:04:40 +00:00
renovate 71094d981f Update module spf13/afero to v1.4.1 (#673)
Update module spf13/afero to v1.4.1

Reviewed-on: vikunja/api#673
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-06 12:03:14 +00:00
renovate 32d97f1451 Update golang.org/x/crypto commit hash to 7f63de1 (#672)
Update golang.org/x/crypto commit hash to 7f63de1

Reviewed-on: vikunja/api#672
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-02 18:19:39 +00:00
renovate bf9d1c634a Update module mattn/go-sqlite3 to v1.14.4 (#670)
Update module mattn/go-sqlite3 to v1.14.4

Reviewed-on: vikunja/api#670
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-02 15:05:51 +00:00
renovate ebd96d7766 Update golang.org/x/crypto commit hash to c90954c (#671)
Update golang.org/x/crypto commit hash to c90954c

Reviewed-on: vikunja/api#671
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-02 15:05:32 +00:00
renovate 089d156259 Update golang.org/x/crypto commit hash to eb9a90e (#669)
Update golang.org/x/crypto commit hash to eb9a90e

Reviewed-on: vikunja/api#669
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-10-01 21:09:37 +00:00
renovate dd589022e4 Update golang.org/x/crypto commit hash to afb6bcd (#668)
Update golang.org/x/crypto commit hash to afb6bcd

Reviewed-on: vikunja/api#668
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-30 17:18:49 +00:00
renovate b850f65295 Update golang.org/x/sync commit hash to 3042136 (#667)
Update golang.org/x/sync commit hash to 3042136

Reviewed-on: vikunja/api#667
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-30 14:44:18 +00:00
kolaente b3d09cd2d4
Fix loading list background information for uploaded backgrounds
Signed-off-by: kolaente <k@knt.li>
2020-09-28 20:53:17 +02:00
konrad 64d125afd9 Testing improvements (#666)
Change method names to avoid doubling db

Assert team test exists

Assert team member test exists

Assert task test exists

Assert task relation test exists

Assert task comment test exists

Better tests for team namespaces

Assert exists in namespace users tests

Assert exists in namespace tests

Assert exists in user list tests

Assert exists in list tests

Better team list tests

Assert label tests exist in db

Assert label task tests exist in db

Assert label task tests exist in db

Assert kanban tests exist in db

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#666
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
2020-09-27 15:45:17 +00:00
renovate dd5d64da3e Update golang.org/x/image commit hash to e162460 (#665)
Update golang.org/x/image commit hash to e162460

Reviewed-on: vikunja/api#665
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-27 13:35:07 +00:00
kolaente 1776eb56fe
Fix upload avatar not working
Signed-off-by: kolaente <k@knt.li>
2020-09-27 12:50:52 +02:00
renovate f8c135f22e Update golang.org/x/image commit hash to a67d67e (#664)
Update golang.org/x/image commit hash to a67d67e

Reviewed-on: vikunja/api#664
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-27 07:12:14 +00:00
konrad 0fb2edf051 Saved filters (#655)
Fix updating saved filters

Fix filter not loadable because of missing param declaration

Add fancy special cases for postgres exists in db

Add special case for postgrs json

Add read one test

Add rights tests

Fix lint

Fixed getting a single saved filter from db

Add tests for the usual crud methods

Add test stubs and TODOs

Add test for converting saved filter ids to list ids and vice versa

Add test fixture for saved filters and fix existing tests

Fix exposed json variables of filters

Fix creating saved filters table for tests

Add getting saved filters as pseudo namespace

Cleanup

Refactor getting all namespaces to use a map for easier handling of pseudo namespaces

Add custom erros for saved filters

Swagger docs

Fix lint

Add routes for saved filters

Add alias for mage build

Add method to get a saved filter from the lists endpoint

Add getting tasks from a saved filter

Add create, update, delete, read one methods

Add rights methods for saved filters

Fix docs minLength

Add saved filters column

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#655
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
2020-09-26 21:02:17 +00:00
renovate a6fdf114d1 Update golang.org/x/image commit hash to 4578eab (#663)
Update golang.org/x/image commit hash to 4578eab

Reviewed-on: vikunja/api#663
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-24 09:01:34 +00:00
renovate ca1b33d24d Update github.com/asaskevich/govalidator commit hash to 7a23bdc (#657)
Update github.com/asaskevich/govalidator commit hash to 7a23bdc

Reviewed-on: vikunja/api#657
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-23 11:27:58 +00:00
renovate c98b9bbee6 Update golang.org/x/image commit hash to e59bae6 (#659)
Update golang.org/x/image commit hash to e59bae6

Reviewed-on: vikunja/api#659
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-23 11:27:43 +00:00
renovate 19a0a85c73 Update github.com/jgautheron/goconst commit hash to 8f5268c (#658)
Update github.com/jgautheron/goconst commit hash to 8f5268c

Reviewed-on: vikunja/api#658
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-23 10:25:10 +00:00
renovate 77122b8f1b Update module iancoleman/strcase to v0.1.2 (#660)
Update module iancoleman/strcase to v0.1.2

Reviewed-on: vikunja/api#660
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-23 07:59:24 +00:00
renovate 436af467d6 Update module mattn/go-sqlite3 to v1.14.3 (#661)
Update module mattn/go-sqlite3 to v1.14.3

Reviewed-on: vikunja/api#661
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-23 07:12:18 +00:00
renovate 04130e4ea3 Update module spf13/afero to v1.4.0 (#662)
Update module spf13/afero to v1.4.0

Reviewed-on: vikunja/api#662
Co-Authored-By: renovate <renovatebot@kolaente.de>
Co-Committed-By: renovate <renovatebot@kolaente.de>
2020-09-23 05:05:58 +00:00
kolaente 7e6e44e787
Replace renovate tokens with env 2020-09-22 22:25:23 +02:00
kolaente 9e7ca8df51
Update renovate token 2020-09-22 21:42:40 +02:00
konrad 6bdddd462a Favorite lists (#654)
Add tests

Remove the favorites pseudo namespace if there are no lists or tasks favorited

Regenerate swagger docs

Fix favorite lists not being updated because of nonexisting users (the favorite list does not have one)

Make the pseudo favorites list always favorited

Add favorited lists to the favorites pseudo namespace

Add favorite field to list

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#654
2020-09-06 14:20:16 +00:00
konrad e5559137dd Favorite tasks (#653)
Fixed namespace tests

Add test for favorite tasks

Fix favorite tasks not being updated

Fix integration tests

Fix lint

Return a pseudo namespace and list for favorites

Make sure users can only see their favorites

Add condition show tasks from the favorites list

Regenerate swagger docs

Add favorite field to task

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#653
2020-09-05 20:16:02 +00:00
kolaente ecf09e17a8
Only check if a bucket limit is exceeded when moving a task between buckets 2020-09-04 22:01:33 +02:00
konrad 14d706c91e Kanban bucket limits (#652)
Fix integration tests

Generate swagger docs

Add test for moving a task between buckets

Add check for bucket limit when updating a task

Add fixture to ensure a bucket with a high limit will never exceed the limit

Refactor bucket limit check into seperate function

Add test for creating and fix

Fix unexported field

Add error in case a task was added to a bucket which has its limit already exceeded

Add migration to add new task field

Add limit field to buckets

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#652
2020-09-04 14:37:56 +00:00
kolaente 5317a89623
Make sure to copy the permissions as well when moving files 2020-09-04 14:00:54 +02:00
kolaente e9b1786188
Regenerate swagger docs 2020-09-04 13:15:46 +02:00
kolaente 313289d28d
Add rootpath to deb command to not include everything in the deb file 2020-09-04 10:42:32 +02:00
kolaente 05e237560d
Add mage command to create a new migration 2020-09-04 10:15:33 +02:00
kolaente e4dd314079
Add caldav enabled/disabled to /info endpoint 2020-09-04 09:58:42 +02:00
kolaente 118c7f25b5
Fix release commands in drone 2020-09-03 22:46:41 +02:00
kolaente b64a80da0b
Make sure built binary files are executable when compressing with upx 2020-09-03 22:45:04 +02:00
kolaente bb26c9d97c
Make sure to only initialize all variables when needed 2020-09-03 22:14:30 +02:00
kolaente edf3854632
Add github sponsor link 2020-09-03 21:59:17 +02:00
kolaente 19a66450ec
Fix building for darwin with mage 2020-09-03 21:22:41 +02:00
kolaente 3a839dfb86
Add util function to move files 2020-09-03 20:42:26 +02:00
kolaente 78b261e440
Skip directories when moving build release artefacts in drone 2020-09-03 18:08:57 +02:00
kolaente 471d1b0ec5
Fix dockerimage build 2020-09-03 18:08:26 +02:00
kolaente 58dfbe13ed
Add FreeBSD guide to installation docs 2020-09-03 17:44:44 +02:00
kolaente 1a4eef1056
Add toc to docs 2020-09-03 17:34:44 +02:00
kolaente 8da7db3e26
Cleanup references to make 2020-09-03 17:18:41 +02:00
konrad d359130bcf Switch to mage (#651)
Add comment about magefile compile

Switch make to mage commands in drone

Fix misspell

Update docs

Add general release command

Add reprepro command

Make sure the filename contains the proper version

Add deb package building

Add zip command

Preserve file permissions when copying files

Fix release:os-package

Make sure to not create checksums of directories

Cleanup

Only compress what upx is able to compress

Add check command

Add release:os-package command

Add copy command

Add comments

Add compress step

Move releasing binaries to a more general function and add ones of linux + darwin

Add release:windows command

Add release:dir command

Add namespaces for commands

Reorder

Add command to run all checks at once

Add goconst-check

Add gosec-check

Add static-check

Add gocyclo-check

Add ineffasign-check

Add misspell-check

Add command to check for swagger docs regeneration

Add comments

Add command to generate swagger docs

Reorder

Add check for installing golint before running it

Add fmt check command

Add fmt command

Use runAndStreamOutput everywhere

Add aliases and comments

Add todo

Reorder

Add test coverage command

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: vikunja/api#651
2020-09-03 15:13:19 +00:00
renovate 05099e1784 Update module spf13/afero to v1.3.5 (#650)
Update module spf13/afero to v1.3.5

Reviewed-on: vikunja/api#650
2020-09-02 21:19:34 +00:00
renovate 79970ebb4a Update module labstack/echo/v4 to v4.1.17 (#646)
Update module labstack/echo/v4 to v4.1.17

Reviewed-on: vikunja/api#646
2020-08-31 09:19:49 +00:00
renovate 27b4086351 Update module iancoleman/strcase to v0.1.1 (#645)
Update module iancoleman/strcase to v0.1.1

Reviewed-on: vikunja/api#645
2020-08-30 08:18:18 +00:00
renovate ae7eafd6ad Update module mattn/go-sqlite3 to v1.14.2 (#647)
Update module mattn/go-sqlite3 to v1.14.2

Reviewed-on: vikunja/api#647
2020-08-30 08:17:50 +00:00
renovate 21b5aee054 Update github.com/c2h5oh/datasize commit hash to 48ed595 (#644)
Update github.com/c2h5oh/datasize commit hash to 48ed595

Reviewed-on: vikunja/api#644
2020-08-25 16:06:32 +00:00
renovate 2b34a8d4e6 Update github.com/shurcooL/vfsgen commit hash to 0d455de (#642)
Update github.com/shurcooL/vfsgen commit hash to 0d455de

Reviewed-on: vikunja/api#642
2020-08-24 20:00:48 +00:00
203 changed files with 6204 additions and 2032 deletions

View File

@ -52,13 +52,26 @@ steps:
commands:
- git fetch --tags
- name: build
# We're statically compiling the magefile to avoid race condition issues caused by multiple pipeline steps
# compiling the same magefile at the same time. It's also faster if each step does not need to compile it first.
- name: mage
image: vikunja/golang-build:latest
pull: true
environment:
GOPROXY: 'https://goproxy.kolaente.de'
commands:
- make build
- mage -compile ./mage-static
when:
event: [ push, tag, pull_request ]
- name: build
image: vikunja/golang-build:latest
pull: true
environment:
GOPROXY: 'https://goproxy.kolaente.de'
depends_on: [ mage ]
commands:
- ./mage-static build:build
when:
event: [ push, tag, pull_request ]
@ -69,17 +82,10 @@ steps:
GOPROXY: 'https://goproxy.kolaente.de'
depends_on: [ build ]
commands:
- make generate
- make lint
- make fmt-check
# - make got-swag # Commented out until we figured out how to get this working on drone
- make ineffassign-check
- make misspell-check
- make goconst-check
- make gocyclo-check
- make static-check
- wget -O - -q https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $GOPATH/bin v2.2.0 # Need to manually install as it does not support being installed via go modules like the rest.
- make gosec-check
- ./mage-static build:generate
- ./mage-static check:got-swag
- wget -O - -q https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.31.0
- ./mage-static check:golangci
when:
event: [ push, tag, pull_request ]
@ -152,9 +158,9 @@ steps:
environment:
GOPROXY: 'https://goproxy.kolaente.de'
commands:
- make generate
- make test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:unit
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -166,9 +172,9 @@ steps:
VIKUNJA_TESTS_USE_CONFIG: 1
VIKUNJA_DATABASE_TYPE: sqlite
commands:
- make generate
- make test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:unit
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -184,9 +190,9 @@ steps:
VIKUNJA_DATABASE_PASSWORD: vikunjatest
VIKUNJA_DATABASE_DATABASE: vikunjatest
commands:
- make generate
- make test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:unit
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -203,9 +209,9 @@ steps:
VIKUNJA_DATABASE_DATABASE: vikunjatest
VIKUNJA_DATABASE_SSLMODE: disable
commands:
- make generate
- make test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:unit
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -215,9 +221,9 @@ steps:
environment:
GOPROXY: 'https://goproxy.kolaente.de'
commands:
- make generate
- make integration-test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:integration
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -229,9 +235,9 @@ steps:
VIKUNJA_TESTS_USE_CONFIG: 1
VIKUNJA_DATABASE_TYPE: sqlite
commands:
- make generate
- make integration-test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:integration
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -247,9 +253,9 @@ steps:
VIKUNJA_DATABASE_PASSWORD: vikunjatest
VIKUNJA_DATABASE_DATABASE: vikunjatest
commands:
- make generate
- make integration-test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:integration
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -266,9 +272,9 @@ steps:
VIKUNJA_DATABASE_DATABASE: vikunjatest
VIKUNJA_DATABASE_SSLMODE: disable
commands:
- make generate
- make integration-test
depends_on: [ fetch-tags ]
- ./mage-static build:generate
- ./mage-static test:integration
depends_on: [ fetch-tags, mage ]
when:
event: [ push, tag, pull_request ]
@ -299,14 +305,27 @@ steps:
commands:
- git fetch --tags
# We're statically compiling the magefile to avoid race condition issues caused by multiple pipeline steps
# compiling the same magefile at the same time. It's also faster if each step does not need to compile it first.
- name: mage
image: vikunja/golang-build:latest
pull: true
environment:
GOPROXY: 'https://goproxy.kolaente.de'
commands:
- mage -compile ./mage-static
when:
event: [ push, tag, pull_request ]
- name: before-static-build
image: techknowlogick/xgo:latest
pull: true
commands:
- export PATH=$PATH:$GOPATH/bin
- make generate
- make release-dirs
depends_on: [ fetch-tags ]
- go install github.com/magefile/mage
- ./mage-static build:generate
- ./mage-static release:dirs
depends_on: [ fetch-tags, mage ]
- name: static-build-windows
image: techknowlogick/xgo:latest
@ -317,7 +336,8 @@ steps:
GOPATH: /srv/app
commands:
- export PATH=$PATH:$GOPATH/bin
- make release-windows
- go install github.com/magefile/mage
- ./mage-static release:windows
depends_on: [ before-static-build ]
- name: static-build-linux
@ -329,7 +349,8 @@ steps:
GOPATH: /srv/app
commands:
- export PATH=$PATH:$GOPATH/bin
- make release-linux
- go install github.com/magefile/mage
- ./mage-static release:linux
depends_on: [ before-static-build ]
- name: static-build-darwin
@ -341,7 +362,8 @@ steps:
GOPATH: /srv/app
commands:
- export PATH=$PATH:$GOPATH/bin
- make release-darwin
- go install github.com/magefile/mage
- ./mage-static release:darwin
depends_on: [ before-static-build ]
- name: after-build-compress
@ -352,7 +374,7 @@ steps:
- static-build-linux
- static-build-darwin
commands:
- make release-compress
- ./mage-static release:compress
- name: after-build-static
image: techknowlogick/xgo:latest
@ -360,10 +382,11 @@ steps:
depends_on:
- after-build-compress
commands:
- make release-copy
- make release-check
- make release-os-package
- make release-zip
- go install github.com/magefile/mage
- ./mage-static release:copy
- ./mage-static release:check
- ./mage-static release:os-package
- ./mage-static release:zip
- name: sign-release
image: plugins/gpgsign:1
@ -396,8 +419,9 @@ steps:
target: /api/master/
trigger:
branch:
include:
- master
- master
event:
- push
depends_on: [ sign-release ]
- name: release-version
@ -416,21 +440,62 @@ steps:
source: dist/zip/*
target: /api/${DRONE_TAG##v}/
trigger:
ref:
- "refs/tags/**"
branch:
exclude:
- master
event:
- tag
depends_on: [ sign-release ]
# Build a debian package and push it to our bucket
- name: build-deb
image: kolaente/fpm
# Build os packages and push it to our bucket
- name: build-os-packages
image: goreleaser/nfpm
pull: true
commands:
- make build-deb
- apk add git go
- ./mage-static release:packages
depends_on: [ static-build-linux ]
# Push the os releases to our pseudo-s3-bucket
- name: release-os-latest
image: plugins/s3:1
pull: true
settings:
bucket: vikunja-releases
access_key:
from_secret: aws_access_key_id
secret_key:
from_secret: aws_secret_access_key
endpoint: https://s3.fr-par.scw.cloud
region: fr-par
path_style: true
strip_prefix: dist/os-packages/
source: dist/os-packages/*
target: /api/master/
trigger:
branch:
- master
event:
- push
depends_on: [ build-os-packages ]
- name: release-os-version
image: plugins/s3:1
pull: true
settings:
bucket: vikunja-releases
access_key:
from_secret: aws_access_key_id
secret_key:
from_secret: aws_secret_access_key
endpoint: https://s3.fr-par.scw.cloud
region: fr-par
path_style: true
strip_prefix: dist/os-packages/
source: dist/os-packages/*
target: /api/${DRONE_TAG##v}/
trigger:
event:
- tag
depends_on: [ build-os-packages ]
- name: deb-structure
image: kolaente/reprepro
pull: true
@ -446,8 +511,8 @@ steps:
- gpg --import ~/frederik.gpg
- mkdir debian/conf -p
- cp build/reprepro-dist-conf debian/conf/distributions
- make reprepro
depends_on: [ build-deb ]
- ./mage-static release:reprepro
depends_on: [ build-os-packages ]
# Push the releases to our pseudo-s3-bucket
- name: release-deb

View File

@ -6,6 +6,6 @@
* [ ] I added or improved tests
* [ ] I added or improved docs for my feature
* [ ] Swagger (including `make do-the-swag`)
* [ ] Swagger (including `mage do-the-swag`)
* [ ] Error codes
* [ ] New config options
* [ ] New config options (including adding them to `config.yml.saml` and running `mage generate-docs`)

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
custom: https://www.buymeacoffee.com/kolaente

1
.gitignore vendored
View File

@ -22,3 +22,4 @@ files/
!pkg/files/
vikunja-dump*
vendor/
os-packages/

76
.golangci.yml Normal file
View File

@ -0,0 +1,76 @@
run:
timeout: 5m
tests: true
linters:
enable:
- megacheck
- govet
- goconst
- gocritic
- gocyclo
- goerr113
- goheader
- gofmt
- goimports
- golint
- misspell
disable:
- scopelint # Obsolete, using exportloopref instead
presets:
- bugs
- unused
fast: false
linter-settings:
nestif:
min-complexity: 6
goheader:
template-path: code-hesader-template.txt
issues:
exclude-rules:
# Exclude some linters from running on tests files.
- path: _test\.go
linters:
- gocyclo
- deadcode
- path: pkg/integrations/*
linters:
- gocyclo
- deadcode
- varcheck
- unparam
- bodyclose
- path: pkg/integrations/*
text: "unlambda"
linters:
- gocritic
- path: pkg/modules/background/unsplash/unsplash\.go
linters:
- bodyclose
- path: pkg/migration/*
linters:
- exhaustive
- goconst
- goerr113
- path: pkg/models/task_collection_filter\.go
linters:
- exhaustive
- path: pkg/utils/random_string\.go
text: "G404:" # We don't care about cryptographically secure randomness when we're using that utility function.
linters:
- gosec
- path: pkg/modules/dump/*
linters:
- goerr113
- path: pkg/
text: "err113: do not define dynamic errors, use wrapped static errors instead:"
linters:
- goerr113
- text: "commentFormatting: put a space between `//` and comment text"
linters:
- gocritic
- path: pkg/modules/migration
linters:
- gocyclo

View File

@ -16,7 +16,8 @@ WORKDIR ${GOPATH}/src/code.vikunja.io/api
# Checkout version if set
RUN if [ -n "${VIKUNJA_VERSION}" ]; then git checkout "${VIKUNJA_VERSION}"; fi \
&& make clean generate build
&& go install github.com/magefile/mage \
&& mage build:clean build:build
###################
# The actual image

247
Makefile
View File

@ -1,247 +0,0 @@
DIST := dist
IMPORT := code.vikunja.io/api
SED_INPLACE := sed -i
ifeq ($(OS), Windows_NT)
EXECUTABLE := vikunja.exe
else
EXECUTABLE := vikunja
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
SED_INPLACE := sed -i ''
endif
endif
GOFILES := $(shell find . -name "*.go" -type f ! -path "*/bindata.go")
GOFMT ?= gofmt -s
EXTRA_GOFLAGS ?=
GOFLAGS := -v $(EXTRA_GOFLAGS)
LDFLAGS := -X "code.vikunja.io/api/pkg/version.Version=$(shell git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')" -X "main.Tags=$(TAGS)"
PACKAGES ?= $(filter-out code.vikunja.io/api/pkg/integrations,$(shell go list all | grep code\.vikunja\.io\/api))
SOURCES ?= $(shell find . -name "*.go" -type f)
TAGS ?=
ifeq ($(OS), Windows_NT)
EXECUTABLE := vikunja.exe
else
EXECUTABLE := vikunja
endif
ifneq ($(DRONE_TAG),)
VERSION ?= $(subst v,,$(DRONE_TAG))
else
ifneq ($(DRONE_BRANCH),)
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
else
VERSION ?= master
endif
endif
ifeq ($(DRONE_WORKSPACE),'')
BINLOCATION := $(EXECUTABLE)
else
BINLOCATION := $(DIST)/binaries/$(EXECUTABLE)-$(VERSION)-linux-amd64
endif
ifeq ($(VERSION),master)
PKGVERSION := $(shell git describe --tags --always --abbrev=10 | sed 's/-/+/' | sed 's/^v//' | sed 's/-g/-/')
else
PKGVERSION := $(VERSION)
endif
.PHONY: all
all: build
.PHONY: clean
clean:
go clean ./...
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA)
.PHONY: test
test:
# We run everything sequentially and not in parallel to prevent issues with real test databases
VIKUNJA_SERVICE_ROOTPATH=$(shell pwd) go test $(GOFLAGS) -p 1 -cover -coverprofile cover.out $(PACKAGES)
.PHONY: test-coverage
test-coverage: test
go tool cover -html=cover.out -o cover.html
.PHONY: integration-test
integration-test:
# We run everything sequentially and not in parallel to prevent issues with real test databases
VIKUNJA_SERVICE_ROOTPATH=$(shell pwd) go test $(GOFLAGS) -p 1 code.vikunja.io/api/pkg/integrations
.PHONY: lint
lint:
@hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) golang.org/x/lint/golint; \
fi
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
.PHONY: fmt
fmt:
$(GOFMT) -w $(GOFILES)
.PHONY: fmt-check
fmt-check:
# get all go files and run go fmt on them
@diff=$$($(GOFMT) -d $(GOFILES)); \
if [ -n "$$diff" ]; then \
echo "Please run 'make fmt' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
.PHONY: build
build: generate $(EXECUTABLE)
.PHONY: generate
generate:
go generate code.vikunja.io/api/pkg/static
$(EXECUTABLE): $(SOURCES)
go build $(GOFLAGS) -tags '$(TAGS)' -ldflags '-s -w $(LDFLAGS)' -o $@
.PHONY: compress-build
compress-build:
upx -9 $(EXECUTABLE)
.PHONY: release
release: release-dirs release-windows release-linux release-darwin release-copy release-check release-os-package release-zip
.PHONY: release-dirs
release-dirs:
mkdir -p $(DIST)/binaries $(DIST)/release $(DIST)/zip
.PHONY: release-windows
release-windows:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) src.techknowlogick.com/xgo; \
fi
xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out vikunja-$(VERSION) .
ifneq ($(DRONE_WORKSPACE),'')
mv /build/* $(DIST)/binaries
endif
.PHONY: release-linux
release-linux:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) src.techknowlogick.com/xgo; \
fi
xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/*' -out vikunja-$(VERSION) .
ifneq ($(DRONE_WORKSPACE),'')
mv /build/* $(DIST)/binaries
endif
.PHONY: release-darwin
release-darwin:
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) src.techknowlogick.com/xgo; \
fi
xgo -dest $(DIST)/binaries -tags 'netgo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out vikunja-$(VERSION) .
ifneq ($(DRONE_WORKSPACE),'')
mv /build/* $(DIST)/binaries
endif
# Compresses all releases made by make release-* but not mips* releases since upx can't handle these.
.PHONY: release-compress
release-compress:
$(foreach file,$(filter-out $(wildcard $(wildcard $(DIST)/binaries/$(EXECUTABLE)-*mips*)),$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*)), upx -9 $(file);)
.PHONY: release-copy
release-copy:
$(foreach file,$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*),cp $(file) $(DIST)/release/$(notdir $(file));)
.PHONY: release-check
release-check:
cd $(DIST)/release; $(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),sha256sum $(notdir $(file)) > $(notdir $(file)).sha256;)
.PHONY: release-os-package
release-os-package:
$(foreach file,$(filter-out %.sha256,$(wildcard $(DIST)/release/$(EXECUTABLE)-*)),mkdir $(file)-full;mv $(file) $(file)-full/; mv $(file).sha256 $(file)-full/; cp config.yml.sample $(file)-full/config.yml; cp LICENSE $(file)-full/; )
.PHONY: release-zip
release-zip:
$(foreach file,$(wildcard $(DIST)/release/$(EXECUTABLE)-*),cd $(file); zip -r ../../zip/$(shell basename $(file)).zip *; cd ../../../; )
# Builds a deb package using fpm from a previously created binary (using make build)
.PHONY: build-deb
build-deb:
fpm -s dir -t deb --url https://vikunja.io -n vikunja -v $(PKGVERSION) --license GPLv3 --directories /opt/vikunja --after-install ./build/after-install.sh --description 'Vikunja is an open-source todo application, written in Go. It lets you create lists,tasks and share them via teams or directly between users.' -m maintainers@vikunja.io ./$(BINLOCATION)=/opt/vikunja/vikunja ./config.yml.sample=/etc/vikunja/config.yml;
.PHONY: reprepro
reprepro:
reprepro_expect debian includedeb strech ./$(EXECUTABLE)_$(PKGVERSION)_amd64.deb
.PHONY: got-swag
got-swag: do-the-swag
@diff=$$(git diff docs/swagger/swagger.json); \
if [ -n "$$diff" ]; then \
echo "Please run 'make do-the-swag' and commit the result:"; \
echo "$${diff}"; \
exit 1; \
fi;
.PHONY: do-the-swag
do-the-swag:
@hash swag > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) github.com/swaggo/swag/cmd/swag; \
fi
swag init -g pkg/routes/routes.go --parseDependency -o ./pkg/swagger;
# Fix the generated swagger file, currently a workaround until swaggo can properly use go mod
sed -i '/"definitions": {/a "code.vikunja.io.web.HTTPError": {"type": "object","properties": {"code": {"type": "integer"},"message": {"type": "string"}}},' pkg/swagger/docs.go;
sed -i 's/code.vikunja.io\/web.HTTPError/code.vikunja.io.web.HTTPError/g' pkg/swagger/docs.go;
sed -i 's/package\ docs/package\ swagger/g' pkg/swagger/docs.go;
sed -i 's/` + \\"`\\" + `/` + "`" + `/g' pkg/swagger/docs.go;
.PHONY: misspell-check
misspell-check:
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) github.com/client9/misspell/cmd/misspell; \
fi
for S in $(GOFILES); do misspell -error $$S || exit 1; done;
.PHONY: ineffassign-check
ineffassign-check:
@hash ineffassign > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go install $(GOFLAGS) github.com/gordonklaus/ineffassign; \
fi
for S in $(GOFILES); do ineffassign $$S || exit 1; done;
.PHONY: gocyclo-check
gocyclo-check:
@hash gocyclo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/fzipp/gocyclo; \
go install $(GOFLAGS) github.com/fzipp/gocyclo; \
fi
for S in $(GOFILES); do gocyclo -over 49 $$S || exit 1; done;
.PHONY: static-check
static-check:
@hash staticcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u honnef.co/go/tools; \
go install $(GOFLAGS) honnef.co/go/tools/cmd/staticcheck; \
fi
staticcheck $(PACKAGES);
.PHONY: gosec-check
gosec-check:
@hash gosec > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
echo "Please manually install gosec by running"; \
echo "curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | bash -s -- -b $GOPATH/bin v2.2.0"; \
exit 1; \
fi
gosec ./...
.PHONY: goconst-check
goconst-check:
@hash goconst > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
go get -u github.com/jgautheron/goconst/cmd/goconst; \
go install $(GOFLAGS) github.com/jgautheron/goconst/cmd/goconst; \
fi;
for S in $(PACKAGES); do goconst $$S || exit 1; done;

View File

@ -35,7 +35,7 @@ try it on [try.vikunja.io](https://try.vikunja.io)!
* [Installing](https://vikunja.io/docs/installing/)
* [Build from source](https://vikunja.io/docs/build-from-sources/)
* [Development setup](https://vikunja.io/docs/development/)
* [Makefile](https://vikunja.io/docs/makefile/)
* [Magefile](https://vikunja.io/docs/mage/)
* [Testing](https://vikunja.io/docs/testing/)
All docs can be found on [the vikunja home page](https://vikunja.io/docs/).

View File

@ -1,5 +1,4 @@
#!/bin/bash
ln -s /opt/vikunja/vikunja /usr/bin/vikunja
# Fix the config to contain proper values
NEW_SECRET=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)

15
code-header-template.txt Normal file
View File

@ -0,0 +1,15 @@
Vikunja is a to-do list application to facilitate your life.
Copyright 2018-2020 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 General Public License 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

View File

@ -61,8 +61,10 @@ database:
cache:
# If cache is enabled or not
enabled: false
# Cache type. Possible values are memory or redis, you'll need to enable redis below when using redis
type: memory
# Cache type. Possible values are "keyvalue", "memory" or "redis".
# When choosing "keyvalue" this setting follows the one configured in the "keyvalue" section.
# When choosing "redis" you will need to configure the redis connection seperately.
type: keyvalue
# When using memory this defines the maximum size an element can take
maxelementsize: 1000
@ -136,8 +138,10 @@ ratelimit:
period: 60
# The max number of requests a user is allowed to do in the configured time period
limit: 100
# The store where the limit counter for each user is stored. Possible values are "memory" or "redis"
store: memory
# The store where the limit counter for each user is stored.
# Possible values are "keyvalue", "memory" or "redis".
# When choosing "keyvalue" this setting follows the one configured in the "keyvalue" section.
store: keyvalue
files:
# The path where files are stored
@ -205,3 +209,9 @@ backgrounds:
legal:
imprinturl:
privacyurl:
# Key Value Storage settings
# The Key Value Storage is used for different kinds of things like metrics and a few cache systems.
keyvalue:
# The type of the storage backend. Can be either "memory" or "redis". If "redis" is chosen it needs to be configured seperately.
type: "memory"

View File

@ -17,9 +17,9 @@ To learn more about the what, why and how, take a look at [the features page](ht
## Start
A good starting point if you want to install and host Vikunja on your server are [the install documentation](installing)
and [available configuration options](config-options).
A good starting point if you want to install and host Vikunja on your server are [the install documentation]({{< ref "./setup/install.md">}})
and [available configuration options]({{< ref "./setup/config.md">}}).
## Developing
If you want to start contributing to Vikunja, take a look at [the development docs](development).
If you want to start contributing to Vikunja, take a look at [the development docs]({{< ref "./development/development.md">}}).

View File

@ -16,6 +16,8 @@ Additionally, they can also be run directly by using the `migrate` command.
We use [xormigrate](https://github.com/techknowlogick/xormigrate) to handle migrations,
which is based on gormigrate.
{{< table_of_contents >}}
## Add a new migration
All migrations are stored in `pkg/migrations` and files should have the same name as their id.

View File

@ -17,7 +17,9 @@ If you don't intend to add new dependencies, go `1.9` and above should be fine.
To contribute to Vikunja, fork the project and work on the master branch.
A lot of developing tasks are automated using a Makefile, so make sure to [take a look at it]({{< ref "make.md">}}).
A lot of developing tasks are automated using a Magefile, so make sure to [take a look at it]({{< ref "mage.md">}}).
{{< table_of_contents >}}
## Libraries
@ -50,8 +52,8 @@ git remote add origin git@git.kolaente.de:<USERNAME>/api.git
git fetch --all --prune
{{< /highlight >}}
This should provide a working development environment for Vikunja. Take a look at the Makefile to get an overview about
the available tasks. The most common tasks should be `make test` which will start our test environment and `make build`
This should provide a working development environment for Vikunja. Take a look at the Magefile to get an overview about
the available tasks. The most common tasks should be `mage test:unit` which will start our test environment and `mage build:build`
which will build a vikunja binary into the working directory. Writing test cases is not mandatory to contribute, but it
is highly encouraged and helps developers sleep at night.
@ -62,4 +64,4 @@ Thats it! You are ready to hack on Vikunja. Test changes, push them to the re
Each Vikunja release contains all static assets directly compiled into the binary.
To prevent this during development, use the `dev` tag when developing.
See the [make docs](make.md#statically-compile-all-templates-into-the-binary) about how to compile with static assets for a release.
See the [mage docs](mage.md#statically-compile-all-templates-into-the-binary) about how to compile with static assets for a release.

View File

@ -0,0 +1,192 @@
---
date: "2019-02-12:00:00+02:00"
title: "Magefile"
draft: false
type: "doc"
menu:
sidebar:
parent: "development"
---
# 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.
This document explains what taks are available and what they do.
{{< table_of_contents >}}
## Installation
To use mage, you'll need to install the mage cli.
To install it, run the following command:
```
go install github.com/magefile/mage
```
## Categories
There are multiple categories of subcommands in the magefile:
* `build`: Contains commands to build a single binary
* `check`: Contains commands to statically check the source code
* `release`: Contains commands to release Vikunja with everything that's required
* `test`: Contains commands to run all kinds of tests
* `dev`: Contains commands to run development tasks
* `misc`: Commands which do not belong in either of the other categories
## CI
These tasks are automatically run in our CI every time someone pushes to master or you update a pull request:
* `mage check:lint`
* `mage check:fmt`
* `mage check:ineffassign`
* `mage check:misspell`
* `mage check:goconst`
* `mage build:generate`
* `mage build:build`
## Build
### Build Vikunja
{{< highlight bash >}}
mage build:build
{{< /highlight >}}
Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on.
### Statically compile all templates into the binary
{{< highlight bash >}}
mage build:generate
{{< /highlight >}}
This generates static code with all templates, meaning no template need to be referenced at runtime.
### clean
{{< highlight bash >}}
mage build:clean
{{< /highlight >}}
Cleans all build, executable and bindata files
## Check
All check sub-commands exit with a status code of 1 if the check fails.
Various code-checks are available:
* `mage check:all`: Runs fmt-check, lint, got-swag, misspell-check, ineffasign-check, gocyclo-check, static-check, gosec-check, goconst-check all in parallel
* `mage check:fmt`: Checks if the code is properly formatted with go fmt
* `mage check:go-sec`: Checks the source code for potential security issues by scanning the Go AST using the [gosec tool](https://github.com/securego/gosec)
* `mage check:goconst`: Checks for repeated strings that could be replaced by a constant using [goconst](https://github.com/jgautheron/goconst/)
* `mage check:gocyclo`: Checks for the cyclomatic complexity of the source code using [gocyclo](https://github.com/fzipp/gocyclo)
* `mage check:got-swag`: Checks if the swagger docs need to be re-generated from the code annotations
* `mage check:ineffassign`: Checks the source code for ineffectual assigns using [ineffassign](https://github.com/gordonklaus/ineffassign)
* `mage check:lint`: Runs golint on all packages
* `mage check:misspell`: Checks the source code for misspellings
* `mage check:static`: Statically analyzes the source code about a range of different problems using [staticcheck](https://staticcheck.io/docs/)
## Release
### Build Releases
{{< highlight bash >}}
mage release
{{< /highlight >}}
Builds binaries for all platforms and zips them with a copy of the `templates/` folder.
All built zip files are stored into `dist/zips/`. Binaries are stored in `dist/binaries/`,
binaries bundled with `templates` are stored in `dist/releases/`.
All cross-platform binaries built using this series of commands are built with the help of
[xgo](https://github.com/techknowlogick/xgo). The mage command will automatically install the
binary to be able to use it.
`mage release:release` is a shortcut to execute `mage release:dirs release:windows release:linux release:darwin release:copy release:check release:os-package release:zip`.
* `mage release:dirs` creates all directories needed
* `mage release:windows`/`release:linux`/`release:darwin` execute xgo to build for their respective platforms
* `mage release:copy` bundles binaries with a copy of the `LICENSE` and sample config files to then be zipped
* `mage release:check` creates sha256 checksums for each binary which will be included in the zip file
* `mage release:os-package` bundles a binary with the `sha256` checksum file, a sample `config.yml` and a copy of the license in a folder for each architecture
* `mage release:compress` compresses all build binaries with `upx` to save space
* `mage release:zip` paclages a zip file for the files created by `release:os-package`
### Build os packages
{{< highlight bash >}}
mage release:packages
{{< /highlight >}}
Will build `.deb`, `.rpm` and `.apk` packages to `dist/os-packages`.
### Make a debian repo
{{< highlight bash >}}
mage release:reprepro
{{< /highlight >}}
Takes an already built debian package and creates a debian repo structure around it.
Used to be run inside a [docker container](https://git.kolaente.de/konrad/reprepro-docker) in the CI process when releasing.
## Test
### unit
{{< highlight bash >}}
mage test:unit
{{< /highlight >}}
Runs all tests except integration tests.
### coverage
{{< highlight bash >}}
mage test:coverage
{{< /highlight >}}
Runs all tests except integration tests and generates a `coverage.html` file to inspect the code coverage.
### integration
{{< highlight bash >}}
mage test:integration
{{< /highlight >}}
Runs all integration tests.
## Dev
### Create a new migration
{{< highlight bash >}}
mage dev:create-migration
{{< /highlight >}}
Creates a new migration with the current date.
Will ask for the name of the struct you want to create a migration for.
## Misc
### Format the code
{{< highlight bash >}}
mage fmt
{{< /highlight >}}
Formats all source code using `go fmt`.
### Generate swagger definitions from code comments
{{< highlight bash >}}
mage do-the-swag
{{< /highlight >}}
Generates swagger definitions from the comment annotations in the code.

View File

@ -1,151 +0,0 @@
---
date: "2019-02-12:00:00+02:00"
title: "Makefile"
draft: false
type: "doc"
menu:
sidebar:
parent: "development"
---
# Makefile
We scripted a lot of tasks used mostly for developing into the makefile. This documents explains what
taks are available and what they do.
## CI
These tasks are automatically run in our CI every time someone pushes to master or you update a pull request:
* `make lint`
* `make fmt-check`
* `make ineffassign-check`
* `make misspell-check`
* `make goconst-check`
* `make generate`
* `make build`
### clean
{{< highlight bash >}}
make clean
{{< /highlight >}}
Clears all builds and binaries.
### test
{{< highlight bash >}}
make test
{{< /highlight >}}
Runs all tests in Vikunja.
### Format the code
{{< highlight bash >}}
make fmt
{{< /highlight >}}
Formats all source code using `go fmt`.
#### Check formatting
{{< highlight bash >}}
make fmt-check
{{< /highlight >}}
Checks if the code needs to be formatted. Fails if it does.
### Build Vikunja
{{< highlight bash >}}
make build
{{< /highlight >}}
Builds a `vikunja`-binary in the root directory of the repo for the platform it is run on.
### Statically compile all templates into the binary
{{< highlight bash >}}
make generate
{{< /highlight >}}
This generates static code with all templates, meaning no template need to be referenced at runtime.
### Compress the built binary
{{< highlight bash >}}
make compress-build
{{< /highlight >}}
Go binaries are very big.
To make the vikunja binary smaller, we can compress it using [upx](https://upx.github.io/).
### Build Releases
{{< highlight bash >}}
make release
{{< /highlight >}}
Builds binaries for all platforms and zips them with a copy of the `templates/` folder.
All built zip files are stored into `dist/zips/`. Binaries are stored in `dist/binaries/`,
binaries bundled with `templates` are stored in `dist/releases/`.
All cross-platform binaries built using this series of commands are built with the help of
[xgo](https://github.com/techknowlogick/xgo). The make command will automatically install the
binary to be able to use it.
`make release` is actually just a shortcut to execute `make release-dirs release-windows release-linux release-darwin release-copy release-check release-os-package release-zip`.
* `release-dirs` creates all directories needed
* `release-windows`/`release-linux`/`release-darwin` execute xgo to build for their respective platforms
* `release-copy` bundles binaries with a copy of `templates/` to then be zipped
* `release-check` creates sha256 checksums for each binary which will be included in the zip file
* `release-os-package` bundles a binary with a copy of the `templates/` folder, the `sha256` checksum file, a sample `config.yml` and a copy of the license in a folder for each architecture
* `release-compress` compresses all build binaries, see `compress-build`
* `release-zip` makes a zip file for the files created by `release-os-package`
### Build debian packages
{{< highlight bash >}}
make build-deb
{{< /highlight >}}
Will build a `.deb` package into the current folder. You need to have [fpm](https://fpm.readthedocs.io/en/latest/intro.html) installed to be able to do this.
#### Make a debian repo
{{< highlight bash >}}
make reprepro
{{< /highlight >}}
Takes an already built debian package and creates a debian repo structure around it.
Used to be run inside a [docker container](https://git.kolaente.de/konrad/reprepro-docker) in the CI process when releasing.
### Generate swagger definitions from code comments
{{< highlight bash >}}
make do-the-swag
{{< /highlight >}}
Generates swagger definitions from the comments in the code.
#### Check if swagger generation is needed
{{< highlight bash >}}
make got-swag
{{< /highlight >}}
This command is currently more an experiment, use it with caution.
It may bring up wrong results.
### Code-Checks
* `misspell-check`: Checks for commonly misspelled words
* `ineffassign-check`: Checks for ineffectual assignments in the code using [ineffassign](https://github.com/gordonklaus/ineffassign).
* `gocyclo-check`: Calculates cyclomatic complexities of functions using [gocyclo](https://github.com/fzipp/gocyclo).
* `static-check`: Analyzes the code for bugs, improvements and more using [staticcheck](https://staticcheck.io/docs/).
* `gosec-check`: Inspects source code for security problems by scanning the Go AST using the [gosec tool](https://github.com/securego/gosec).
* `goconst-check`: Finds repeated strings that could be replaced by a constant using [goconst](https://github.com/jgautheron/goconst/).

View File

@ -16,12 +16,14 @@ To make this easier, we have put together a few helpers which are documented on
In general, each migrator implements a migrator interface which is then called from a client.
The interface makes it possible to use helper methods which handle http an focus only on the implementation of the migrator itself.
### Structure
{{< table_of_contents >}}
## Structure
All migrator implementations live in their own package in `pkg/modules/migration/<name-of-the-service>`.
When creating a new migrator, you should place all related code inside that module.
### Migrator interface
## Migrator interface
The migrator interface is defined as follows:
@ -41,7 +43,7 @@ type Migrator interface {
}
```
### Defining http routes
## Defining http routes
Once your migrator implements the migration interface, it becomes possible to use the helper http handlers.
Their usage is very similar to the [general web handler](https://kolaente.dev/vikunja/web#user-content-defining-routes-using-the-standard-web-handler):
@ -63,7 +65,7 @@ if config.MigrationWunderlistEnable.GetBool() {
You should also document the routes with [swagger annotations]({{< ref "../practical-instructions/swagger-docs.md" >}}).
### Insertion helper method
## Insertion helper method
There is a method available in the `migration` package which takes a fully nested Vikunja structure and creates it with all relations.
This means you start by adding a namespace, then add lists inside of that namespace, then tasks in the lists and so on.
@ -81,7 +83,7 @@ if err != nil {
err = migration.InsertFromStructure(fullVikunjaHierachie, user)
```
### Configuration
## Configuration
You should add at least an option to enable or disable the migration.
Chances are, you'll need some more options for things like client ID and secret
@ -90,7 +92,7 @@ Chances are, you'll need some more options for things like client ID and secret
The easiest way to implement an on/off switch is to check whether your migration service is enabled or not when
registering the routes, and then simply don't registering the routes in the case it is disabled.
#### Making the migrator public in `/info`
### Making the migrator public in `/info`
You should make your migrator available in the `/info` endpoint so that frontends can display options to enable them or not.
To do this, add an entry to `pkg/routes/api/v1/info.go`.

View File

@ -45,9 +45,11 @@ In general, this api repo has the following structure:
This document will explain what these mean and what you can find where.
{{< table_of_contents >}}
## Root level
The root directory is where [the config file]({{< ref "../setup/config.md">}}), [Makefile]({{< ref "make.md">}}), license, drone config,
The root directory is where [the config file]({{< ref "../setup/config.md">}}), [Magefile]({{< ref "mage.md">}}), license, drone config,
application entry point (`main.go`) and so on are located.
## docker
@ -152,11 +154,11 @@ Every handler function which does not use the standard web handler should live h
### static
All static files generated by `make generate` live here.
All static files generated by `mage generate` live here.
### swagger
This is where the [generated]({{< ref "make.md#generate-swagger-definitions-from-code-comments">}} [api docs]({{< ref "../usage/api.md">}}) live.
This is where the [generated]({{< ref "mage.md#generate-swagger-definitions-from-code-comments">}} [api docs]({{< ref "../usage/api.md">}}) live.
You usually don't need to touch this package.
### user
@ -175,7 +177,7 @@ See their function definitions for instructions on how to use them.
### version
The single purpouse of this package is to hold the current vikunja version which gets overridden through build flags
each time `make release` or `make build` is run.
each time `mage release` or `mage build` is run.
It is a seperate package to avoid import cycles with other packages.
## REST-Tests

View File

@ -10,40 +10,42 @@ menu:
# Testing
You can run unit tests with [our `Makefile`]({{< ref "make.md">}}) with
You can run unit tests with [our `Magefile`]({{< ref "mage.md">}}) with
{{< highlight bash >}}
make test
mage test:unit
{{< /highlight >}}
### Running tests with config
{{< table_of_contents >}}
## 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
## Show sql queries
When `UNIT_TESTS_VERBOSE=1` is set, all sql queries will be shown when tests are run.
### Fixtures
## 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 `make integration-test`.
You can run them by executing `mage test:integration`.
The integration tests use the same config and fixtures as the unit tests and therefor have the same options available,
see at the beginning of this document.
To run integration tests, use `make integration-test`.
To run integration tests, use `mage test:integration`.
# Initializing db fixtures when writing tests
## 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.

View File

@ -18,7 +18,9 @@ This is used whenever you make a call to the database to get or update data.
This xorm instance is set up and initialized every time vikunja is started.
### Adding new database tables
{{< table_of_contents >}}
## Adding new database tables
To add a new table to the database, add a an instance of your struct to the `tables` variable in the
init function in `pkg/models/models.go`. Xorm will sync them automatically.
@ -27,7 +29,7 @@ You also need to add a pointer to the `tablesWithPointer` slice to enable cachin
To learn more about how to configure your struct to create "good" tables, refer to [the xorm documentaion](http://xorm.io/docs/).
### Adding data to test fixtures
## Adding data to test fixtures
Adding data for test fixtures is done in via `yaml` files insinde of `pkg/models/fixtures`.

View File

@ -12,6 +12,8 @@ menu:
This document explains how to use the mailer to send emails and what to do to create a new kind of email to be sent.
{{< table_of_contents >}}
## Sending emails
**Note:** You should use mail templates whenever possible (see below).
@ -30,7 +32,7 @@ type Opts struct {
}
{{< /highlight >}}
## Sending emails based on a template
### Sending emails based on a template
For each mail with a template, there are two email templates: One for plaintext emails, one for html emails.
@ -41,7 +43,7 @@ To send a mail based on a template, use the function `mail.SendMailWithTemplate(
`to` and `subject` are pretty much self-explanatory, `tpl` is the name of the template, without `.html.tmpl` or `.plain.tmpl`.
`data` is a map you can pass additional data to your template.
#### Sending a mail with a template
### Sending a mail with a template
A basic html email template would look like this:

View File

@ -15,6 +15,8 @@ Metrics work by exposing a `/metrics` endpoint which can then be accessed by pro
To keep the load on the database minimal, metrics are stored and updated in redis.
The `metrics` package provides several functions to create and update metrics.
{{< table_of_contents >}}
## New metrics
First, define a `const` with the metric key in redis. This is done in `pkg/metrics/metrics.go`.
@ -41,6 +43,6 @@ Because metrics are stored in redis, you are responsible to increase or decrease
To do this, use `metrics.UpdateCount(value, key)` where `value` is the amount you want to cange it (you can pass
negative values to decrease it) and `key` it the redis key used to define the metric.
# Using it
## Using it
A Prometheus config with a Grafana template is available at [our git repo](https://git.kolaente.de/vikunja/monitoring).

View File

@ -12,7 +12,7 @@ menu:
The api documentation is generated using [swaggo](https://github.com/swaggo/swag) from comments.
### Documenting structs
## Documenting structs
You should always comment every field which will be exposed as a json in the api.
These comments will show up in the documentation, it'll make it easier for developers using the api.

View File

@ -13,6 +13,8 @@ menu:
Vikunja does not store any data outside of the database.
So, all you need to backup are the contents of that database and maybe the config file.
{{< table_of_contents >}}
## MySQL
To create a backup from mysql use the `mysqldump` command:

View File

@ -14,16 +14,16 @@ Vikunja being a go application, has no other dependencies than go itself.
All libraries are bundeled inside the repo in the `vendor/` folder, so all it boils down to are these steps:
1. Make sure [Go](https://golang.org/doc/install) is properly installed on your system. You'll need at least Go `1.9`.
2. Make sure [Make](https://www.gnu.org/software/make/) is properly installed on your system.
2. Make sure [Mage](https://magefile) is properly installed on your system.
3. Clone the repo with `git clone https://code.vikunja.io/api`
3. Run `make build` in the source of this repo. This will build a binary in the root of the repo which will be able to run on your system.
3. Run `mage build:build` in the source of this repo. This will build a binary in the root of the repo which will be able to run on your system.
*Note:* Static ressources such as email templates are built into the binary.
For these to work, you may need to run `make generate` before building the vikunja binary.
When builing entirely with `make`, you dont need to do this, `make generate` will be run automatically when running `make build`.
For these to work, you may need to run `mage build:generate` before building the vikunja binary.
When builing entirely with `mage`, you dont need to do this, `mage build:generate` will be run automatically when running `mage build:build`.
# Build for different architectures
To build for other platforms and architectures than the one you're currently on, simply run `make release` or `make release-{linux|windows|darwin}`.
To build for other platforms and architectures than the one you're currently on, simply run `mage release:release` or `mage release:{linux|windows|darwin}`.
More options are available, please refer to the [makefile docs]({{< ref "../development/make.md">}}) for more details.
More options are available, please refer to the [magefile docs]({{< ref "../development/mage.md">}}) for more details.

View File

@ -27,7 +27,14 @@ first:
child: true
{{< /highlight >}}
## Config file locations
# Formats
Vikunja supports using `toml`, `yaml`, `hcl`, `ini`, `json`, envfile, env variables and Java Properties files.
We reccomend yaml or toml, but you're free to use whatever you want.
Vikunja provides a default [`config.yml`](https://kolaente.dev/vikunja/api/src/branch/master/config.yml.sample) file which you can use as a starting point.
# Config file locations
Vikunja will search on various places for a config file:
@ -38,214 +45,521 @@ Vikunja will search on various places for a config file:
# Default configuration with explanations
This is the same as the `config.yml.sample` file you'll find in the root of vikunja.
The following explains all possible config variables and their defaults.
You can find a full example configuration file in [here](https://code.vikunja.io/api/src/branch/master/config.yml.sample).
{{< highlight yaml >}}
service:
# This token is used to verify issued JWT tokens.
# Default is a random token which will be generated at each startup of vikunja.
# (This means all already issued tokens will be invalid once you restart vikunja)
JWTSecret: "cei6gaezoosah2bao3ieZohkae5aicah"
# The interface on which to run the webserver
interface: ":3456"
# The URL of the frontend, used to send password reset emails.
frontendurl: ""
# The base path on the file system where the binary and assets are.
# Vikunja will also look in this path for a config file, so you could provide only this variable to point to a folder
# with a config file which will then be used.
rootpath: <the path of the executable>
# The max number of items which can be returned per page
maxitemsperpage: 50
# If set to true, enables a /metrics endpoint for prometheus to collect metrics about the system
# You'll need to use redis for this in order to enable common metrics over multiple nodes
enablemetrics: false
# Enable the caldav endpoint, see the docs for more details
enablecaldav: true
# Set the motd message, available from the /info endpoint
motd: ""
# Enable sharing of lists via a link
enablelinksharing: true
# Whether to let new users registering themselves or not
enableregistration: true
# Whether to enable task attachments or not
enabletaskattachments: true
# The time zone all timestamps are in
timezone: GMT
# Whether task comments should be enabled or not
enabletaskcomments: true
# Whether totp is enabled. In most cases you want to leave that enabled.
enabletotp: true
# If not empty, enables logging of crashes and unhandled errors in sentry.
sentrydsn: ''
If you don't provide a value in your config file, their default will be used.
database:
# Database type to use. Supported types are mysql, postgres and sqlite.
type: "sqlite"
# Database user which is used to connect to the database.
user: "vikunja"
# Databse password
password: ""
# Databse host
host: "localhost"
# Databse to use
database: "vikunja"
# When using sqlite, this is the path where to store the data
path: "./vikunja.db"
# Sets the max open connections to the database. Only used when using mysql and postgres.
maxopenconnections: 100
# Sets the maximum number of idle connections to the db.
maxidleconnections: 50
# The maximum lifetime of a single db connection in miliseconds.
maxconnectionlifetime: 10000
# Secure connection mode. Only used with postgres.
# (see https://pkg.go.dev/github.com/lib/pq?tab=doc#hdr-Connection_String_Parameters)
sslmode: disable
## Nesting
cache:
# If cache is enabled or not
enabled: false
# Cache type. Possible values are memory or redis, you'll need to enable redis below when using redis
type: memory
# When using memory this defines the maximum size an element can take
maxelementsize: 1000
Most config variables are nested under some "higher-level" key.
For example, the `interface` config variable is a child of the `service` key.
redis:
# Whether to enable redis or not
enabled: false
# The host of the redis server including its port.
host: 'localhost:6379'
# The password used to authenicate against the redis server
password: ''
# 0 means default database
db: 0
The docs below aim to reflect that leveling, but please also have a lookt at [the default config](https://code.vikunja.io/api/src/branch/master/config.yml.sample) file
to better grasp how the nesting looks like.
cors:
# Whether to enable or disable cors headers.
# Note: If you want to put the frontend and the api on seperate domains or ports, you will need to enable this.
# Otherwise the frontend won't be able to make requests to the api through the browser.
enable: true
# A list of origins which may access the api.
origins:
- *
# How long (in seconds) the results of a preflight request can be cached.
maxage: 0
<!-- Generated config will be injected here -->
mailer:
# Whether to enable the mailer or not. If it is disabled, all users are enabled right away and password reset is not possible.
enabled: false
# SMTP Host
host: ""
# SMTP Host port
port: 587
# SMTP username
username: "user"
# SMTP password
password: ""
# Wether to skip verification of the tls certificate on the server
skiptlsverify: false
# The default from address when sending emails
fromemail: "mail@vikunja"
# The length of the mail queue.
queuelength: 100
# The timeout in seconds after which the current open connection to the mailserver will be closed.
queuetimeout: 30
# By default, vikunja will try to connect with starttls, use this option to force it to use ssl.
forcessl: false
---
log:
# A folder where all the logfiles should go.
path: <rootpath>logs
# Whether to show any logging at all or none
enabled: true
# Where the normal log should go. Possible values are stdout, stderr, file or off to disable standard logging.
standard: "stdout"
# Change the log level. Possible values (case-insensitive) are CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG.
level: "INFO"
# Whether or not to log database queries. Useful for debugging. Possible values are stdout, stderr, file or off to disable database logging.
database: "off"
# The log level for database log messages. Possible values (case-insensitive) are CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG.
databaselevel: "WARNING"
# Whether to log http requests or not. Possible values are stdout, stderr, file or off to disable http logging.
http: "stdout"
# Echo has its own logging which usually is unnessecary, which is why it is disabled by default. Possible values are stdout, stderr, file or off to disable standard logging.
echo: "off"
ratelimit:
# whether or not to enable the rate limit
enabled: false
# The kind on which rates are based. Can be either "user" for a rate limit per user or "ip" for an ip-based rate limit.
kind: user
# The time period in seconds for the limit
period: 60
# The max number of requests a user is allowed to do in the configured time period
limit: 100
# The store where the limit counter for each user is stored. Possible values are "memory" or "redis"
store: memory
## service
files:
# The path where files are stored
basepath: ./files # relative to the binary
# The maximum size of a file, as a human-readable string.
# Warning: The max size is limited 2^64-1 bytes due to the underlying datatype
maxsize: 20MB
migration:
# These are the settings for the wunderlist migrator
wunderlist:
# Wheter to enable the wunderlist migrator or not
enable: false
# The client id, required for making requests to the wunderlist api
# You need to register your vikunja instance at https://developer.wunderlist.com/apps/new to get this
clientid:
# The client secret, also required for making requests to the wunderlist api
clientsecret:
# The url where clients are redirected after they authorized Vikunja to access their wunderlist stuff.
# This needs to match the url you entered when registering your Vikunja instance at wunderlist.
# This is usually the frontend url where the frontend then makes a request to /migration/wunderlist/migrate
# with the code obtained from the wunderlist api.
# Note that the vikunja frontend expects this to be /migrate/wunderlist
redirecturl:
todoist:
# Wheter to enable the todoist migrator or not
enable: false
# The client id, required for making requests to the wunderlist api
# You need to register your vikunja instance at https://developer.todoist.com/appconsole.html to get this
clientid:
# The client secret, also required for making requests to the todoist api
clientsecret:
# The url where clients are redirected after they authorized Vikunja to access their todoist items.
# This needs to match the url you entered when registering your Vikunja instance at todoist.
# This is usually the frontend url where the frontend then makes a request to /migration/todoist/migrate
# with the code obtained from the todoist api.
# Note that the vikunja frontend expects this to be /migrate/todoist
redirecturl:
avatar:
# When using gravatar, this is the duration in seconds until a cached gravatar user avatar expires
gravatarexpiration: 3600
### JWTSecret
backgrounds:
# Whether to enable backgrounds for lists at all.
enabled: true
providers:
upload:
# Whethere to enable uploaded list backgrounds
enabled: true
unsplash:
# Whether to enable setting backgrounds from unsplash as list backgrounds
enabled: false
# You need to create an application for your installation at https://unsplash.com/oauth/applications/new
# and set the access token below.
accesstoken:
# The unsplash application id is only used for pingback and required as per their api guidelines.
# You can find the Application ID in the dashboard for your API application. It should be a numeric ID.
# It will only show in the UI if your application has been approved for Enterprise usage, therefore if
# youre in Demo mode, you can also find the ID in the URL at the end: https://unsplash.com/oauth/applications/:application_id
applicationid:
This token is used to verify issued JWT tokens.
Default is a random token which will be generated at each startup of vikunja.
(This means all already issued tokens will be invalid once you restart vikunja)
Default: `<jwt-secret>`
### interface
The interface on which to run the webserver
Default: `:3456`
### frontendurl
The URL of the frontend, used to send password reset emails.
Default: `<empty>`
### rootpath
The base path on the file system where the binary and assets are.
Vikunja will also look in this path for a config file, so you could provide only this variable to point to a folder
with a config file which will then be used.
Default: `<rootpath>`
### maxitemsperpage
The max number of items which can be returned per page
Default: `50`
### enablemetrics
If set to true, enables a /metrics endpoint for prometheus to collect metrics about the system
You'll need to use redis for this in order to enable common metrics over multiple nodes
Default: `false`
### enablecaldav
Enable the caldav endpoint, see the docs for more details
Default: `true`
### motd
Set the motd message, available from the /info endpoint
Default: `<empty>`
### enablelinksharing
Enable sharing of lists via a link
Default: `true`
### enableregistration
Whether to let new users registering themselves or not
Default: `true`
### enabletaskattachments
Whether to enable task attachments or not
Default: `true`
### timezone
The time zone all timestamps are in
Default: `GMT`
### enabletaskcomments
Whether task comments should be enabled or not
Default: `true`
### enabletotp
Whether totp is enabled. In most cases you want to leave that enabled.
Default: `true`
### sentrydsn
If not empty, enables logging of crashes and unhandled errors in sentry.
Default: `<empty>`
---
## database
### type
Database type to use. Supported types are mysql, postgres and sqlite.
Default: `sqlite`
### user
Database user which is used to connect to the database.
Default: `vikunja`
### password
Databse password
Default: `<empty>`
### host
Databse host
Default: `localhost`
### database
Databse to use
Default: `vikunja`
### path
When using sqlite, this is the path where to store the data
Default: `./vikunja.db`
### maxopenconnections
Sets the max open connections to the database. Only used when using mysql and postgres.
Default: `100`
### maxidleconnections
Sets the maximum number of idle connections to the db.
Default: `50`
### maxconnectionlifetime
The maximum lifetime of a single db connection in miliseconds.
Default: `10000`
### sslmode
Secure connection mode. Only used with postgres.
(see https://pkg.go.dev/github.com/lib/pq?tab=doc#hdr-Connection_String_Parameters)
Default: `disable`
---
## cache
### enabled
If cache is enabled or not
Default: `false`
### type
Cache type. Possible values are "keyvalue", "memory" or "redis".
When choosing "keyvalue" this setting follows the one configured in the "keyvalue" section.
When choosing "redis" you will need to configure the redis connection seperately.
Default: `keyvalue`
### maxelementsize
When using memory this defines the maximum size an element can take
Default: `1000`
---
## redis
### enabled
Whether to enable redis or not
Default: `false`
### host
The host of the redis server including its port.
Default: `localhost:6379`
### password
The password used to authenicate against the redis server
Default: `<empty>`
### db
0 means default database
Default: `0`
---
## cors
### enable
Whether to enable or disable cors headers.
Note: If you want to put the frontend and the api on seperate domains or ports, you will need to enable this.
Otherwise the frontend won't be able to make requests to the api through the browser.
Default: `true`
### origins
A list of origins which may access the api.
Default: `<empty>`
### maxage
How long (in seconds) the results of a preflight request can be cached.
Default: `0`
---
## mailer
### enabled
Whether to enable the mailer or not. If it is disabled, all users are enabled right away and password reset is not possible.
Default: `false`
### host
SMTP Host
Default: `<empty>`
### port
SMTP Host port
Default: `587`
### username
SMTP username
Default: `user`
### password
SMTP password
Default: `<empty>`
### skiptlsverify
Wether to skip verification of the tls certificate on the server
Default: `false`
### fromemail
The default from address when sending emails
Default: `mail@vikunja`
### queuelength
The length of the mail queue.
Default: `100`
### queuetimeout
The timeout in seconds after which the current open connection to the mailserver will be closed.
Default: `30`
### forcessl
By default, vikunja will try to connect with starttls, use this option to force it to use ssl.
Default: `false`
---
## log
### path
A folder where all the logfiles should go.
Default: `<rootpath>logs`
### enabled
Whether to show any logging at all or none
Default: `true`
### standard
Where the normal log should go. Possible values are stdout, stderr, file or off to disable standard logging.
Default: `stdout`
### level
Change the log level. Possible values (case-insensitive) are CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG.
Default: `INFO`
### database
Whether or not to log database queries. Useful for debugging. Possible values are stdout, stderr, file or off to disable database logging.
Default: `off`
### databaselevel
The log level for database log messages. Possible values (case-insensitive) are CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG.
Default: `WARNING`
### http
Whether to log http requests or not. Possible values are stdout, stderr, file or off to disable http logging.
Default: `stdout`
### echo
Echo has its own logging which usually is unnessecary, which is why it is disabled by default. Possible values are stdout, stderr, file or off to disable standard logging.
Default: `off`
---
## ratelimit
### enabled
whether or not to enable the rate limit
Default: `false`
### kind
The kind on which rates are based. Can be either "user" for a rate limit per user or "ip" for an ip-based rate limit.
Default: `user`
### period
The time period in seconds for the limit
Default: `60`
### limit
The max number of requests a user is allowed to do in the configured time period
Default: `100`
### store
The store where the limit counter for each user is stored.
Possible values are "keyvalue", "memory" or "redis".
When choosing "keyvalue" this setting follows the one configured in the "keyvalue" section.
Default: `keyvalue`
---
## files
### basepath
The path where files are stored
Default: `./files`
### maxsize
The maximum size of a file, as a human-readable string.
Warning: The max size is limited 2^64-1 bytes due to the underlying datatype
Default: `20MB`
---
## migration
### wunderlist
These are the settings for the wunderlist migrator
Default: `<empty>`
### todoist
Default: `<empty>`
---
## avatar
### gravatarexpiration
When using gravatar, this is the duration in seconds until a cached gravatar user avatar expires
Default: `3600`
---
## backgrounds
### enabled
Whether to enable backgrounds for lists at all.
Default: `true`
### providers
Default: `<empty>`
---
## legal
Legal urls
Will be shown in the frontend if configured here
### imprinturl
Default: `<empty>`
### privacyurl
Default: `<empty>`
---
## keyvalue
Key Value Storage settings
The Key Value Storage is used for different kinds of things like metrics and a few cache systems.
### type
The type of the storage backend. Can be either "memory" or "redis". If "redis" is chosen it needs to be configured seperately.
Default: `memory`
# Legal urls
# Will be shown in the frontend if configured here
legal:
imprinturl:
privacyurl:
{{< /highlight >}}

View File

@ -17,6 +17,8 @@ We'll use [docker compose](https://docs.docker.com/compose/) to make handling th
> If you have any issues setting up vikunja, please don't hesitate to reach out to us via [matrix](https://riot.im/app/#/room/!dCRiCiLaCCFVNlDnYs:matrix.org?via=matrix.org), the [community forum](https://community.vikunja.io/) or even [email](mailto:hello@vikunja.io).
{{< table_of_contents >}}
## Preparations (optional)
Create a directory for the project where all data and the compose file will live in.

View File

@ -21,7 +21,9 @@ For all available configuration options, see [configuration]({{< ref "config.md"
All examples on this page already reflect this and do not require additional work.
</div>
### Redis
{{< table_of_contents >}}
## Redis
To use redis, you'll need to add this to the config examples below:

View File

@ -15,6 +15,8 @@ menu:
<a href="{{< ref "utf-8.md">}}">make sure your db is utf-8 compatible</a>.
</div>
{{< table_of_contents >}}
## Install from binary
Download a copy of Vikunja from the [download page](https://vikunja.io/en/download/) for your architecture.
@ -176,6 +178,100 @@ dpkg -i vikunja.deb
This will install the backend to `/opt/vikunja`.
To configure it, use the config file in `/etc/vikunja/config.yml`.
## FreeBSD / FreeNAS
Unfortunately, we currently can't provide pre-built binaries for FreeBSD.
As a workaround, it is possible to compile vikunja for FreeBSD directly on a FreeBSD machine, a guide is available below:
*Thanks to HungrySkeleton who originally created this guide [in the forum](https://community.vikunja.io/t/freebsd-support/69/11).*
### Jail Setup
1. Create jail named ```vikunja```
2. Set jail properties to 'auto start'
3. Mount storage (```/mnt``` to ```jailData/vikunja```)
4. Start jail & SSH into it
### Installing packages
{{< highlight bash >}}
pkg update && pkg upgrade -y
pkg install nano git go gmake
go install github.com/magefile/mage
{{< /highlight >}}
### Clone vikunja repo
{{< highlight bash >}}
mkdir /mnt/GO/code.vikunja.io
cd /mnt/GO/code.vikunja.io
git clone https://code.vikunja.io/api
cd /mnt/GO/code.vikunja.io/api
{{< /highlight >}}
### Compile binaries
{{< highlight bash >}}
go install
mage build
{{< /highlight >}}
### Create folder to install backend server into
{{< highlight bash >}}
mkdir /mnt/backend
cp /mnt/GO/code.vikunja.io/api/vikunja /mnt/backend/vikunja
cd /mnt/backend
chmod +x /mnt/backend/vikunja
{{< /highlight >}}
### Set vikunja to boot on startup
{{< highlight bash >}}
nano /etc/rc.d/vikunja
{{< /highlight >}}
Then paste into the file:
{{< highlight bash >}}
#!/bin/sh
. /etc/rc.subr
name=vikunja
rcvar=vikunja_enable
command="/mnt/backend/${name}"
load_rc_config $name
run_rc_command "$1"
{{< /highlight >}}
Save and exit. Then execute:
{{< highlight bash >}}
chmod +x /etc/rc.d/vikunja
nano /etc/rc.conf
{{< /highlight >}}
Then add line to bottom of file:
{{< highlight bash >}}
vikunja_enable="YES"
{{< /highlight >}}
Test vikunja now works with
{{< highlight bash >}}
service vikunja start
{{< /highlight >}}
The API is now available through IP:
```
192.168.1.XXX:3456
```
## Configuration
See [available configuration options]({{< ref "config.md">}}).

View File

@ -17,6 +17,8 @@ Unzip them and store them somewhere your server can access them.
You also need to configure a rewrite condition to internally redirect all requests to `index.html` which handles all urls.
{{< table_of_contents >}}
## API URL configuration
By default, the frontend assumes it can reach the api at `/api/v1` relative to the frontend url.

View File

@ -13,6 +13,8 @@ menu:
These examples assume you have an instance of the backend running on your server listening on port `3456`.
If you've changed this setting, you need to update the server configurations accordingly.
{{< table_of_contents >}}
## NGINX
Below are two example configurations which you can put in your `nginx.conf`:

View File

@ -17,6 +17,8 @@ Vikunja itself will work just fine until you want to use non-latin characters in
On this page, you will find information about how to fully ensure non-latin characters like aüäß or emojis work
with your installation.
{{< table_of_contents >}}
## Postgresql & SQLite
Postgresql and SQLite should handle utf-8 just fine - If you discover any issues nonetheless, please
@ -49,11 +51,11 @@ The charset `latin1` means the db is encoded in the `latin1` encoding which does
(The following guide is based on [this thread from stackoverflow](https://dba.stackexchange.com/a/104866))
#### 0. Backup your database
### 0. Backup your database
Before attempting any conversion, please [back up your database]({{< ref "backups.md">}}).
#### 1. Create a pre-conversion script
### 1. Create a pre-conversion script
Copy the following sql statements in a file called `preAlterTables.sql` and replace all occurences of `vikunja` with
the name of your database:
@ -70,7 +72,7 @@ SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column
FROM `COLUMNS` where table_schema like 'vikunja' and data_type in ('text','tinytext','mediumtext','longtext');
{{< /highlight >}}
#### 2. Run the pre-conversion script
### 2. Run the pre-conversion script
Running this will create the actual migration script for your particular database structure and save it in a file called `alterTables.sql`:
@ -78,7 +80,7 @@ Running this will create the actual migration script for your particular databas
mysql -uroot < preAlterTables.sql | egrep '^ALTER' > alterTables.sql
{{< /highlight >}}
#### 3. Convert the database
### 3. Convert the database
At this point converting is just a matter of executing the previously generated sql script:
@ -86,7 +88,7 @@ At this point converting is just a matter of executing the previously generated
mysql -uroot < alterTables.sql
{{< /highlight >}}
#### 4. Verify it was successfully converted
### 4. Verify it was successfully converted
If everything worked as intended, your db collation should now look like this:

View File

@ -16,6 +16,8 @@ menu:
Vikunja supports managing tasks via the [caldav VTODO](https://tools.ietf.org/html/rfc5545#section-3.6.2) extension.
{{< table_of_contents >}}
## URLs
All urls are located under the `/dav` subspace.
@ -64,11 +66,11 @@ Vikunja **currently does not** support these properties:
## Tested Clients
#### Working
### Working
* [Evolution](https://wiki.gnome.org/Apps/Evolution/)
#### Not working
### Not working
* [Tasks (Android)](https://tasks.org/)

View File

@ -12,13 +12,15 @@ menu:
This document describes the different errors Vikunja can return.
### Generic
{{< table_of_contents >}}
## Generic
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 0001 | 403 | Generic forbidden error. |
### User
## User
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
@ -39,14 +41,14 @@ This document describes the different errors Vikunja can return.
| 1017 | 412 | The provided Totp passcode is invalid. |
| 1018 | 412 | The provided user avatar provider type setting is invalid. |
### Validation
## Validation
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 2001 | 400 | ID cannot be empty or 0. |
| 2002 | 400 | Some of the request data was invalid. The response contains an aditional array with all invalid fields. |
### List
## List
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
@ -57,7 +59,7 @@ This document describes the different errors Vikunja can return.
| 3007 | 400 | A list with this identifier already exists. |
| 3008 | 412 | The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list. |
### Task
## Task
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
@ -81,7 +83,7 @@ This document describes the different errors Vikunja can return.
| 4018 | 403 | Invalid task filter concatinator. |
| 4019 | 403 | Invalid task filter value. |
### Namespace
## Namespace
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
@ -93,7 +95,7 @@ This document describes the different errors Vikunja can return.
| 5011 | 409 | This user has already access to that namespace. |
| 5012 | 412 | The namespace is archived and can therefore only be accessed read only. |
### Team
## Team
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
@ -104,14 +106,14 @@ This document describes the different errors Vikunja can return.
| 6006 | 400 | Cannot delete the last team member. |
| 6007 | 403 | The team does not have access to the list to perform that action. |
### User List Access
## User List Access
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 7002 | 409 | The user already has access to that list. |
| 7003 | 403 | The user does not have access to that list. |
### Label
## Label
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
@ -119,16 +121,24 @@ This document describes the different errors Vikunja can return.
| 8002 | 404 | The label does not exist. |
| 8003 | 403 | The user does not have access to this label. |
### Right
## Right
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 9001 | 403 | The right is invalid. |
### Kanban
## Kanban
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 10001 | 404 | The bucket does not exist. |
| 10002 | 400 | The bucket does not belong to that list. |
| 10003 | 412 | You cannot remove the last bucket on a list. |
| 10004 | 412 | You cannot add the task to this bucket as it already exceeded the limit of tasks it can hold. |
## Saved Filters
| ErrorCode | HTTP Status Code | Description |
|-----------|------------------|-------------|
| 11001 | 404 | The saved filter does not exist. |
| 11002 | 412 | Saved filters are not available for link shares. |

View File

@ -23,7 +23,7 @@ The following values are possible:
| 1 | Read and write. Namespaces or lists shared with this right can be read and written to by the team or user. |
| 2 | Admin. Can do anything like read and write, but can additionally manage sharing options. |
### Team admins
## Team admins
When adding or querying a team, every member has an additional boolean value stating if it is admin or not.
A team admin can also add and remove team members and also change whether a user in the team is admin or not.

2
docs/themes/vikunja vendored

@ -1 +1 @@
Subproject commit a17ba5976906ee431943798c08e4d3c38689590d
Subproject commit 958219fc84db455ed58d7a4380bbffc8d04fd5cf

48
go.mod
View File

@ -21,59 +21,67 @@ require (
code.vikunja.io/web v0.0.0-20200809154828-8767618f181f
gitea.com/xorm/xorm-redis-cache v0.2.0
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/asaskevich/govalidator v0.0.0-20200819183940-29e1ff8eb0bb
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef
github.com/beevik/etree v1.1.0 // indirect
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2
github.com/client9/misspell v0.3.4
github.com/cweill/gotests v1.5.3
github.com/d4l3k/messagediff v1.2.1 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/disintegration/imaging v1.6.2
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835
github.com/fzipp/gocyclo v0.3.0
github.com/gabriel-vasile/mimetype v1.1.1
github.com/getsentry/sentry-go v0.7.0
github.com/go-errors/errors v1.1.1
github.com/go-openapi/swag v0.19.9 // indirect
github.com/go-redis/redis/v7 v7.4.0
github.com/go-sql-driver/mysql v1.5.0
github.com/go-testfixtures/testfixtures/v3 v3.4.0
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
github.com/google/go-cmp v0.5.2 // indirect
github.com/gordonklaus/ineffassign v0.0.0-20200809085317-e36bfde3bb78
github.com/iancoleman/strcase v0.1.0
github.com/iancoleman/strcase v0.1.2
github.com/imdario/mergo v0.3.11
github.com/jgautheron/goconst v0.0.0-20200227150835-cda7ea3bf591
github.com/jgautheron/goconst v0.0.0-20200920201509-8f5268ce89d5
github.com/kr/text v0.2.0 // indirect
github.com/labstack/echo/v4 v4.1.16
github.com/labstack/echo/v4 v4.1.17
github.com/labstack/gommon v0.3.0
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef
github.com/lib/pq v1.8.0
github.com/mailru/easyjson v0.7.0 // indirect
github.com/mattn/go-sqlite3 v1.14.1
github.com/magefile/mage v1.10.0
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-sqlite3 v1.14.4
github.com/mitchellh/mapstructure v1.3.2 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/olekukonko/tablewriter v0.0.4
github.com/onsi/ginkgo v1.12.0 // indirect
github.com/onsi/gomega v1.9.0 // indirect
github.com/onsi/ginkgo v1.13.0 // indirect
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pelletier/go-toml v1.4.0 // indirect
github.com/pelletier/go-toml v1.8.0 // indirect
github.com/pquerna/otp v1.2.0
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/client_golang v1.8.0
github.com/samedi/caldav-go v3.0.0+incompatible
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
github.com/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c
github.com/spf13/afero v1.3.4
github.com/spf13/cobra v1.0.0
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
github.com/spf13/afero v1.4.1
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.1
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.6.1
github.com/swaggo/swag v1.6.7
github.com/swaggo/swag v1.6.8
github.com/ulule/limiter/v3 v3.5.0
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/image v0.0.0-20200801110659-972c09e46d76
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5
golang.org/x/lint v0.0.0-20200302205851-738671d3881b
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef // indirect
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 // indirect
golang.org/x/sync v0.0.0-20201008141435-b3e1573b7520
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/d4l3k/messagediff.v1 v1.2.1
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.57.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
honnef.co/go/tools v0.0.1-2020.1.5
src.techknowlogick.com/xgo v1.1.1-0.20200811225412-bff6512e7c9c
src.techknowlogick.com/xormigrate v1.3.0

284
go.sum
View File

@ -1,7 +1,5 @@
4d63.com/embedfiles v0.0.0-20190311033909-995e0740726f h1:oyYjGRBNq1TxAIG8aHqtxlvqUfzdZf+MbcRb/oweNfY=
4d63.com/embedfiles v0.0.0-20190311033909-995e0740726f/go.mod h1:HxEsUxoVZyRxsZML/S6e2xAuieFMlGO0756ncWx1aXE=
4d63.com/tz v1.1.0 h1:Hi58WbeFjiUH4XOWuCpl5iSzuUuw1axZzTqIfMKPKrg=
4d63.com/tz v1.1.0/go.mod h1:SHGqVdL7hd2ZaX2T9uEiOZ/OFAUfCCLURdLPJsd8ZNs=
4d63.com/tz v1.2.0 h1:EpJt060xY+M+M0Wj8btz+THdOJbSxj4i8jhVQP3Wr0U=
4d63.com/tz v1.2.0/go.mod h1:SHGqVdL7hd2ZaX2T9uEiOZ/OFAUfCCLURdLPJsd8ZNs=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
@ -36,6 +34,7 @@ github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EF
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
@ -49,28 +48,30 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4=
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200817114649-df4adffc9d8c h1:W9P/cRMhwMMfrtInPTAn5rcNu/+vb3zKdGeAd+87tFs=
github.com/asaskevich/govalidator v0.0.0-20200817114649-df4adffc9d8c/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20200818142706-50839af6027e h1:6P0tOQaAiB0G+etsknZvSDjNpdYshZ7wFXTqJpl41h0=
github.com/asaskevich/govalidator v0.0.0-20200818142706-50839af6027e/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/asaskevich/govalidator v0.0.0-20200819183940-29e1ff8eb0bb h1:kvlW1qyM1aU3xeyeIVTU2jx5fSvjKpsU3aXvuaCMg3Q=
github.com/asaskevich/govalidator v0.0.0-20200819183940-29e1ff8eb0bb/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
@ -84,16 +85,22 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
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-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I=
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2 h1:t8KYCwSKsOEZBFELI4Pn/phbp38iJ1RRAkDFNin1aak=
github.com/c2h5oh/datasize v0.0.0-20200825124411-48ed595a09d2/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@ -101,6 +108,7 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
@ -128,22 +136,29 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835 h1:roDmqJ4Qes7hrDOsWsMCce0vQHz3xiMPjJ9m4c2eeNs=
github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835/go.mod h1:BjL/N0+C+j9uNX+1xcNuM9vdSIcXCZrQZUYbXOFbgN8=
github.com/fzipp/gocyclo v0.3.0 h1:GGYiyz9o4lDXRn4hA3FidRkR3agaTwbDEMd98qFG6Lk=
github.com/fzipp/gocyclo v0.3.0/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E=
github.com/gabriel-vasile/mimetype v1.1.1 h1:qbN9MPuRf3bstHu9zkI9jDWNfH//9+9kHxr9oRBBBOA=
github.com/gabriel-vasile/mimetype v1.1.1/go.mod h1:6CDPel/o/3/s4+bp6kIbsWATq8pmgOisOPG40CJa6To=
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
@ -160,35 +175,39 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-openapi/jsonpointer v0.17.0 h1:nH6xp8XdXHx8dqveo0ZuJBluCO2qGrPbDNZ0dwoRHP0=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0 h1:yJW3HCkTHg7NOA+gZ83IPHzUSnUzGXhGmsdiCcMexbA=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk=
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/jsonreference v0.19.4 h1:3Vw+rh13uq2JFNxgnMTGE1rnoieU9FmyE1gvnyylsYg=
github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4=
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.4 h1:ixzUSnHTd6hCemgtAJgluaTSGYpLNpJY4mA2DIkdOAo=
github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/spec v0.19.9 h1:9z9cbFuZJ7AcvOHKIY+f6Aevb4vObNDkTEyoMfO7rAc=
github.com/go-openapi/spec v0.19.9/go.mod h1:vqK/dIdLGCosfvYsQV3WfC7N3TiZSnGY2RZKoFK7X28=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE=
github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY=
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=
@ -197,6 +216,7 @@ github.com/go-redis/redis/v7 v7.2.0 h1:CrCexy/jYWZjW0AyVoHlcJUeZN19VWlbepTh1Vq6d
github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4=
github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
@ -210,6 +230,9 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
@ -218,7 +241,9 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@ -236,6 +261,8 @@ github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@ -249,12 +276,15 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@ -263,15 +293,21 @@ github.com/gordonklaus/ineffassign v0.0.0-20200809085317-e36bfde3bb78 h1:U/zHjaV
github.com/gordonklaus/ineffassign v0.0.0-20200809085317-e36bfde3bb78/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
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/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
@ -294,15 +330,15 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334 h1:VHgatEHNcBFEB7inlalqfNqw65aNkM1lGX2yt3NmbS8=
github.com/iancoleman/strcase v0.0.0-20191112232945-16388991a334/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.1.0 h1:Lar8rut26AXkJUmVOb2bRsFGv//+tJBeJLxXvpZpF1Q=
github.com/iancoleman/strcase v0.1.0/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/iancoleman/strcase v0.1.2 h1:gnomlvw9tnV3ITTAxzKSgTF+8kFWcU/f+TgttpXGz1U=
github.com/iancoleman/strcase v0.1.2/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
@ -365,13 +401,19 @@ github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl
github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/jeffbean/tail v1.0.1 h1:mRuCwa9iq5kH1SBFAIWWFsg+NEi5+VVEf2E2ORVkKp8=
github.com/jeffbean/tail v1.0.1/go.mod h1:+MhJ+VPZMpv8Ui6WRzpJFuWFKxBCZgVOo5HAmlw1sFc=
github.com/jgautheron/goconst v0.0.0-20200227150835-cda7ea3bf591 h1:x/BpEhm6aL26o4TLtcU0loJ7B3+69jielrGc70V7Yb4=
github.com/jgautheron/goconst v0.0.0-20200227150835-cda7ea3bf591/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jgautheron/goconst v0.0.0-20200920201509-8f5268ce89d5 h1:LlI/THEqi2n5RNtIIplDTGNCQ6m81r2tem36s7XSxtU=
github.com/jgautheron/goconst v0.0.0-20200920201509-8f5268ce89d5/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
@ -381,6 +423,7 @@ github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0b
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
@ -398,12 +441,12 @@ github.com/kolaente/fsnotify v1.4.10-0.20200411160148-1bc3c8ff4048 h1:j/BtLkVyqt
github.com/kolaente/fsnotify v1.4.10-0.20200411160148-1bc3c8ff4048/go.mod h1:dv6KyzAg9UuJWiE1pwkvvB2i0TvcQM6QhdsXLZ7K5KI=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
@ -412,6 +455,8 @@ 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 h1:8swiwjE5Jkai3RPfZoahp8kjVCRNq+y7Q0hPji2Kz0o=
github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
github.com/labstack/echo/v4 v4.1.17 h1:PQIBaRplyRy3OjwILGkPg89JRtH2x5bssi59G2EL3fo=
github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef h1:RZnRnSID1skF35j/15KJ6hKZkdIC/teQClJK5wP5LU4=
@ -427,6 +472,11 @@ github.com/lib/pq v1.6.0 h1:I5DPxhYJChW9KYc66se+oKFFQX6VuQrKiprsX6ivRZc=
github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g=
github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
@ -435,8 +485,8 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
@ -457,14 +507,15 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-oci8 v0.0.0-20191108001511-cbd8d5bc1da0/go.mod h1:/M9VLO+lUPmxvoOK2PfWRZ8mTtB4q1Hy9lEGijv9Nr8=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.1 h1:AHx9Ra40wIzl+GelgX2X6AWxmT5tfxhI1PL0523HcSw=
github.com/mattn/go-sqlite3 v1.14.1/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI=
github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
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=
@ -474,6 +525,7 @@ 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/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
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=
@ -481,18 +533,32 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg=
github.com/mitchellh/mapstructure v1.3.2/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/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/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -500,23 +566,35 @@ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw=
github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
@ -526,6 +604,7 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -537,14 +616,19 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+Ci
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw=
github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
@ -553,16 +637,22 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.14.0 h1:RHRyE8UocrbjU+6UvRzwi6HjiDfxrrBU91TtbKzkGp4=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@ -576,7 +666,9 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
github.com/russross/blackfriday/v2 v2.0.1/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/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
@ -586,38 +678,49 @@ github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06B
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
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/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c h1:XLPw6rny9Vrrvrzhw8pNLrC2+x/kH0a/3gOx5xWDa6Y=
github.com/shurcooL/vfsgen v0.0.0-20200627165143-92b8a710ab6c/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU=
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
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=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.3.4 h1:8q6vk3hthlpb2SouZcnBVKboxWQWMDNF38bwholZrJc=
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.4.1 h1:asw9sl74539yqavKaglDM5hFpdJVK0Y5Dr/JOgQ89nQ=
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.0 h1:aq3wCKjTPmzcNWLVGnsFVN4rflK7Uzn10F8/aw8MhdQ=
github.com/spf13/cobra v1.1.0/go.mod h1:yk5b0mALVusDL5fMM6Rd1wgnoO5jUPhwsQ6LQAJTidQ=
github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
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=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
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=
@ -638,10 +741,11 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s=
github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc=
github.com/swaggo/swag v1.6.8 h1:z3ZNcpJs/NLMpZcKqXUsBELmmY2Ocy09JXKx5gu3L4M=
github.com/swaggo/swag v1.6.8/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0=
@ -654,8 +758,10 @@ github.com/ulule/limiter/v3 v3.5.0 h1:QRAebbswjlezHIfiSQgM8+jMxaz/zsrxGRuiUJ43MH
github.com/ulule/limiter/v3 v3.5.0/go.mod h1:TgOUQZKZ2KHjemqrC8UHUbKPqpTmSY43/2wbQ7YN1h8=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@ -667,6 +773,8 @@ github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.0 h1:y3yXRCoDvC2HTtIHvL2cc7Zd+bqA+zqDO6oQzsJO07E=
github.com/valyala/fasttemplate v1.2.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
@ -677,20 +785,29 @@ github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmv
github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -699,7 +816,6 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -712,6 +828,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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=
@ -721,8 +839,8 @@ golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMx
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200801110659-972c09e46d76 h1:U7GPaoQyQmX+CBRWXKrvRzWTbd+slqeSh8uARsIyhAw=
golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
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=
@ -737,8 +855,8 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -758,7 +876,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -772,8 +889,14 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
@ -784,7 +907,12 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201008141435-b3e1573b7520 h1:Bx6FllMpG4NWDOfhMBz1VR2QYNp/SAOHPIAsaVmxfPo=
golang.org/x/sync v0.0.0-20201008141435-b3e1573b7520/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -805,26 +933,35 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6 h1:DvY3Zkh7KabQE/kfzMvYvKirSiguP9Q/veMtkYyf0o8=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211 h1:9UQO31fZ+0aKQOFldThf7BKPMJTiBfWycGh/u3UoO88=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -832,8 +969,10 @@ golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -848,10 +987,10 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628034336-212fb13d595e h1:ZlQjfVdpDxeqxRfmO30CdqWWzTvgRCj0MxaUVfxEG1k=
golang.org/x/tools v0.0.0-20190628034336-212fb13d595e/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@ -860,19 +999,26 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7 h1:EBZoQjiKKPaLbPrbpssUfuHtwM6KV/vb4U85g/cigFY=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef h1:RHORRhs540cYZYrzgU2CPUyykkwZM78hGdzocOo9P8A=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac h1:DugppSxw0LSF8lcjaODPJZoDzq0ElTGskTst3ZaBkHI=
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 h1:ZB1XYzdDo7c/O48jzjMkvIjnC120Z9/CwgDWhePjQdQ=
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
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=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -880,6 +1026,7 @@ google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -894,15 +1041,21 @@ google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
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=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -921,9 +1074,11 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/d4l3k/messagediff.v1 v1.2.1 h1:70AthpjunwzUiarMHyED52mj9UwtAnE89l1Gmrt3EU0=
gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn++04Xniyg44=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
@ -931,6 +1086,8 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkp
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
@ -940,6 +1097,8 @@ gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3M
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -955,16 +1114,21 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a h1:LJwr7TCTghdatWv40WobzlKXc9c4s8oGa7QKJUtHhWA=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.5 h1:nI5egYTGJakVyOryqLs1cQO5dO0ksin5XXs2pspk75k=
honnef.co/go/tools v0.0.1-2020.1.5/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
src.techknowlogick.com/xgo v1.1.1-0.20200811225412-bff6512e7c9c h1:1W7owgaAgZHvJN1RERlBhPOhqm9+Dk1VTqaFKjEjIpQ=
src.techknowlogick.com/xgo v1.1.1-0.20200811225412-bff6512e7c9c/go.mod h1:31CE1YKtDOrKTk9PSnjTpe6YbO6W/0LTYZ1VskL09oU=
src.techknowlogick.com/xormigrate v1.3.0 h1:cCOEk8CjhRqxMtE8X8aV0qd6b2njwU1c3++ZuyaTsA0=

925
magefile.go Normal file
View File

@ -0,0 +1,925 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2020 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 General Public License 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// +build mage
package main
import (
"bufio"
"bytes"
"context"
"crypto/sha256"
"fmt"
"github.com/magefile/mage/mg"
"golang.org/x/sync/errgroup"
"gopkg.in/yaml.v3"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
)
const (
PACKAGE = `code.vikunja.io/api`
DIST = `dist`
)
var (
Goflags = []string{
"-v",
}
Executable = "vikunja"
Ldflags = ""
Tags = ""
VersionNumber = "dev"
Version = "master" // This holds the built version, master by default, when building from a tag or release branch, their name
BinLocation = ""
PkgVersion = "master"
ApiPackages = []string{}
RootPath = ""
GoFiles = []string{}
// Aliases are mage aliases of targets
Aliases = map[string]interface{}{
"build": Build.Build,
"do-the-swag": DoTheSwag,
"check:got-swag": Check.GotSwag,
"release:os-package": Release.OsPackage,
"dev:create-migration": Dev.CreateMigration,
"generate-docs": GenerateDocs,
}
)
func setVersion() {
versionCmd := exec.Command("git", "describe", "--tags", "--always", "--abbrev=10")
version, err := versionCmd.Output()
if err != nil {
fmt.Printf("Error getting version: %s\n", err)
os.Exit(1)
}
VersionNumber = strings.Trim(string(version), "\n")
VersionNumber = strings.Replace(VersionNumber, "-", "+", 1)
VersionNumber = strings.Replace(VersionNumber, "-g", "-", 1)
if os.Getenv("DRONE_TAG") != "" {
Version = os.Getenv("DRONE_TAG")
} else if os.Getenv("DRONE_BRANCH") != "" {
Version = strings.Replace(os.Getenv("DRONE_BRANCH"), "release/v", "", 1)
}
}
func setBinLocation() {
if os.Getenv("DRONE_WORKSPACE") != "" {
BinLocation = DIST + `/binaries/` + Executable + `-` + Version + `-linux-amd64`
} else {
BinLocation = Executable
}
}
func setPkgVersion() {
if Version == "master" {
PkgVersion = VersionNumber
}
}
func setExecutable() {
if runtime.GOOS == "windows" {
Executable += ".exe"
}
}
func setApiPackages() {
cmd := exec.Command("go", "list", "all")
pkgs, err := cmd.Output()
if err != nil {
fmt.Printf("Error getting packages: %s\n", err)
os.Exit(1)
}
for _, p := range strings.Split(string(pkgs), "\n") {
if strings.Contains(p, "code.vikunja.io/api") && !strings.Contains(p, "code.vikunja.io/api/pkg/integrations") {
ApiPackages = append(ApiPackages, p)
}
}
}
func setRootPath() {
pwd, err := os.Getwd()
if err != nil {
fmt.Printf("Error getting pwd: %s\n", err)
os.Exit(1)
}
if err := os.Setenv("VIKUNJA_SERVICE_ROOTPATH", pwd); err != nil {
fmt.Printf("Error setting root path: %s\n", err)
os.Exit(1)
}
RootPath = pwd
}
func setGoFiles() {
// GOFILES := $(shell find . -name "*.go" -type f ! -path "*/bindata.go")
cmd := exec.Command("find", ".", "-name", "*.go", "-type", "f", "!", "-path", "*/bindata.go")
files, err := cmd.Output()
if err != nil {
fmt.Printf("Error getting go files: %s\n", err)
os.Exit(1)
}
for _, f := range strings.Split(string(files), "\n") {
if strings.HasSuffix(f, ".go") {
GoFiles = append(GoFiles, RootPath+strings.TrimLeft(f, "."))
}
}
}
// Some variables can always get initialized, so we do just that.
func init() {
setExecutable()
setRootPath()
}
// Some variables have external dependencies (like git) which may not always be available.
func initVars() {
Tags = os.Getenv("TAGS")
setVersion()
setBinLocation()
setPkgVersion()
setApiPackages()
setGoFiles()
Ldflags = `-X "` + PACKAGE + `/pkg/version.Version=` + VersionNumber + `" -X "main.Tags=` + Tags + `"`
}
func runAndStreamOutput(cmd string, args ...string) {
c := exec.Command(cmd, args...)
c.Env = os.Environ()
c.Dir = RootPath
fmt.Printf("%s\n\n", c.String())
stdout, _ := c.StdoutPipe()
errbuf := bytes.Buffer{}
c.Stderr = &errbuf
c.Start()
reader := bufio.NewReader(stdout)
line, err := reader.ReadString('\n')
for err == nil {
fmt.Print(line)
line, err = reader.ReadString('\n')
}
if err := c.Wait(); err != nil {
fmt.Printf(errbuf.String())
fmt.Printf("Error: %s\n", err)
os.Exit(1)
}
}
// Will check if the tool exists and if not install it from the provided import path
// If any errors occur, it will exit with a status code of 1.
func checkAndInstallGoTool(tool, importPath string) {
if err := exec.Command(tool).Run(); err != nil && strings.Contains(err.Error(), "executable file not found") {
fmt.Printf("%s not installed, installing %s...\n", tool, importPath)
if err := exec.Command("go", "install", Goflags[0], importPath).Run(); err != nil {
fmt.Printf("Error installing %s\n", tool)
os.Exit(1)
}
fmt.Println("Installed.")
}
}
// Calculates a hash of a file
func calculateSha256FileHash(path string) (hash string, err error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return "", err
}
return fmt.Sprintf("%x", h.Sum(nil)), nil
}
// Copy the src file to dst. Any existing file will be overwritten and will not
// copy file attributes.
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, in)
if err != nil {
return err
}
si, err := os.Stat(src)
if err != nil {
return err
}
if err := os.Chmod(dst, si.Mode()); err != nil {
return err
}
return out.Close()
}
// os.Rename has issues with moving files between docker volumes.
// Because of this limitaion, it fails in drone.
// Source: https://gist.github.com/var23rav/23ae5d0d4d830aff886c3c970b8f6c6b
func moveFile(src, dst string) error {
inputFile, err := os.Open(src)
defer inputFile.Close()
if err != nil {
return fmt.Errorf("couldn't open source file: %s", err)
}
outputFile, err := os.Create(dst)
defer outputFile.Close()
if err != nil {
return fmt.Errorf("couldn't open dest file: %s", err)
}
_, err = io.Copy(outputFile, inputFile)
if err != nil {
return fmt.Errorf("writing to output file failed: %s", err)
}
// Make sure to copy copy the permissions of the original file as well
si, err := os.Stat(src)
if err != nil {
return err
}
if err := os.Chmod(dst, si.Mode()); err != nil {
return err
}
// The copy was successful, so now delete the original file
err = os.Remove(src)
if err != nil {
return fmt.Errorf("failed removing original file: %s", err)
}
return nil
}
// Formats the code using go fmt
func Fmt() {
mg.Deps(initVars)
args := append([]string{"-s", "-w"}, GoFiles...)
runAndStreamOutput("gofmt", args...)
}
// Generates the swagger docs from the code annotations
func DoTheSwag() {
mg.Deps(initVars)
checkAndInstallGoTool("swag", "github.com/swaggo/swag/cmd/swag")
runAndStreamOutput("swag", "init", "-g", "./pkg/routes/routes.go", "--parseDependency", "-d", RootPath, "-o", RootPath+"/pkg/swagger")
}
type Test mg.Namespace
// Runs all tests except integration tests
func (Test) Unit() {
mg.Deps(initVars)
// We run everything sequentially and not in parallel to prevent issues with real test databases
args := append([]string{"test", Goflags[0], "-p", "1"}, ApiPackages...)
runAndStreamOutput("go", args...)
}
// Runs the tests and builds the coverage html file from coverage output
func (Test) Coverage() {
mg.Deps(initVars)
mg.Deps(Test.Unit)
runAndStreamOutput("go", "tool", "cover", "-html=cover.out", "-o", "cover.html")
}
// Runs the integration tests
func (Test) Integration() {
mg.Deps(initVars)
// We run everything sequentially and not in parallel to prevent issues with real test databases
runAndStreamOutput("go", "test", Goflags[0], "-p", "1", PACKAGE+"/pkg/integrations")
}
type Check mg.Namespace
// Checks if the swagger docs need to be re-generated from the code annotations
func (Check) GotSwag() {
mg.Deps(initVars)
// The check is pretty cheaply done: We take the hash of the swagger.json file, generate the docs,
// hash the file again and compare the two hashes to see if anything changed. If that's the case,
// regenerating the docs is necessary.
// swag is not capable of just outputting the generated docs to stdout, therefore we need to do it this way.
// Another drawback of this is obviously it will only work once - we're not resetting the newly generated
// docs after the check. This behaviour is good enough for ci though.
oldHash, err := calculateSha256FileHash(RootPath + "/pkg/swagger/swagger.json")
if err != nil {
fmt.Printf("Error getting old hash of the swagger docs: %s", err)
os.Exit(1)
}
DoTheSwag()
newHash, err := calculateSha256FileHash(RootPath + "/pkg/swagger/swagger.json")
if err != nil {
fmt.Printf("Error getting new hash of the swagger docs: %s", err)
os.Exit(1)
}
if oldHash != newHash {
fmt.Println("Swagger docs are not up to date.")
fmt.Println("Please run 'mage do-the-swag' and commit the result.")
os.Exit(1)
}
}
func checkGolangCiLintInstalled() {
mg.Deps(initVars)
if err := exec.Command("golangci-lint").Run(); err != nil && strings.Contains(err.Error(), "executable file not found") {
fmt.Println("Please manually install golangci-lint by running")
fmt.Println("curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.31.0")
os.Exit(1)
}
}
func (Check) Golangci() {
checkGolangCiLintInstalled()
runAndStreamOutput("golangci-lint", "run")
}
func (Check) GolangciFix() {
checkGolangCiLintInstalled()
runAndStreamOutput("golangci-lint", "run", "--fix")
}
// Runs fmt-check, lint, got-swag, misspell-check, ineffasign-check, gocyclo-check, static-check, gosec-check, goconst-check all in parallel
func (Check) All() {
mg.Deps(initVars)
mg.Deps(
Check.Golangci,
Check.GotSwag,
)
}
type Build mg.Namespace
// Cleans all build, executable and bindata files
func (Build) Clean() error {
mg.Deps(initVars)
if err := exec.Command("go", "clean", "./...").Run(); err != nil {
return err
}
if err := os.Remove(Executable); err != nil && !os.IsNotExist(err) {
return err
}
if err := os.RemoveAll(DIST); err != nil && !os.IsNotExist(err) {
return err
}
if err := os.RemoveAll(BinLocation); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}
// Generates static content into the final binary
func (Build) Generate() {
mg.Deps(initVars)
runAndStreamOutput("go", "generate", PACKAGE+"/pkg/static")
}
// Builds a vikunja binary, ready to run
func (Build) Build() {
mg.Deps(initVars)
mg.Deps(Build.Generate)
runAndStreamOutput("go", "build", Goflags[0], "-tags", Tags, "-ldflags", "-s -w "+Ldflags, "-o", Executable)
}
type Release mg.Namespace
// Runs all steps in the right order to create release packages for various platforms
func (Release) Release(ctx context.Context) error {
mg.Deps(initVars)
mg.Deps(Build.Generate, Release.Dirs)
mg.Deps(Release.Windows, Release.Linux, Release.Darwin)
// Run compiling in parallel to speed it up
errs, _ := errgroup.WithContext(ctx)
errs.Go((Release{}).Windows)
errs.Go((Release{}).Linux)
errs.Go((Release{}).Darwin)
if err := errs.Wait(); err != nil {
return err
}
if err := (Release{}).Compress(ctx); err != nil {
return err
}
if err := (Release{}).Copy(); err != nil {
return err
}
if err := (Release{}).Check(); err != nil {
return err
}
if err := (Release{}).OsPackage(); err != nil {
return err
}
if err := (Release{}).Zip(); err != nil {
return err
}
return nil
}
// Creates all directories needed to release vikunja
func (Release) Dirs() error {
for _, d := range []string{"binaries", "release", "zip"} {
if err := os.MkdirAll(RootPath+"/"+DIST+"/"+d, 0755); err != nil {
return err
}
}
return nil
}
func runXgo(targets string) error {
mg.Deps(initVars)
checkAndInstallGoTool("xgo", "src.techknowlogick.com/xgo")
extraLdflags := `-linkmode external -extldflags "-static" `
// See https://github.com/techknowlogick/xgo/issues/79
if strings.HasPrefix(targets, "darwin") {
extraLdflags = ""
}
runAndStreamOutput("xgo",
"-dest", RootPath+"/"+DIST+"/binaries",
"-tags", "netgo "+Tags,
"-ldflags", extraLdflags+Ldflags,
"-targets", targets,
"-out", Executable+"-"+Version,
RootPath)
if os.Getenv("DRONE_WORKSPACE") != "" {
return filepath.Walk("/build/", func(path string, info os.FileInfo, err error) error {
// Skip directories
if info.IsDir() {
return nil
}
return moveFile(path, RootPath+"/"+DIST+"/binaries/"+info.Name())
})
}
return nil
}
// Builds binaries for windows
func (Release) Windows() error {
return runXgo("windows/*")
}
// Builds binaries for linux
func (Release) Linux() error {
return runXgo("linux/*")
}
// Builds binaries for darwin
func (Release) Darwin() error {
return runXgo("darwin/*")
}
// Compresses the built binaries in dist/binaries/ to reduce their filesize
func (Release) Compress(ctx context.Context) error {
// $(foreach file,$(filter-out $(wildcard $(wildcard $(DIST)/binaries/$(EXECUTABLE)-*mips*)),$(wildcard $(DIST)/binaries/$(EXECUTABLE)-*)), upx -9 $(file);)
errs, _ := errgroup.WithContext(ctx)
filepath.Walk(RootPath+"/"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error {
// Only executable files
if !strings.Contains(info.Name(), Executable) {
return nil
}
// No mips or s390x for you today
if strings.Contains(info.Name(), "mips") || strings.Contains(info.Name(), "s390x") {
return nil
}
// Runs compressing in parallel since upx is single-threaded
errs.Go(func() error {
runAndStreamOutput("chmod", "+x", path) // Make sure all binaries are executable. Sometimes the CI does weired things and they're not.
runAndStreamOutput("upx", "-9", path)
return nil
})
return nil
})
return errs.Wait()
}
// Copies all built binaries to dist/release/ in preparation for creating the os packages
func (Release) Copy() error {
return filepath.Walk(RootPath+"/"+DIST+"/binaries/", func(path string, info os.FileInfo, err error) error {
// Only executable files
if !strings.Contains(info.Name(), Executable) {
return nil
}
return copyFile(path, RootPath+"/"+DIST+"/release/"+info.Name())
})
}
// Creates sha256 checksum files for each binary in dist/release/
func (Release) Check() error {
p := RootPath + "/" + DIST + "/release/"
return filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
f, err := os.Create(p + info.Name() + ".sha256")
if err != nil {
return err
}
hash, err := calculateSha256FileHash(path)
if err != nil {
return err
}
_, err = f.WriteString(hash + " " + info.Name())
if err != nil {
return err
}
return f.Close()
})
}
// Creates a folder for each
func (Release) OsPackage() error {
p := RootPath + "/" + DIST + "/release/"
// We first put all files in a map to then iterate over it since the walk function would otherwise also iterate
// over the newly created files, creating some kind of endless loop.
bins := make(map[string]os.FileInfo)
if err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
if strings.Contains(info.Name(), ".sha256") || info.IsDir() {
return nil
}
bins[path] = info
return nil
}); err != nil {
return err
}
for path, info := range bins {
folder := p + info.Name() + "-full/"
if err := os.Mkdir(folder, 0755); err != nil {
return err
}
if err := moveFile(p+info.Name()+".sha256", folder+info.Name()+".sha256"); err != nil {
return err
}
if err := moveFile(path, folder+info.Name()); err != nil {
return err
}
if err := copyFile(RootPath+"/config.yml.sample", folder+"config.yml.sample"); err != nil {
return err
}
if err := copyFile(RootPath+"/LICENSE", folder+"LICENSE"); err != nil {
return err
}
}
return nil
}
// Creates a zip file from all os-package folders in dist/release
func (Release) Zip() error {
p := RootPath + "/" + DIST + "/release/"
if err := filepath.Walk(p, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() || info.Name() == "release" {
return nil
}
fmt.Printf("Zipping %s...\n", info.Name())
c := exec.Command("zip", "-r", RootPath+"/"+DIST+"/zip/"+info.Name(), ".", "-i", "*")
c.Dir = path
out, err := c.Output()
fmt.Print(string(out))
return err
}); err != nil {
return err
}
return nil
}
// Creates a debian repo structure
func (Release) Reprepro() {
mg.Deps(setVersion, setBinLocation)
runAndStreamOutput("reprepro_expect", "debian", "includedeb", "strech", RootPath+"/"+DIST+"/os-packages/"+Executable+"_"+strings.ReplaceAll(VersionNumber, "v0", "0")+"_amd64.deb")
}
// Creates deb, rpm and apk packages
func (Release) Packages() error {
mg.Deps(initVars)
var err error
binpath := "nfpm"
err = exec.Command(binpath).Run()
if err != nil && strings.Contains(err.Error(), "executable file not found") {
binpath = "/nfpm"
err = exec.Command(binpath).Run()
}
if err != nil && strings.Contains(err.Error(), "executable file not found") {
fmt.Println("Please manually install nfpm by running")
fmt.Println("curl -sfL https://install.goreleaser.com/github.com/goreleaser/nfpm.sh | sh -s -- -b $(go env GOPATH)/bin")
os.Exit(1)
}
// Because nfpm does not support templating, we replace the values in the config file and restore it after running
nfpmConfigPath := RootPath + "/nfpm.yaml"
nfpmconfig, err := ioutil.ReadFile(nfpmConfigPath)
if err != nil {
return err
}
fixedConfig := strings.ReplaceAll(string(nfpmconfig), "<version>", VersionNumber)
fixedConfig = strings.ReplaceAll(fixedConfig, "<binlocation>", BinLocation)
if err := ioutil.WriteFile(nfpmConfigPath, []byte(fixedConfig), 0); err != nil {
return err
}
releasePath := RootPath + "/" + DIST + "/os-packages/"
if err := os.MkdirAll(releasePath, 0755); err != nil {
return err
}
runAndStreamOutput(binpath, "pkg", "--packager", "deb", "--target", releasePath)
runAndStreamOutput(binpath, "pkg", "--packager", "rpm", "--target", releasePath)
runAndStreamOutput(binpath, "pkg", "--packager", "apk", "--target", releasePath)
return ioutil.WriteFile(nfpmConfigPath, nfpmconfig, 0)
}
type Dev mg.Namespace
// Creates a new bare db migration skeleton in pkg/migration with the current date
func (Dev) CreateMigration() error {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter the name of the struct: ")
str, _ := reader.ReadString('\n')
str = strings.Trim(str, "\n")
date := time.Now().Format("20060102150405")
migration := `// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2020 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 General Public License 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type ` + str + date + ` struct {
}
func (` + str + date + `) TableName() string {
return "` + str + `"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "` + date + `",
Description: "",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(` + str + date + `{})
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}
`
f, err := os.Create(RootPath + "/pkg/migration/" + date + ".go")
defer f.Close()
if err != nil {
return err
}
_, err = f.WriteString(migration)
return err
}
type configOption struct {
key string
description string
defaultValue string
children []*configOption
}
func parseYamlConfigNode(node *yaml.Node) (config *configOption) {
config = &configOption{
key: node.Value,
description: strings.ReplaceAll(node.HeadComment, "# ", ""),
}
valMap := make(map[string]*configOption)
var lastOption *configOption
for i, n2 := range node.Content {
coo := &configOption{
key: n2.Value,
description: strings.ReplaceAll(n2.HeadComment, "# ", ""),
}
// If there's a key in valMap for the current key we should use that to append etc
// Else we just create a new configobject
co, exists := valMap[n2.Value]
if exists {
co.description = coo.description
} else {
valMap[n2.Value] = coo
config.children = append(config.children, coo)
}
// fmt.Println(i, coo.key, coo.description, n2.Value)
if i%2 == 0 {
lastOption = coo
continue
} else {
lastOption.defaultValue = n2.Value
}
if i-1 >= 0 && i-1 <= len(node.Content) && node.Content[i-1].Value != "" {
coo.defaultValue = n2.Value
coo.key = node.Content[i-1].Value
}
if len(n2.Content) > 0 {
for _, n := range n2.Content {
coo.children = append(coo.children, parseYamlConfigNode(n))
}
}
}
return config
}
func printConfig(config []*configOption, level int) (rendered string) {
// Keep track of what we already printed to prevent printing things twice
printed := make(map[string]bool)
for _, option := range config {
if option.key != "" {
// Filter out all config objects where the default value == key
// Yaml is weired: It gives you a slice with an entry each for the key and their value.
if printed[option.key] {
continue
}
if level == 0 {
rendered += "---\n\n"
}
rendered += "#"
for i := 0; i <= level; i++ {
rendered += "#"
}
rendered += " " + option.key + "\n\n"
if option.description != "" {
rendered += option.description + "\n\n"
}
// Top level config values never have a default value
if level > 0 {
rendered += "Default: `" + option.defaultValue
if option.defaultValue == "" {
rendered += "<empty>"
}
rendered += "`\n"
}
}
printed[option.key] = true
rendered += "\n" + printConfig(option.children, level+1)
}
return
}
const (
configDocPath = `docs/content/doc/setup/config.md`
configInjectComment = `<!-- Generated config will be injected here -->`
)
// Generates the error docs from a commented config.yml.sample file in the repo root.
func GenerateDocs() error {
config, err := ioutil.ReadFile("config.yml.sample")
if err != nil {
return err
}
var d yaml.Node
err = yaml.Unmarshal(config, &d)
if err != nil {
return err
}
conf := []*configOption{}
for _, node := range d.Content {
for _, n := range node.Content {
co := parseYamlConfigNode(n)
conf = append(conf, co)
}
}
renderedConfig := printConfig(conf, 0)
// Rebuild the config
file, err := os.OpenFile(configDocPath, os.O_RDWR, 0)
if err != nil {
return err
}
defer file.Close()
// We read the config doc up until the marker, then stop and append our generated config
fullConfig := ""
scanner := bufio.NewScanner(file)
for scanner.Scan() {
t := scanner.Text()
fullConfig += t + "\n"
if t == configInjectComment {
break
}
}
if err := scanner.Err(); err != nil {
return err
}
fullConfig += "\n" + renderedConfig
// We write the full file to prevent old content leftovers at the end
// I know, there are probably better ways to do this.
if err := ioutil.WriteFile(configDocPath, []byte(fullConfig), 0); err != nil {
return err
}
return nil
}

18
nfpm.yaml Normal file
View File

@ -0,0 +1,18 @@
name: "vikunja"
arch: "amd64"
platform: "linux"
version: "<version>"
description: "Vikunja is an open-source todo application, written in Go. It lets you create lists,tasks and share them via teams or directly between users."
maintainer: "Vikunja Maintainers <maintainers@vikunja.io>"
homepage: "https://vikunja.io"
section: "default"
priority: "extra"
license: "GPLv3"
files:
<binlocation>: /opt/vikunja/vikunja
config_files:
./config.yml.sample: /etc/vikunja/config.yml
symlinks:
/opt/vikunja/vikunja: /usr/local/bin/vikunja
scripts:
postinstall: ./build/after-install.sh

View File

@ -17,16 +17,17 @@
package caldav
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"fmt"
"strconv"
"strings"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
)
// DateFormat ist the caldav date format
// DateFormat is the caldav date format
const DateFormat = `20060102T150405`
// Event holds a single caldav event

View File

@ -17,10 +17,11 @@
package caldav
import (
"code.vikunja.io/api/pkg/config"
"github.com/stretchr/testify/assert"
"testing"
"time"
"code.vikunja.io/api/pkg/config"
"github.com/stretchr/testify/assert"
)
func TestParseEvents(t *testing.T) {

View File

@ -18,8 +18,9 @@ package cmd
import (
"fmt"
"github.com/spf13/cobra"
"os"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{

View File

@ -17,11 +17,12 @@
package cmd
import (
"time"
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/modules/dump"
"github.com/spf13/cobra"
"time"
)
func init() {

View File

@ -18,17 +18,18 @@
package cmd
import (
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
"fmt"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
"os"
"strconv"
"strings"
"time"
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)
var (

View File

@ -17,10 +17,11 @@
package cmd
import (
"code.vikunja.io/api/pkg/version"
"fmt"
"github.com/spf13/cobra"
"runtime"
"code.vikunja.io/api/pkg/version"
"github.com/spf13/cobra"
)
func init() {

View File

@ -17,17 +17,18 @@
package cmd
import (
"context"
"os"
"os/signal"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/initialize"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/routes"
"code.vikunja.io/api/pkg/swagger"
"code.vikunja.io/api/pkg/version"
"context"
"github.com/spf13/cobra"
"os"
"os/signal"
"time"
)
func init() {

View File

@ -124,6 +124,8 @@ const (
BackgroundsUnsplashEnabled Key = `backgrounds.providers.unsplash.enabled`
BackgroundsUnsplashAccessToken Key = `backgrounds.providers.unsplash.accesstoken`
BackgroundsUnsplashApplicationID Key = `backgrounds.providers.unsplash.applicationid`
KeyvalueType Key = `keyvalue.type`
)
// GetString returns a string config value
@ -277,6 +279,8 @@ func InitDefaultConfig() {
BackgroundsEnabled.setDefault(true)
BackgroundsUploadEnabled.setDefault(true)
BackgroundsUnsplashEnabled.setDefault(false)
// Key Value
KeyvalueType.setDefault("memory")
}
// InitConfig initializes the config, sets defaults etc.
@ -310,6 +314,14 @@ func InitConfig() {
return
}
if CacheType.GetString() == "keyvalue" {
CacheType.Set(KeyvalueType.GetString())
}
if RateLimitStore.GetString() == "keyvalue" {
RateLimitStore.Set(KeyvalueType.GetString())
}
log.Printf("Using config file: %s", viper.ConfigFileUsed())
}

View File

@ -17,16 +17,17 @@
package db
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"encoding/gob"
"fmt"
xrc "gitea.com/xorm/xorm-redis-cache"
"net/url"
"os"
"strconv"
"strings"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
xrc "gitea.com/xorm/xorm-redis-cache"
"xorm.io/core"
"xorm.io/xorm"
"xorm.io/xorm/caches"
@ -52,23 +53,24 @@ func CreateDBEngine() (engine *xorm.Engine, err error) {
}
// Use Mysql if set
if config.DatabaseType.GetString() == "mysql" {
switch config.DatabaseType.GetString() {
case "mysql":
engine, err = initMysqlEngine()
if err != nil {
return
}
} else if config.DatabaseType.GetString() == "postgres" {
case "postgres":
engine, err = initPostgresEngine()
if err != nil {
return
}
} else if config.DatabaseType.GetString() == "sqlite" {
case "sqlite":
// Otherwise use sqlite
engine, err = initSqliteEngine()
if err != nil {
return
}
} else {
default:
log.Fatalf("Unknown database type %s", config.DatabaseType.GetString())
}
@ -90,7 +92,7 @@ func CreateDBEngine() (engine *xorm.Engine, err error) {
cacher := caches.NewLRUCacher(caches.NewMemoryStore(), config.CacheMaxElementSize.GetInt())
engine.SetDefaultCacher(cacher)
case "redis":
cacher := xrc.NewRedisCacher(config.RedisEnabled.GetString(), config.RedisPassword.GetString(), xrc.DEFAULT_EXPIRATION, engine.Logger())
cacher := xrc.NewRedisCacher(config.RedisHost.GetString(), config.RedisPassword.GetString(), xrc.DEFAULT_EXPIRATION, engine.Logger())
engine.SetDefaultCacher(cacher)
default:
log.Info("Did not find a valid cache type. Caching disabled. Please refer to the docs for poosible cache types.")

View File

@ -2,12 +2,14 @@
title: testbucket1
list_id: 1
created_by_id: 1
limit: 9999999 # This bucket has a limit we will never exceed in the tests to make sure the logic allows for buckets with limits
created: 2020-04-18 21:13:52
updated: 2020-04-18 21:13:52
- id: 2
title: testbucket2
list_id: 1
created_by_id: 1
limit: 3
created: 2020-04-18 21:13:52
updated: 2020-04-18 21:13:52
- id: 3

View File

@ -199,3 +199,13 @@
is_archived: 1
updated: 2018-12-02 15:13:12
created: 2018-12-01 15:13:12
-
id: 23
title: Test23
description: Lorem Ipsum
identifier: test23
owner_id: 12
namespace_id: 17
is_favorite: true
updated: 2018-12-02 15:13:12
created: 2018-12-01 15:13:12

View File

@ -82,3 +82,9 @@
is_archived: 1
updated: 2018-12-02 15:13:12
created: 2018-12-01 15:13:12
- id: 17
title: testnamespace17
description: Lorem Ipsum
owner_id: 12
updated: 2018-12-02 15:13:12
created: 2018-12-01 15:13:12

View File

@ -0,0 +1,6 @@
- id: 1
filters: '{"sort_by":null,"order_by":null,"filter_by":["start_date","end_date","due_date"],"filter_value":["2018-12-11T03:46:40+00:00","2018-12-13T11:20:01+00:00","2018-11-29T14:00:00+00:00"],"filter_comparator":["greater","less","greater"],"filter_concat":"","filter_include_nulls":false}'
title: testfilter1
owner_id: 1
updated: 2020-09-08 15:13:12
created: 2020-09-08 14:13:12

View File

@ -8,6 +8,7 @@
created: 2018-12-01 01:12:04
updated: 2018-12-01 01:12:04
bucket_id: 1
is_favorite: true
- id: 2
title: 'task #2 done'
done: true
@ -140,6 +141,7 @@
list_id: 6
index: 1
bucket_id: 6
is_favorite: true
created: 2018-12-01 01:12:04
updated: 2018-12-01 01:12:04
- id: 16
@ -315,6 +317,7 @@
list_id: 20
index: 20
bucket_id: 5
is_favorite: true
created: 2018-12-01 01:12:04
updated: 2018-12-01 01:12:04
- id: 35

View File

@ -18,9 +18,13 @@
package db
import (
"fmt"
"os"
"testing"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"os"
"github.com/stretchr/testify/assert"
"xorm.io/core"
"xorm.io/xorm"
)
@ -69,3 +73,32 @@ func InitTestFixtures(tablenames ...string) (err error) {
return nil
}
// AssertExists checks and asserts the existence of certain entries in the db
func AssertExists(t *testing.T, table string, values map[string]interface{}, custom bool) {
var exists bool
var err error
v := make(map[string]interface{})
// Postgres sometimes needs to build raw sql. Because it won't always need to do this and this isn't fun, it's a flag.
if custom {
//#nosec
sql := "SELECT * FROM " + table + " WHERE "
for col, val := range values {
sql += col + "=" + fmt.Sprintf("%v", val) + " AND "
}
sql = sql[:len(sql)-5]
exists, err = x.SQL(sql).Get(&v)
} else {
exists, err = x.Table(table).Where(values).Get(&v)
}
assert.NoError(t, err, fmt.Sprintf("Failed to assert entries exist in db, error was: %s", err))
assert.True(t, exists, fmt.Sprintf("Entries %v do not exist in table %s", values, table))
}
// AssertMissing checks and asserts the nonexiste nce of certain entries in the db
func AssertMissing(t *testing.T, table string, values map[string]interface{}) {
v := make(map[string]interface{})
exists, err := x.Table(table).Where(values).Exist(&v)
assert.NoError(t, err, fmt.Sprintf("Failed to assert entries don't exist in db, error was: %s", err))
assert.False(t, exists, fmt.Sprintf("Entries %v exist in table %s", values, table))
}

View File

@ -18,12 +18,13 @@
package db
import (
"code.vikunja.io/api/pkg/config"
"fmt"
"github.com/go-testfixtures/testfixtures/v3"
"github.com/stretchr/testify/assert"
"path/filepath"
"testing"
"code.vikunja.io/api/pkg/config"
"github.com/go-testfixtures/testfixtures/v3"
"github.com/stretchr/testify/assert"
"xorm.io/xorm/schemas"
)

View File

@ -29,7 +29,7 @@ func (err ErrFileDoesNotExist) Error() string {
return fmt.Sprintf("file %d does not exist", err.FileID)
}
//IsErrFileDoesNotExist checks if an error is ErrFileDoesNotExist
// IsErrFileDoesNotExist checks if an error is ErrFileDoesNotExist
func IsErrFileDoesNotExist(err error) bool {
_, ok := err.(ErrFileDoesNotExist)
return ok
@ -45,7 +45,7 @@ func (err ErrFileIsTooLarge) Error() string {
return fmt.Sprintf("file is too large [Size: %d]", err.Size)
}
//IsErrFileIsTooLarge checks if an error is ErrFileIsTooLarge
// IsErrFileIsTooLarge checks if an error is ErrFileIsTooLarge
func IsErrFileIsTooLarge(err error) bool {
_, ok := err.(ErrFileIsTooLarge)
return ok
@ -62,7 +62,7 @@ func (err ErrFileIsNotUnsplashFile) Error() string {
return fmt.Sprintf("file was not downloaded from unsplash [FileID: %d]", err.FileID)
}
//IsErrFileIsNotUnsplashFile checks if an error is ErrFileIsNotUnsplashFile
// IsErrFileIsNotUnsplashFile checks if an error is ErrFileIsNotUnsplashFile
func IsErrFileIsNotUnsplashFile(err error) bool {
_, ok := err.(ErrFileIsNotUnsplashFile)
return ok

View File

@ -17,13 +17,14 @@
package files
import (
"os"
"testing"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/log"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"os"
"testing"
)
// This file handles storing and retrieving a file for different backends
@ -49,7 +50,7 @@ func initFixtures(t *testing.T) {
InitTestFileFixtures(t)
}
//InitTestFileFixtures initializes file fixtures
// InitTestFileFixtures initializes file fixtures
func InitTestFileFixtures(t *testing.T) {
// Init fixture files
filename := config.FilesBasePath.GetString() + "/1"

View File

@ -17,13 +17,14 @@
package files
import (
"io"
"strconv"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/web"
"github.com/c2h5oh/datasize"
"github.com/spf13/afero"
"io"
"strconv"
"time"
)
// File holds all information about a file

View File

@ -18,10 +18,11 @@
package files
import (
"github.com/stretchr/testify/assert"
"io"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
type testfile struct {

View File

@ -23,6 +23,7 @@ import (
"code.vikunja.io/api/pkg/mail"
"code.vikunja.io/api/pkg/migration"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/modules/keyvalue"
migrator "code.vikunja.io/api/pkg/modules/migration"
"code.vikunja.io/api/pkg/red"
"code.vikunja.io/api/pkg/user"
@ -36,6 +37,9 @@ func LightInit() {
// Init redis
red.InitRedis()
// Init keyvalue store
keyvalue.InitStorage()
// Set logger
log.InitLogger()
}

View File

@ -18,11 +18,12 @@
package integrations
import (
"net/url"
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/stretchr/testify/assert"
"net/url"
"testing"
)
// This tests the following behaviour:

View File

@ -17,6 +17,13 @@
package integrations
import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/files"
@ -29,12 +36,6 @@ import (
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"net/url"
"os"
"strings"
"testing"
)
// These are the test users, the same way they are in the test database

View File

@ -17,11 +17,12 @@
package integrations
import (
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"testing"
)
func TestBucket(t *testing.T) {

View File

@ -17,12 +17,13 @@
package integrations
import (
"net/url"
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"net/url"
"testing"
)
func TestLinkSharing(t *testing.T) {

View File

@ -17,12 +17,13 @@
package integrations
import (
"net/url"
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"net/url"
"testing"
)
func TestList(t *testing.T) {

View File

@ -17,11 +17,12 @@
package integrations
import (
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestLogin(t *testing.T) {

View File

@ -17,11 +17,12 @@
package integrations
import (
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestRegister(t *testing.T) {

View File

@ -18,11 +18,12 @@
package integrations
import (
"net/url"
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/stretchr/testify/assert"
"net/url"
"testing"
)
func TestTaskCollection(t *testing.T) {
@ -113,49 +114,49 @@ func TestTaskCollection(t *testing.T) {
t.Run("by priority", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("by priority desc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1`)
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1`)
})
t.Run("by priority asc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
// should equal duedate asc
t.Run("by due_date", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("by duedate desc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
})
// Due date without unix suffix
t.Run("by duedate asc without suffix", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("by due_date without suffix", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("by duedate desc without suffix", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
})
t.Run("by duedate asc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, urlParams)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("invalid sort parameter", func(t *testing.T) {
_, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"loremipsum"}}, urlParams)
@ -258,6 +259,29 @@ func TestTaskCollection(t *testing.T) {
assertHandlerErrorCode(t, err, models.ErrCodeInvalidTaskFilterValue)
})
})
t.Run("saved filter", func(t *testing.T) {
t.Run("date range", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(
nil,
map[string]string{"list": "-2"}, // Actually a saved filter - contains the same filter arguments as the start and end date filter from above
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.Contains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
assert.NotContains(t, rec.Body.String(), `task #13`)
assert.NotContains(t, rec.Body.String(), `task #14`)
})
})
})
t.Run("ReadAll for all tasks", func(t *testing.T) {
@ -318,33 +342,33 @@ func TestTaskCollection(t *testing.T) {
t.Run("by priority", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, nil)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("by priority desc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, nil)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1`)
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1`)
})
t.Run("by priority asc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, nil)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
// should equal duedate asc
t.Run("by due_date", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, nil)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("by duedate desc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, nil)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
})
t.Run("by duedate asc", func(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, nil)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_from_current_date":false,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
})
t.Run("invalid parameter", func(t *testing.T) {
// Invalid parameter should not sort at all

View File

@ -17,11 +17,12 @@
package integrations
import (
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"testing"
)
func TestTaskComments(t *testing.T) {

View File

@ -17,11 +17,12 @@
package integrations
import (
"testing"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"testing"
)
func TestTask(t *testing.T) {
@ -289,9 +290,9 @@ func TestTask(t *testing.T) {
})
t.Run("Bucket", func(t *testing.T) {
t.Run("Normal", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "1"}, `{"bucket_id":2}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "1"}, `{"bucket_id":3}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"bucket_id":2`)
assert.Contains(t, rec.Body.String(), `"bucket_id":3`)
assert.NotContains(t, rec.Body.String(), `"bucket_id":1`)
})
t.Run("Different List", func(t *testing.T) {
@ -472,9 +473,9 @@ func TestTask(t *testing.T) {
})
t.Run("Bucket", func(t *testing.T) {
t.Run("Normal", func(t *testing.T) {
rec, err := testHandler.testCreateWithUser(nil, map[string]string{"list": "1"}, `{"title":"Lorem Ipsum","bucket_id":2}`)
rec, err := testHandler.testCreateWithUser(nil, map[string]string{"list": "1"}, `{"title":"Lorem Ipsum","bucket_id":3}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"bucket_id":2`)
assert.Contains(t, rec.Body.String(), `"bucket_id":3`)
assert.NotContains(t, rec.Body.String(), `"bucket_id":1`)
})
t.Run("Different List", func(t *testing.T) {

View File

@ -17,10 +17,11 @@
package integrations
import (
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"github.com/stretchr/testify/assert"
)
func TestCheckToken(t *testing.T) {

View File

@ -17,11 +17,12 @@
package integrations
import (
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestUserChangePassword(t *testing.T) {

View File

@ -17,12 +17,13 @@
package integrations
import (
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestUserConfirmEmail(t *testing.T) {

View File

@ -17,10 +17,11 @@
package integrations
import (
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"github.com/stretchr/testify/assert"
)
func TestUserList(t *testing.T) {

View File

@ -17,12 +17,13 @@
package integrations
import (
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestUserRequestResetPasswordToken(t *testing.T) {

View File

@ -17,12 +17,13 @@
package integrations
import (
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestUserPasswordReset(t *testing.T) {

View File

@ -17,10 +17,11 @@
package integrations
import (
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"github.com/stretchr/testify/assert"
)
func TestUserShow(t *testing.T) {

View File

@ -17,13 +17,14 @@
package log
import (
"code.vikunja.io/api/pkg/config"
"github.com/op/go-logging"
"github.com/spf13/viper"
"io"
"os"
"strings"
"time"
"code.vikunja.io/api/pkg/config"
"github.com/op/go-logging"
"github.com/spf13/viper"
)
// ErrFmt holds the format for all the console logging
@ -105,7 +106,6 @@ func GetLogger() *logging.Logger {
return logInstance
}
/////
// The following functions are to be used as an "eye-candy", so one can just write log.Error() instead of log.Log.Error()
// Debug is for debug messages

View File

@ -17,10 +17,11 @@
package log
import (
"code.vikunja.io/api/pkg/config"
"github.com/op/go-logging"
"strings"
"time"
"code.vikunja.io/api/pkg/config"
"github.com/op/go-logging"
"xorm.io/xorm/log"
)

View File

@ -17,11 +17,12 @@
package mail
import (
"crypto/tls"
"time"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"crypto/tls"
"gopkg.in/gomail.v2"
"time"
)
// Queue is the mail queue

View File

@ -18,13 +18,14 @@ package mail
import (
"bytes"
"html/template"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/static"
"code.vikunja.io/api/pkg/utils"
"github.com/shurcooL/httpfs/html/vfstemplate"
"gopkg.in/gomail.v2"
"html/template"
)
// Opts holds infos for a mail

View File

@ -17,14 +17,14 @@
package metrics
import (
"bytes"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/web"
"encoding/gob"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"sync"
"time"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/modules/keyvalue"
"code.vikunja.io/web"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
// SecondsUntilInactive defines the seconds until a user is considered inactive
@ -91,36 +91,19 @@ func SetUserActive(a web.Auth) (err error) {
// getActiveUsers returns the active users from redis
func getActiveUsers() (users activeUsersMap, err error) {
activeUsersR, err := r.Get(ActiveUsersKey).Bytes()
if err != nil {
if err.Error() == "redis: nil" {
return users, nil
}
return
}
var b bytes.Buffer
_, err = b.Write(activeUsersR)
u, err := keyvalue.Get(ActiveUsersKey)
if err != nil {
return nil, err
}
d := gob.NewDecoder(&b)
if err := d.Decode(&users); err != nil {
return nil, err
}
users = u.(activeUsersMap)
return
}
// PushActiveUsers pushed the content of the activeUsers map to redis
func PushActiveUsers() (err error) {
var b bytes.Buffer
e := gob.NewEncoder(&b)
activeUsers.mutex.Lock()
defer activeUsers.mutex.Unlock()
if err := e.Encode(activeUsers.users); err != nil {
return err
}
return r.Set(ActiveUsersKey, b.Bytes(), 0).Err()
return keyvalue.Put(ActiveUsersKey, activeUsers.users)
}

View File

@ -19,14 +19,12 @@ package metrics
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/red"
"github.com/go-redis/redis/v7"
"code.vikunja.io/api/pkg/modules/keyvalue"
e "code.vikunja.io/api/pkg/modules/keyvalue/error"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
)
var r *redis.Client
const (
// ListCountKey is the name of the key in which we save the list count
ListCountKey = `listcount`
@ -46,8 +44,6 @@ const (
// InitMetrics Initializes the metrics
func InitMetrics() {
r = red.GetRedis()
// init active users, sometimes we'll have garbage from previous runs in redis instead
if err := PushActiveUsers(); err != nil {
log.Fatalf("Could not set initial count for active users, error was %s", err)
@ -101,18 +97,21 @@ func InitMetrics() {
// GetCount returns the current count from redis
func GetCount(key string) (count int64, err error) {
count, err = r.Get(key).Int64()
if err != nil && err.Error() != "redis: nil" {
return
cnt, err := keyvalue.Get(key)
if err != nil {
if e.IsErrValueNotFoundForKey(err) {
return 0, nil
}
return 0, err
}
err = nil
count = cnt.(int64)
return
}
// SetCount sets the list count to a given value
func SetCount(count int64, key string) error {
return r.Set(key, count, 0).Err()
return keyvalue.Put(key, count)
}
// UpdateCount updates a count with a given amount
@ -121,13 +120,13 @@ func UpdateCount(update int64, key string) {
return
}
if update > 0 {
err := r.IncrBy(key, update).Err()
err := keyvalue.IncrBy(key, update)
if err != nil {
log.Error(err.Error())
}
}
if update < 0 {
err := r.DecrBy(key, update).Err()
err := keyvalue.DecrBy(key, update)
if err != nil {
log.Error(err.Error())
}

View File

@ -18,6 +18,7 @@ package migration
import (
"math"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)

View File

@ -17,8 +17,9 @@
package migration
import (
"src.techknowlogick.com/xormigrate"
"strings"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
@ -55,7 +56,7 @@ func init() {
// The general idea here is to take the title and slice it into pieces, until we found a unique piece.
var exists = true
titleSlug := []rune(strings.Replace(strings.ToUpper(l.Title), " ", "", -1))
titleSlug := []rune(strings.ReplaceAll(strings.ToUpper(l.Title), " ", ""))
// We can save at most 10 characters in the db, so we need to ensure it has at most 10 characters
if len(titleSlug) > 10 {

View File

@ -18,8 +18,9 @@ package migration
import (
"fmt"
"src.techknowlogick.com/xormigrate"
"strings"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
@ -654,7 +655,7 @@ create unique index UQE_users_namespace_id
// The statement is probably useless anyway since its only purpose is to clean up old tables
// which may be leftovers from a previously failed migration. However, since the whole thing
// is wrapped in sessions, this is extremely unlikely to happen anyway.
//"ALTER TABLE " + table + " DROP COLUMN IF EXISTS " + colTmp + ";",
// "ALTER TABLE " + table + " DROP COLUMN IF EXISTS " + colTmp + ";",
"ALTER TABLE " + table + " ADD COLUMN " + colTmp + " DATETIME NULL;",
// #nosec
"UPDATE " + table + " SET " + colTmp + " = IF(" + colOld + " = 0, NULL, FROM_UNIXTIME(" + colOld + "));",

View File

@ -0,0 +1,43 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2020 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 General Public License 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type buckets20200904101559 struct {
Limit int64 `xorm:"default 0" json:"limit"`
}
func (buckets20200904101559) TableName() string {
return "buckets"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20200904101559",
Description: "Add limit field to kanban",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(buckets20200904101559{})
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -0,0 +1,43 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2020 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 General Public License 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type tasks20200905151040 struct {
IsFavorite bool `xorm:"default false" json:"is_favorite"`
}
func (tasks20200905151040) TableName() string {
return "tasks"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20200905151040",
Description: "Add favorite field to tasks",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(tasks20200905151040{})
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -0,0 +1,43 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2020 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 General Public License 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type list20200905232458 struct {
IsFavorite bool `xorm:"default false" json:"is_favorite"`
}
func (list20200905232458) TableName() string {
return "list"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20200905232458",
Description: "Add is_favorite field to lists",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(list20200905232458{})
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -0,0 +1,52 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2020 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 General Public License 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"time"
"code.vikunja.io/api/pkg/models"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type savedFilters20200906184746 struct {
ID int64 `xorm:"autoincr not null unique pk" json:"id"`
Filters *models.TaskCollection `xorm:"JSON not null" json:"filters"`
Title string `xorm:"varchar(250) not null" json:"title" valid:"required,runelength(1|250)" minLength:"1" maxLength:"250"`
Description string `xorm:"longtext null" json:"description"`
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
Created time.Time `xorm:"created not null" json:"created"`
Updated time.Time `xorm:"updated not null" json:"updated"`
}
func (savedFilters20200906184746) TableName() string {
return "saved_filters"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20200906184746",
Description: "Add the saved filters column",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(savedFilters20200906184746{})
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -17,6 +17,9 @@
package migration
import (
"os"
"sort"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/files"
@ -25,8 +28,6 @@ import (
"code.vikunja.io/api/pkg/modules/migration"
"code.vikunja.io/api/pkg/user"
"github.com/olekukonko/tablewriter"
"os"
"sort"
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)

View File

@ -1,9 +1,10 @@
package models
import (
"testing"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"testing"
)
func TestBulkTask_Update(t *testing.T) {

View File

@ -17,10 +17,11 @@
package models
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/web"
"fmt"
"net/http"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/web"
)
// Generic
@ -1334,3 +1335,91 @@ func (err ErrCannotRemoveLastBucket) HTTPError() web.HTTPError {
Message: "You cannot remove the last bucket on this list.",
}
}
// ErrBucketLimitExceeded represents an error where a task is being created or moved to a bucket which has its limit already exceeded.
type ErrBucketLimitExceeded struct {
BucketID int64
Limit int64
TaskID int64 // may be 0
}
// IsErrBucketLimitExceeded checks if an error is ErrBucketLimitExceeded.
func IsErrBucketLimitExceeded(err error) bool {
_, ok := err.(ErrBucketLimitExceeded)
return ok
}
func (err ErrBucketLimitExceeded) Error() string {
return fmt.Sprintf("Cannot add a task to this bucket because it would exceed the limit [BucketID: %d, Limit: %d, TaskID: %d]", err.BucketID, err.Limit, err.TaskID)
}
// ErrCodeBucketLimitExceeded holds the unique world-error code of this error
const ErrCodeBucketLimitExceeded = 10004
// HTTPError holds the http error description
func (err ErrBucketLimitExceeded) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeBucketLimitExceeded,
Message: "You cannot add the task to this bucket as it already exceeded the limit of tasks it can hold.",
}
}
// =============
// Saved Filters
// =============
// ErrSavedFilterDoesNotExist represents an error where a kanban bucket does not exist
type ErrSavedFilterDoesNotExist struct {
SavedFilterID int64
}
// IsErrSavedFilterDoesNotExist checks if an error is ErrSavedFilterDoesNotExist.
func IsErrSavedFilterDoesNotExist(err error) bool {
_, ok := err.(ErrSavedFilterDoesNotExist)
return ok
}
func (err ErrSavedFilterDoesNotExist) Error() string {
return fmt.Sprintf("Saved filter does not exist [SavedFilterID: %d]", err.SavedFilterID)
}
// ErrCodeSavedFilterDoesNotExist holds the unique world-error code of this error
const ErrCodeSavedFilterDoesNotExist = 11001
// HTTPError holds the http error description
func (err ErrSavedFilterDoesNotExist) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusNotFound,
Code: ErrCodeSavedFilterDoesNotExist,
Message: "This saved filter does not exist.",
}
}
// ErrSavedFilterNotAvailableForLinkShare represents an error where a kanban bucket does not exist
type ErrSavedFilterNotAvailableForLinkShare struct {
SavedFilterID int64
LinkShareID int64
}
// IsErrSavedFilterNotAvailableForLinkShare checks if an error is ErrSavedFilterNotAvailableForLinkShare.
func IsErrSavedFilterNotAvailableForLinkShare(err error) bool {
_, ok := err.(ErrSavedFilterNotAvailableForLinkShare)
return ok
}
func (err ErrSavedFilterNotAvailableForLinkShare) Error() string {
return fmt.Sprintf("Saved filters are not available for link shares [SavedFilterID: %d, LinkShareID: %d]", err.SavedFilterID, err.LinkShareID)
}
// ErrCodeSavedFilterNotAvailableForLinkShare holds the unique world-error code of this error
const ErrCodeSavedFilterNotAvailableForLinkShare = 11002
// HTTPError holds the http error description
func (err ErrSavedFilterNotAvailableForLinkShare) HTTPError() web.HTTPError {
return web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeSavedFilterNotAvailableForLinkShare,
Message: "Saved filters are not available for link shares.",
}
}

View File

@ -17,10 +17,11 @@
package models
import (
"time"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"time"
"xorm.io/xorm"
)
@ -35,6 +36,9 @@ type Bucket struct {
// All tasks which belong to this bucket.
Tasks []*Task `xorm:"-" json:"tasks"`
// How many tasks can be at the same time on this board max
Limit int64 `xorm:"default 0" json:"limit"`
// A timestamp when this bucket was created. You cannot change this value.
Created time.Time `xorm:"created not null" json:"created"`
// A timestamp when this bucket was last updated. You cannot change this value.
@ -125,7 +129,7 @@ func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (r
},
},
}
tasks, _, _, err := getTasksForLists([]*List{{ID: b.ListID}}, opts)
tasks, _, _, err := getTasksForLists([]*List{{ID: b.ListID}}, auth, opts)
if err != nil {
return
}

View File

@ -17,10 +17,11 @@
package models
import (
"testing"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"testing"
)
func TestBucket_ReadAll(t *testing.T) {
@ -78,6 +79,10 @@ func TestBucket_Delete(t *testing.T) {
err = x.Where("bucket_id = ?", 1).Find(&tasks)
assert.NoError(t, err)
assert.Len(t, tasks, 15)
db.AssertMissing(t, "buckets", map[string]interface{}{
"id": 2,
"list_id": 1,
})
})
t.Run("last bucket in list", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
@ -88,5 +93,9 @@ func TestBucket_Delete(t *testing.T) {
err := b.Delete()
assert.Error(t, err)
assert.True(t, IsErrCannotRemoveLastBucket(err))
db.AssertExists(t, "buckets", map[string]interface{}{
"id": 34,
"list_id": 18,
}, false)
})
}

View File

@ -17,9 +17,10 @@
package models
import (
"time"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"time"
)
// Label represents a label
@ -27,7 +28,7 @@ type Label struct {
// The unique, numeric id of this label.
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id" param:"label"`
// The title of the lable. You'll see this one on tasks associated with it.
Title string `xorm:"varchar(250) not null" json:"title" valid:"runelength(1|250)" minLength:"3" maxLength:"250"`
Title string `xorm:"varchar(250) not null" json:"title" valid:"runelength(1|250)" minLength:"1" maxLength:"250"`
// The label description.
Description string `xorm:"longtext null" json:"description"`
// The color this label has
@ -217,7 +218,7 @@ func getUserTaskIDs(u *user.User) (taskIDs []int64, err error) {
return nil, err
}
tasks, _, _, err := getRawTasksForLists(lists, &taskOptions{
tasks, _, _, err := getRawTasksForLists(lists, u, &taskOptions{
page: -1,
perPage: 0,
})

View File

@ -17,9 +17,10 @@
package models
import (
"time"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"time"
"xorm.io/builder"
)

View File

@ -1,14 +1,15 @@
package models
import (
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"reflect"
"runtime"
"testing"
"time"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"code.vikunja.io/web"
)
@ -202,6 +203,13 @@ func TestLabelTask_Create(t *testing.T) {
if (err != nil) && tt.wantErr && !tt.errType(err) {
t.Errorf("LabelTask.Create() Wrong error type! Error = %v, want = %v", err, runtime.FuncForPC(reflect.ValueOf(tt.errType).Pointer()).Name())
}
if !tt.wantErr {
db.AssertExists(t, "label_task", map[string]interface{}{
"id": l.ID,
"task_id": l.TaskID,
"label_id": l.LabelID,
}, false)
}
})
}
}
@ -291,6 +299,12 @@ func TestLabelTask_Delete(t *testing.T) {
if (err != nil) && tt.wantErr && !tt.errType(err) {
t.Errorf("LabelTask.Delete() Wrong error type! Error = %v, want = %v", err, runtime.FuncForPC(reflect.ValueOf(tt.errType).Pointer()).Name())
}
if !tt.wantForbidden {
db.AssertMissing(t, "label_task", map[string]interface{}{
"label_id": l.LabelID,
"task_id": l.TaskID,
})
}
})
}
}

View File

@ -17,14 +17,15 @@
package models
import (
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"reflect"
"runtime"
"testing"
"time"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"code.vikunja.io/web"
)
@ -314,6 +315,14 @@ func TestLabel_Create(t *testing.T) {
if err := l.Create(tt.args.a); (err != nil) != tt.wantErr {
t.Errorf("Label.Create() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.wantErr {
db.AssertExists(t, "labels", map[string]interface{}{
"id": l.ID,
"title": l.Title,
"description": l.Description,
"hex_color": l.HexColor,
}, false)
}
})
}
}
@ -396,6 +405,12 @@ func TestLabel_Update(t *testing.T) {
if err := l.Update(); (err != nil) != tt.wantErr {
t.Errorf("Label.Update() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.wantErr && !tt.wantForbidden {
db.AssertExists(t, "labels", map[string]interface{}{
"id": tt.fields.ID,
"title": tt.fields.Title,
}, false)
}
})
}
}
@ -474,6 +489,11 @@ func TestLabel_Delete(t *testing.T) {
if err := l.Delete(); (err != nil) != tt.wantErr {
t.Errorf("Label.Delete() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.wantErr && !tt.wantForbidden {
db.AssertMissing(t, "labels", map[string]interface{}{
"id": l.ID,
})
}
})
}
}

Some files were not shown because too many files have changed in this diff Show More