Sort Order for tasks #110
|
@ -45,6 +45,8 @@ This document describes the different errors Vikunja can return.
|
|||
| 4010 | 400 | Cannot relate a task with itself. |
|
||||
| 4011 | 404 | The task attachment does not exist. |
|
||||
| 4012 | 400 | The task attachment is too large. |
|
||||
| 4013 | 400 | The task sort param is invalid. |
|
||||
| 4014 | 400 | The task sort order is invalid. |
|
||||
| 5001 | 404 | The namspace does not exist. |
|
||||
| 5003 | 403 | The user does not have access to the specified namespace. |
|
||||
| 5006 | 400 | The namespace name cannot be empty. |
|
||||
|
|
13
go.mod
13
go.mod
|
@ -25,15 +25,12 @@ require (
|
|||
github.com/c2h5oh/datasize v0.0.0-20171227191756-4eba002a5eae
|
||||
github.com/client9/misspell v0.3.4
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/creack/pty v1.1.9 // indirect
|
||||
github.com/d4l3k/messagediff v1.2.1 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/fzipp/gocyclo v0.0.0-20150627053110-6acd4345c835
|
||||
github.com/garyburd/redigo v1.6.0 // indirect
|
||||
github.com/gin-gonic/gin v1.5.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.3 // indirect
|
||||
github.com/go-openapi/spec v0.19.4 // indirect
|
||||
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||
github.com/go-redis/redis v6.15.2+incompatible
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/go-xorm/builder v0.3.4
|
||||
|
@ -41,22 +38,21 @@ require (
|
|||
github.com/go-xorm/tests v0.5.6 // indirect
|
||||
github.com/go-xorm/xorm v0.7.1
|
||||
github.com/go-xorm/xorm-redis-cache v0.0.0-20180727005610-859b313566b2
|
||||
github.com/golang/protobuf v1.3.2 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc
|
||||
github.com/imdario/mergo v0.3.7
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jgautheron/goconst v0.0.0-20170703170152-9740945f5dcb
|
||||
github.com/json-iterator/go v1.1.8 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
github.com/labstack/echo/v4 v4.1.11
|
||||
github.com/labstack/gommon v0.3.0
|
||||
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef
|
||||
github.com/leodido/go-urn v1.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.10 // indirect
|
||||
github.com/mattn/go-oci8 v0.0.0-20181130072307-052f5d97b9b6 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.10.0
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/olekukonko/tablewriter v0.0.1
|
||||
github.com/onsi/ginkgo v1.7.0 // indirect
|
||||
github.com/onsi/gomega v1.4.3 // indirect
|
||||
|
@ -79,15 +75,12 @@ require (
|
|||
golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422
|
||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 // indirect
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 // indirect
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d // indirect
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 // indirect
|
||||
google.golang.org/appengine v1.5.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1
|
||||
gopkg.in/go-playground/validator.v9 v9.30.2 // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/testfixtures.v2 v2.5.3
|
||||
gopkg.in/yaml.v2 v2.2.7 // indirect
|
||||
|
@ -97,3 +90,5 @@ require (
|
|||
)
|
||||
|
||||
replace github.com/samedi/caldav-go => github.com/kolaente/caldav-go v3.0.1-0.20190524174923-9e5cd1688227+incompatible // Branch: feature/dynamic-supported-components, PR: https://github.com/samedi/caldav-go/pull/6 and https://github.com/samedi/caldav-go/pull/7
|
||||
|
||||
go 1.13
|
||||
|
|
119
go.sum
119
go.sum
|
@ -1,24 +1,6 @@
|
|||
cloud.google.com/go v0.33.1/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
code.vikunja.io/web v0.0.0-20190507193736-edb39812af9c h1:L8aPCsaLQe9qytRavkRqipse64EbDK8mFijm+9SKf7I=
|
||||
code.vikunja.io/web v0.0.0-20190507193736-edb39812af9c/go.mod h1:9dOotUqYZJhDhimNh4Xo4e2i+8cR+qPFEQNCUzaplsI=
|
||||
code.vikunja.io/web v0.0.0-20190628071027-b5c16e24b0a7 h1:P9ncMaJE7RbYqBXF9lwT0hab7EPwuHOPslz3k1VxFs8=
|
||||
code.vikunja.io/web v0.0.0-20190628071027-b5c16e24b0a7/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20190628075253-b457b5a1a332 h1:gXxyLkjhgN+vqrLvPyqyScyG5fbu44FJp61TvntWM24=
|
||||
code.vikunja.io/web v0.0.0-20190628075253-b457b5a1a332/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191021211916-f7834b02a174 h1:hBY+r6bzGEfHxolaXbiVoz2LBNNnyHZK7d7Ga4Jowu8=
|
||||
code.vikunja.io/web v0.0.0-20191021211916-f7834b02a174/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191022193355-23a3d145177a h1:exDC9eZ+SK0GT3zB/5f3OBahWzbTZlvX9OfZWgqlbeI=
|
||||
code.vikunja.io/web v0.0.0-20191022193355-23a3d145177a/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191022195605-8edfc5d33c79 h1:U2px27G/b082nUu8vO21wFNKF9BM+5YQJj4XRZiyn2I=
|
||||
code.vikunja.io/web v0.0.0-20191022195605-8edfc5d33c79/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191023144416-3ee093147b6d h1:zhNidbAwqJSnkql03i7aHDUMyQo1vM8yR1Ks495FKvc=
|
||||
code.vikunja.io/web v0.0.0-20191023144416-3ee093147b6d/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191023145656-bce8b505205d h1:Fw5eiTr4p82l4PLaML1ARgx3fjyebxVNvPsCz727brk=
|
||||
code.vikunja.io/web v0.0.0-20191023145656-bce8b505205d/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191023190415-502bbbbd9dfa h1:rtYKpdT/6wGgxGNFUzl9Q/AHgS778+rSC20AcBPNu/I=
|
||||
code.vikunja.io/web v0.0.0-20191023190415-502bbbbd9dfa/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
code.vikunja.io/web v0.0.0-20191023202526-f337750c3573 h1:q+nf3ao4vLpoAaksuk6lkRAMAcD2grOPNj/HwjejLl4=
|
||||
code.vikunja.io/web v0.0.0-20191023202526-f337750c3573/go.mod h1:cuP1/ieGWAZzgQGw+QPt6Y5F0fVb/8Ol5NV4QSezGdo=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
|
@ -31,8 +13,6 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
|
|||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
|
@ -55,9 +35,6 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cweill/gotests v1.5.3 h1:k3t4wW/x/YNixWZJhUIn+mivmK5iV1tJVOwVYkx0UcU=
|
||||
github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
|
||||
github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -81,42 +58,27 @@ github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NB
|
|||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
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.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||
github.com/go-chi/chi v3.3.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
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.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.0 h1:FTUMcX77w5rQkClIzDtTxvn6Bsa894CcrzNj2MMfeg8=
|
||||
github.com/go-openapi/jsonpointer v0.19.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.18.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/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
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.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
||||
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/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8=
|
||||
github.com/go-openapi/swag v0.19.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-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-redis/redis v6.14.0+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
|
||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
|
@ -147,7 +109,6 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
|
|||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc h1:cJlkeAx1QYgO5N80aF5xRGstVsRQwgLR7uA2FnP1ZjY=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
|
@ -169,63 +130,42 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx
|
|||
github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
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/kolaente/caldav-go v3.0.1-0.20190524174923-9e5cd1688227+incompatible h1:PkEEpmbrFXlMul8cOplR8nkcIM/NDbx+H6fq2+vaKAA=
|
||||
github.com/kolaente/caldav-go v3.0.1-0.20190524174923-9e5cd1688227+incompatible/go.mod h1:y1UhTNI4g0hVymJrI6yJ5/ohy09hNBeU8iJEZjgdDOw=
|
||||
github.com/kolaente/echo/v4 v4.0.0-20190507190305-3725a216d803/go.mod h1:3LbYC6VkwmUnmLPZ8WFdHdQHG77e9GQbjyhWdb1QvC4=
|
||||
github.com/kolaente/echo/v4 v4.0.0-20190621113036-3b0700f6d073 h1:vOueKBVhcaAusqPDK/g7lRYOwqfQ0YI3oLrBV+iGZV8=
|
||||
github.com/kolaente/echo/v4 v4.0.0-20190621113036-3b0700f6d073/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
||||
github.com/kolaente/echo/v4 v4.0.0-20190622213746-34000ea0f7d3 h1:5RyXbSrJtkFl1EGFgyDYwiBQMbj8sMtP33aFHnT+5YE=
|
||||
github.com/kolaente/echo/v4 v4.0.0-20190622213746-34000ea0f7d3/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
||||
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=
|
||||
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
|
||||
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||
github.com/labstack/echo/v4 v4.1.5/go.mod h1:3LbYC6VkwmUnmLPZ8WFdHdQHG77e9GQbjyhWdb1QvC4=
|
||||
github.com/labstack/echo/v4 v4.1.6 h1:WOvLa4T1KzWCRpANwz0HGgWDelXSSGwIKtKBbFdHTv4=
|
||||
github.com/labstack/echo/v4 v4.1.6/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
||||
github.com/labstack/echo/v4 v4.1.7-0.20190627175217-8fb7b5be270f h1:fNJtR+TNyxTdYCZU40fc8Or8RyBqMOKYNv+Zay5gjvk=
|
||||
github.com/labstack/echo/v4 v4.1.7-0.20190627175217-8fb7b5be270f/go.mod h1:kU/7PwzgNxZH4das4XNsSpBSOD09XIF5YEPzjpkGnGE=
|
||||
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
|
||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||
github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0=
|
||||
github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
|
||||
github.com/labstack/gommon v0.2.9 h1:heVeuAYtevIQVYkGj6A41dtfT91LrvFG220lavpWhrU=
|
||||
github.com/labstack/gommon v0.2.9/go.mod h1:E8ZTmW9vw5az5/ZyHWCp0Lw4OH2ecsaBP1C/NKavGG4=
|
||||
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=
|
||||
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef/go.mod h1:4LATl0uhhtytR6p9n1AlktDyIz4u2iUnWEdI3L/hXiw=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983 h1:wL11wNW7dhKIcRCHSm4sHKPWz0tt4mwBsVodG7+Xyqg=
|
||||
github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/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/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
|
||||
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=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
|
||||
|
@ -245,10 +185,11 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
|
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
|
@ -314,31 +255,20 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
|||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||
github.com/swaggo/gin-swagger v1.1.0/go.mod h1:FQlm07YuT1glfN3hQiO11UQ2m39vOCZ/aa3WWr5E+XU=
|
||||
github.com/swaggo/gin-swagger v1.2.0/go.mod h1:qlH2+W7zXGZkczuL+r2nEBR2JTT+/lX05Nn6vPhc7OI=
|
||||
github.com/swaggo/swag v1.4.0/go.mod h1:hog2WgeMOrQ/LvQ+o1YGTeT+vWVrbi0SiIslBtxKTyM=
|
||||
github.com/swaggo/swag v1.5.0 h1:haK8VG3hj+v/c8hQ4f3U+oYpkdI/26m9LAUTXHOv+2U=
|
||||
github.com/swaggo/swag v1.5.0/go.mod h1:+xZrnu5Ut3GcUkKAJm9spnOooIS1WB1cUOkLNPrvrE0=
|
||||
github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
|
||||
github.com/swaggo/swag v1.6.3 h1:N+uVPGP4H2hXoss2pt5dctoSUPKKRInr6qcTMOm0usI=
|
||||
github.com/swaggo/swag v1.6.3/go.mod h1:wcc83tB4Mb2aNiL/HP4MFeQdpHUrca+Rp/DRNgWAUio=
|
||||
github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
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=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v0.0.0-20190320090025-2dc34c0b8780/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
|
||||
github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2tfCQDUqRd8fI=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ulule/limiter/v3 v3.3.0 h1:DuMRthpkl1wW9Em6xOVw5HMHnbDumSIDydiMqP0PTXs=
|
||||
github.com/ulule/limiter/v3 v3.3.0/go.mod h1:E6sfg3hfRgW+yFvkE/rZf6YLqXYFMWTmZaZKvdEiQsA=
|
||||
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 v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
|
@ -354,16 +284,11 @@ golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 h1:rlLehGeYg6jfoyz/eDqDU1iRXLKfR42nnNh57ytKEWo=
|
||||
golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/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-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1 h1:anGSYQpPhQwXlwsu5wmfq0nWkCNaMEMUwAv13Y92hd8=
|
||||
golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
|
||||
|
@ -376,9 +301,7 @@ golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73r
|
|||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190322120337-addf6b3196f6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/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=
|
||||
|
@ -388,10 +311,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191011234655-491137f69257 h1:ry8e2D+cwaV6hk7lb3aRTjjZo24shrbK0e11QEOkTIg=
|
||||
golang.org/x/net v0.0.0-20191011234655-491137f69257/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8=
|
||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk=
|
||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -399,34 +318,20 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTm
|
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190609082536-301114b31cce/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-20190621203818-d432491b9138 h1:t8BZD9RDjkm9/h7yYN6kE8oaeov5r9aztkB7zKA5Tkg=
|
||||
golang.org/x/sys v0.0.0-20190621203818-d432491b9138/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-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU=
|
||||
golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191023145028-b69606af412f h1:HNixo/W24k2W4EliZfUFl5ApIz/dMDShw52wmWfJ8/s=
|
||||
golang.org/x/sys v0.0.0-20191023145028-b69606af412f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191023151326-f89234f9a2c2 h1:I7efaDQAsIQmkTF+WSdcydwVWzK07Yuz8IFF8rNkDe0=
|
||||
golang.org/x/sys v0.0.0-20191023151326-f89234f9a2c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
|
@ -434,31 +339,16 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190110015856-aa033095749b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190608022120-eacb66d2a7c3/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 h1:MQEvx39qSf8vyrx3XRaOe+j1UDIzKwkYOVObRgGPVqI=
|
||||
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=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a h1:TwMENskLwU2NnWBzrJGEWHqSiGUkO/B4rfyhwqDxDYQ=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191022174149-ab6dbf99d100 h1:OT2Y8iVtXGHPODZd6iwpndJmAYRiZc75IYxlufvlkLg=
|
||||
golang.org/x/tools v0.0.0-20191022174149-ab6dbf99d100/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191023143423-ff611c50cd12 h1:s9/f9YHBWfC3jIKMbJElk5+EwgC58Khn6t1EdLnQ9+k=
|
||||
golang.org/x/tools v0.0.0-20191023143423-ff611c50cd12/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191023163450-98e333b8b3a3 h1:4haCIJia9wHJUU7z9f7PTC8Nf599Ok93njSCHb5gJas=
|
||||
golang.org/x/tools v0.0.0-20191023163450-98e333b8b3a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191023202404-2b779830f9d3 h1:0vQisIa3mUFShxg7Xyq8WFt/ArQ1soDk5A5uF62IJCc=
|
||||
golang.org/x/tools v0.0.0-20191023202404-2b779830f9d3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d h1:/iIZNFGxc/a7C3yWjGcnboV+Tkc7mxr+p6fDztwoxuM=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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=
|
||||
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=
|
||||
|
@ -470,6 +360,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1 h1:70AthpjunwzUiarMHyED52mj9UwtAnE89l1Gmrt3EU0=
|
||||
gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn++04Xniyg44=
|
||||
|
@ -477,8 +368,6 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
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/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/go-playground/validator.v9 v9.30.2/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M=
|
||||
|
@ -491,8 +380,6 @@ gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a h1:LJwr7TCTghdatWv40WobzlKXc9c4s8oGa7QKJUtHhWA=
|
||||
|
|
|
@ -90,38 +90,49 @@ func TestTaskCollection(t *testing.T) {
|
|||
assert.NotContains(t, rec.Body.String(), `task #14`)
|
||||
})
|
||||
t.Run("Sort Order", func(t *testing.T) {
|
||||
// should equal priority desc
|
||||
// TODO: Add more cases
|
||||
// should equal priority asc
|
||||
t.Run("by priority", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"priority"}}, urlParams)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, urlParams)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,`)
|
||||
assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0.5,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
t.Run("by priority desc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"prioritydesc"}}, urlParams)
|
||||
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,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,`)
|
||||
})
|
||||
t.Run("by priority asc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"priorityasc"}}, urlParams)
|
||||
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,"text":"task #33 with percent done","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0.5,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
// should equal duedate desc
|
||||
// should equal duedate asc
|
||||
t.Run("by duedate", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedate"}}, urlParams)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date_unix"}}, urlParams)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
|
||||
assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
t.Run("by duedate desc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedatedesc"}}, urlParams)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date_unix"}, "order_by": []string{"desc"}}, urlParams)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
|
||||
})
|
||||
t.Run("by duedate asc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedateasc"}}, urlParams)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date_unix"}, "order_by": []string{"asc"}}, urlParams)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
t.Run("invalid sort parameter", func(t *testing.T) {
|
||||
_, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"loremipsum"}}, urlParams)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidSortParam)
|
||||
})
|
||||
t.Run("invalid sort order", func(t *testing.T) {
|
||||
_, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"id"}, "order_by": []string{"loremipsum"}}, urlParams)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidSortOrder)
|
||||
})
|
||||
t.Run("invalid parameter", func(t *testing.T) {
|
||||
// Invalid parameter should not sort at all
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"loremipsum"}}, urlParams)
|
||||
|
@ -234,35 +245,35 @@ func TestTaskCollection(t *testing.T) {
|
|||
assert.NotContains(t, rec.Body.String(), `task #14`)
|
||||
})
|
||||
t.Run("Sort Order", func(t *testing.T) {
|
||||
// should equal priority desc
|
||||
// should equal priority asc
|
||||
t.Run("by priority", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"priority"}}, nil)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,`)
|
||||
assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0.5,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
t.Run("by priority desc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"prioritydesc"}}, nil)
|
||||
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,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,`)
|
||||
})
|
||||
t.Run("by priority asc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"priorityasc"}}, nil)
|
||||
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,"text":"task #33 with percent done","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0.5,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
// should equal duedate desc
|
||||
// should equal duedate asc
|
||||
t.Run("by duedate", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedate"}}, nil)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date_unix"}}, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
|
||||
assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
t.Run("by duedate desc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedatedesc"}}, nil)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date_unix"}, "order_by": []string{"desc"}}, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`)
|
||||
})
|
||||
t.Run("by duedate asc", func(t *testing.T) {
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort": []string{"duedateasc"}}, nil)
|
||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date_unix"}, "order_by": []string{"asc"}}, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","percentDone":0,"related_tasks":{},"attachments":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","avatarUrl":"111d68d06e2d317b5a59c2c6c5bad808","created":0,"updated":0}}]`)
|
||||
})
|
||||
|
|
|
@ -788,6 +788,60 @@ func (err ErrTaskAttachmentIsTooLarge) HTTPError() web.HTTPError {
|
|||
}
|
||||
}
|
||||
|
||||
// ErrInvalidSortParam represents an error where the provided sort param is invalid
|
||||
type ErrInvalidSortParam struct {
|
||||
SortBy sortProperty
|
||||
}
|
||||
|
||||
// IsErrInvalidSortParam checks if an error is ErrInvalidSortParam.
|
||||
func IsErrInvalidSortParam(err error) bool {
|
||||
_, ok := err.(ErrInvalidSortParam)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrInvalidSortParam) Error() string {
|
||||
return fmt.Sprintf("Sort param is invalid [SortBy: %s]", err.SortBy)
|
||||
}
|
||||
|
||||
// ErrCodeInvalidSortParam holds the unique world-error code of this error
|
||||
const ErrCodeInvalidSortParam = 4013
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrInvalidSortParam) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{
|
||||
HTTPCode: http.StatusBadRequest,
|
||||
Code: ErrCodeInvalidSortParam,
|
||||
Message: fmt.Sprintf("The task sort param '%s' is invalid.", err.SortBy),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrInvalidSortOrder represents an error where the provided sort order is invalid
|
||||
type ErrInvalidSortOrder struct {
|
||||
OrderBy sortOrder
|
||||
}
|
||||
|
||||
// IsErrInvalidSortOrder checks if an error is ErrInvalidSortOrder.
|
||||
func IsErrInvalidSortOrder(err error) bool {
|
||||
_, ok := err.(ErrInvalidSortOrder)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrInvalidSortOrder) Error() string {
|
||||
return fmt.Sprintf("Sort order is invalid [OrderBy: %s]", err.OrderBy)
|
||||
}
|
||||
|
||||
// ErrCodeInvalidSortOrder holds the unique world-error code of this error
|
||||
const ErrCodeInvalidSortOrder = 4014
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrInvalidSortOrder) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{
|
||||
HTTPCode: http.StatusBadRequest,
|
||||
Code: ErrCodeInvalidSortOrder,
|
||||
Message: fmt.Sprintf("The task sort order '%s' is invalid. Allowed is either asc or desc.", err.OrderBy),
|
||||
}
|
||||
}
|
||||
|
||||
// =================
|
||||
// Namespace errors
|
||||
// =================
|
||||
|
|
|
@ -209,7 +209,6 @@ func getUserTaskIDs(u *User) (taskIDs []int64, err error) {
|
|||
tasks, _, _, err := getRawTasksForLists(lists, &taskOptions{
|
||||
startDate: time.Unix(0, 0),
|
||||
endDate: time.Unix(0, 0),
|
||||
sortby: SortTasksByUnsorted,
|
||||
page: -1,
|
||||
perPage: 0,
|
||||
})
|
||||
|
|
|
@ -24,18 +24,22 @@ import (
|
|||
|
||||
// TaskCollection is a struct used to hold filter details and not clutter the Task struct with information not related to actual tasks.
|
||||
type TaskCollection struct {
|
||||
ListID int64 `param:"list"`
|
||||
Sorting string `query:"sort"` // Parameter to sort by
|
||||
StartDateSortUnix int64 `query:"startdate"`
|
||||
EndDateSortUnix int64 `query:"enddate"`
|
||||
ListID int64 `param:"list"`
|
||||
StartDateSortUnix int64 `query:"startdate"`
|
||||
EndDateSortUnix int64 `query:"enddate"`
|
||||
Lists []*List
|
||||
|
||||
// The query parameter to sort by. This is for ex. done, priority, etc.
|
||||
SortBy []string `query:"sort_by"`
|
||||
// The query parameter to order the items by. This can be either asc or desc, with asc being the default.
|
||||
OrderBy []string `query:"order_by"`
|
||||
|
||||
web.CRUDable `xorm:"-" json:"-"`
|
||||
web.Rights `xorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// ReadAll gets all tasks for a collection
|
||||
// @Summary Get tasks on a list
|
||||
// @Summary Get tasks in a list
|
||||
// @Description Returns all tasks for the current list.
|
||||
// @tags task
|
||||
// @Accept json
|
||||
|
@ -44,7 +48,8 @@ type TaskCollection struct {
|
|||
// @Param page query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @Param per_page query int false "The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page."
|
||||
|
||||
// @Param s query string false "Search tasks by task text."
|
||||
// @Param sort query string false "The sorting parameter. Possible values to sort by are priority, prioritydesc, priorityasc, duedate, duedatedesc, duedateasc."
|
||||
// @Param sort_by query string false "The sorting parameter. You can pass this multiple times to get the tasks ordered by multiple different parametes, along with `order_by`. Possible values to sort by are `id`, `text`, `description`, `done`, `done_at_unix`, `due_date_unix`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date_unix`, `end_date_unix`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default is `id`."
|
||||
// @Param order_by query string false "The ordering parameter. Possible values to order by are `asc` or `desc`. Default is `asc`."
|
||||
// @Param startdate query int false "The start date parameter to filter by. Expects a unix timestamp. If no end date, but a start date is specified, the end date is set to the current time."
|
||||
// @Param enddate query int false "The end date parameter to filter by. Expects a unix timestamp. If no start date, but an end date is specified, the start date is set to the current time."
|
||||
// @Security JWTKeyAuth
|
||||
|
@ -52,31 +57,32 @@ type TaskCollection struct {
|
|||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{listID}/tasks [get]
|
||||
func (tf *TaskCollection) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, totalItems int64, err error) {
|
||||
var sortby SortBy
|
||||
switch tf.Sorting {
|
||||
case "priority":
|
||||
sortby = SortTasksByPriorityDesc
|
||||
case "prioritydesc":
|
||||
sortby = SortTasksByPriorityDesc
|
||||
case "priorityasc":
|
||||
sortby = SortTasksByPriorityAsc
|
||||
case "duedate":
|
||||
sortby = SortTasksByDueDateDesc
|
||||
case "duedatedesc":
|
||||
sortby = SortTasksByDueDateDesc
|
||||
case "duedateasc":
|
||||
sortby = SortTasksByDueDateAsc
|
||||
default:
|
||||
sortby = SortTasksByUnsorted
|
||||
|
||||
var sort = make([]*sortParam, 0, len(tf.SortBy))
|
||||
for i, s := range tf.SortBy {
|
||||
param := &sortParam{
|
||||
sortBy: sortProperty(s),
|
||||
orderBy: orderAscending,
|
||||
}
|
||||
// This checks if tf.OrderBy has an entry with the same index as the current entry from tf.SortBy
|
||||
// Taken from https://stackoverflow.com/a/27252199/10924593
|
||||
if len(tf.OrderBy) > i {
|
||||
param.orderBy = getSortOrderFromString(tf.OrderBy[i])
|
||||
}
|
||||
// Param validation
|
||||
if err := param.validate(); err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
sort = append(sort, param)
|
||||
}
|
||||
|
||||
taskopts := &taskOptions{
|
||||
search: search,
|
||||
sortby: sortby,
|
||||
startDate: time.Unix(tf.StartDateSortUnix, 0),
|
||||
endDate: time.Unix(tf.EndDateSortUnix, 0),
|
||||
page: page,
|
||||
perPage: perPage,
|
||||
sortby: sort,
|
||||
}
|
||||
|
||||
shareAuth, is := a.(*LinkSharing)
|
||||
|
|
|
@ -0,0 +1,233 @@
|
|||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2019 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 models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type (
|
||||
sortParam struct {
|
||||
sortBy sortProperty
|
||||
orderBy sortOrder // asc or desc
|
||||
}
|
||||
|
||||
sortProperty string
|
||||
|
||||
sortOrder string
|
||||
)
|
||||
|
||||
const (
|
||||
taskPropertyID sortProperty = "id"
|
||||
taskPropertyText sortProperty = "text"
|
||||
taskPropertyDescription sortProperty = "description"
|
||||
taskPropertyDone sortProperty = "done"
|
||||
taskPropertyDoneAtUnix sortProperty = "done_at_unix"
|
||||
taskPropertyDueDateUnix sortProperty = "due_date_unix"
|
||||
taskPropertyCreatedByID sortProperty = "created_by_id"
|
||||
taskPropertyListID sortProperty = "list_id"
|
||||
taskPropertyRepeatAfter sortProperty = "repeat_after"
|
||||
taskPropertyPriority sortProperty = "priority"
|
||||
taskPropertyStartDateUnix sortProperty = "start_date_unix"
|
||||
taskPropertyEndDateUnix sortProperty = "end_date_unix"
|
||||
taskPropertyHexColor sortProperty = "hex_color"
|
||||
taskPropertyPercentDone sortProperty = "percent_done"
|
||||
taskPropertyUID sortProperty = "uid"
|
||||
taskPropertyCreated sortProperty = "created"
|
||||
taskPropertyUpdated sortProperty = "updated"
|
||||
)
|
||||
|
||||
func (p sortProperty) String() string {
|
||||
return string(p)
|
||||
}
|
||||
|
||||
const (
|
||||
orderInvalid sortOrder = "invalid"
|
||||
orderAscending sortOrder = "asc"
|
||||
orderDescending sortOrder = "desc"
|
||||
)
|
||||
|
||||
func (o sortOrder) String() string {
|
||||
return string(o)
|
||||
}
|
||||
|
||||
func getSortOrderFromString(s string) sortOrder {
|
||||
if s == "asc" {
|
||||
return orderAscending
|
||||
}
|
||||
if s == "desc" {
|
||||
return orderDescending
|
||||
}
|
||||
return orderInvalid
|
||||
}
|
||||
|
||||
func (sp *sortParam) validate() error {
|
||||
if sp.orderBy != orderDescending && sp.orderBy != orderAscending {
|
||||
return ErrInvalidSortOrder{OrderBy: sp.orderBy}
|
||||
}
|
||||
switch sp.sortBy {
|
||||
case
|
||||
taskPropertyID,
|
||||
taskPropertyText,
|
||||
taskPropertyDescription,
|
||||
taskPropertyDone,
|
||||
taskPropertyDoneAtUnix,
|
||||
taskPropertyDueDateUnix,
|
||||
taskPropertyCreatedByID,
|
||||
taskPropertyListID,
|
||||
taskPropertyRepeatAfter,
|
||||
taskPropertyPriority,
|
||||
taskPropertyStartDateUnix,
|
||||
taskPropertyEndDateUnix,
|
||||
taskPropertyHexColor,
|
||||
taskPropertyPercentDone,
|
||||
taskPropertyUID,
|
||||
taskPropertyCreated,
|
||||
taskPropertyUpdated:
|
||||
return nil
|
||||
}
|
||||
return ErrInvalidSortParam{SortBy: sp.sortBy}
|
||||
}
|
||||
|
||||
type taskComparator func(lhs, rhs *Task) int64
|
||||
|
||||
func mustMakeComparator(fieldName string) taskComparator {
|
||||
field, ok := reflect.TypeOf(&Task{}).Elem().FieldByName(fieldName)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Field '%s' has not been found on Task", fieldName))
|
||||
}
|
||||
|
||||
extractProp := func(task *Task) interface{} {
|
||||
return reflect.ValueOf(task).Elem().FieldByIndex(field.Index).Interface()
|
||||
}
|
||||
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Int64:
|
||||
return func(lhs, rhs *Task) int64 {
|
||||
return extractProp(lhs).(int64) - extractProp(rhs).(int64)
|
||||
}
|
||||
case reflect.Float64:
|
||||
return func(lhs, rhs *Task) int64 {
|
||||
floatLHS, floatRHS := extractProp(lhs).(float64), extractProp(rhs).(float64)
|
||||
if floatLHS > floatRHS {
|
||||
return 1
|
||||
} else if floatLHS < floatRHS {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
case reflect.String:
|
||||
return func(lhs, rhs *Task) int64 {
|
||||
strLHS, strRHS := extractProp(lhs).(string), extractProp(rhs).(string)
|
||||
if strLHS > strRHS {
|
||||
return 1
|
||||
} else if strLHS < strRHS {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
case reflect.Bool:
|
||||
return func(lhs, rhs *Task) int64 {
|
||||
boolLHS, boolRHS := extractProp(lhs).(bool), extractProp(rhs).(bool)
|
||||
if !boolLHS && boolRHS {
|
||||
return 1
|
||||
} else if boolLHS && !boolRHS {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("Unsupported type for sorting: %s", field.Type.Name()))
|
||||
}
|
||||
}
|
||||
|
||||
// This is a map of properties that can be sorted by
|
||||
// and their appropriate comparator function.
|
||||
// The comparator function sorts in ascending mode.
|
||||
var propertyComparators = map[sortProperty]taskComparator{
|
||||
taskPropertyID: mustMakeComparator("ID"),
|
||||
taskPropertyText: mustMakeComparator("Text"),
|
||||
taskPropertyDescription: mustMakeComparator("Description"),
|
||||
taskPropertyDone: mustMakeComparator("Done"),
|
||||
taskPropertyDoneAtUnix: mustMakeComparator("DoneAtUnix"),
|
||||
taskPropertyDueDateUnix: mustMakeComparator("DueDateUnix"),
|
||||
taskPropertyCreatedByID: mustMakeComparator("CreatedByID"),
|
||||
taskPropertyListID: mustMakeComparator("ListID"),
|
||||
taskPropertyRepeatAfter: mustMakeComparator("RepeatAfter"),
|
||||
taskPropertyPriority: mustMakeComparator("Priority"),
|
||||
taskPropertyStartDateUnix: mustMakeComparator("StartDateUnix"),
|
||||
taskPropertyEndDateUnix: mustMakeComparator("EndDateUnix"),
|
||||
taskPropertyHexColor: mustMakeComparator("HexColor"),
|
||||
taskPropertyPercentDone: mustMakeComparator("PercentDone"),
|
||||
taskPropertyUID: mustMakeComparator("UID"),
|
||||
taskPropertyCreated: mustMakeComparator("Created"),
|
||||
taskPropertyUpdated: mustMakeComparator("Updated"),
|
||||
}
|
||||
|
||||
// Creates a taskComparator that sorts by the first comparator and falls back to
|
||||
// the second one (and so on...) if the properties were equal.
|
||||
func combineComparators(comparators ...taskComparator) taskComparator {
|
||||
return func(lhs, rhs *Task) int64 {
|
||||
for _, compare := range comparators {
|
||||
res := compare(lhs, rhs)
|
||||
if res != 0 {
|
||||
return res
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func sortTasks(tasks []*Task, by []*sortParam) {
|
||||
|
||||
// Always sort at least by id asc so we have a consistent order of items every time
|
||||
// If we would not do this, we would get a different order for items with the same content every time
|
||||
// the slice is sorted. To circumvent this, we always order at least by ID.
|
||||
if len(by) == 0 ||
|
||||
(len(by) > 0 && by[len(by)-1].sortBy != taskPropertyID) { // Don't sort by ID last if the id parameter is already passed as the last parameter.
|
||||
by = append(by, &sortParam{sortBy: taskPropertyID, orderBy: orderAscending})
|
||||
}
|
||||
|
||||
comparators := make([]taskComparator, 0, len(by))
|
||||
for _, param := range by {
|
||||
comparator, ok := propertyComparators[param.sortBy]
|
||||
if !ok {
|
||||
panic("No suitable comparator for sortBy found! Param was " + param.sortBy)
|
||||
}
|
||||
|
||||
// This is a descending sort, so we need to negate the comparator (i.e. switch the inputs).
|
||||
if param.orderBy == orderDescending {
|
||||
oldComparator := comparator
|
||||
comparator = func(lhs, rhs *Task) int64 {
|
||||
return oldComparator(lhs, rhs) * -1
|
||||
}
|
||||
}
|
||||
|
||||
comparators = append(comparators, comparator)
|
||||
}
|
||||
|
||||
combinedComparator := combineComparators(comparators...)
|
||||
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
lhs, rhs := tasks[i], tasks[j]
|
||||
|
||||
res := combinedComparator(lhs, rhs)
|
||||
return res <= 0
|
||||
})
|
||||
}
|
|
@ -0,0 +1,829 @@
|
|||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2019 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 models
|
||||
|
||||
import (
|
||||
"github.com/mohae/deepcopy"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSortParamValidation(t *testing.T) {
|
||||
t.Run("Test valid order by", func(t *testing.T) {
|
||||
t.Run(orderAscending.String(), func(t *testing.T) {
|
||||
s := &sortParam{
|
||||
orderBy: orderAscending,
|
||||
sortBy: "id",
|
||||
}
|
||||
err := s.validate()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run(orderDescending.String(), func(t *testing.T) {
|
||||
s := &sortParam{
|
||||
orderBy: orderDescending,
|
||||
sortBy: "id",
|
||||
}
|
||||
err := s.validate()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
})
|
||||
t.Run("Test valid sort by", func(t *testing.T) {
|
||||
for _, test := range []sortProperty{
|
||||
taskPropertyID,
|
||||
taskPropertyText,
|
||||
taskPropertyDescription,
|
||||
taskPropertyDone,
|
||||
taskPropertyDoneAtUnix,
|
||||
taskPropertyDueDateUnix,
|
||||
taskPropertyCreatedByID,
|
||||
taskPropertyListID,
|
||||
taskPropertyRepeatAfter,
|
||||
taskPropertyPriority,
|
||||
taskPropertyStartDateUnix,
|
||||
taskPropertyEndDateUnix,
|
||||
taskPropertyHexColor,
|
||||
taskPropertyPercentDone,
|
||||
taskPropertyUID,
|
||||
taskPropertyCreated,
|
||||
taskPropertyUpdated,
|
||||
} {
|
||||
t.Run(test.String(), func(t *testing.T) {
|
||||
s := &sortParam{
|
||||
orderBy: orderAscending,
|
||||
sortBy: test,
|
||||
}
|
||||
err := s.validate()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
})
|
||||
t.Run("Test invalid order by", func(t *testing.T) {
|
||||
s := &sortParam{
|
||||
orderBy: "somethingInvalid",
|
||||
sortBy: "id",
|
||||
}
|
||||
err := s.validate()
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrInvalidSortOrder(err))
|
||||
})
|
||||
t.Run("Test invalid sort by", func(t *testing.T) {
|
||||
s := &sortParam{
|
||||
orderBy: orderAscending,
|
||||
sortBy: "somethingInvalid",
|
||||
}
|
||||
err := s.validate()
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrInvalidSortParam(err))
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
task1 = &Task{
|
||||
ID: 1,
|
||||
Text: "aaa",
|
||||
Description: "Lorem Ipsum",
|
||||
Done: true,
|
||||
DoneAtUnix: 1543626000,
|
||||
ListID: 1,
|
||||
UID: "JywtBPCESImlyKugvaZWrxmXAFAWXFISMeXYImEh",
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task2 = &Task{
|
||||
ID: 2,
|
||||
Text: "bbb",
|
||||
Description: "Arem Ipsum",
|
||||
Done: true,
|
||||
DoneAtUnix: 1543626724,
|
||||
CreatedByID: 1,
|
||||
ListID: 2,
|
||||
PercentDone: 0.3,
|
||||
StartDateUnix: 1543626724,
|
||||
Created: 1553626724,
|
||||
Updated: 1553626724,
|
||||
}
|
||||
task3 = &Task{
|
||||
ID: 3,
|
||||
Text: "ccc",
|
||||
DueDateUnix: 1583626724,
|
||||
Priority: 100,
|
||||
ListID: 3,
|
||||
HexColor: "000000",
|
||||
PercentDone: 0.1,
|
||||
Updated: 1555555555,
|
||||
}
|
||||
task4 = &Task{
|
||||
ID: 4,
|
||||
Text: "ddd",
|
||||
Priority: 1,
|
||||
StartDateUnix: 1643626724,
|
||||
ListID: 1,
|
||||
}
|
||||
task5 = &Task{
|
||||
ID: 5,
|
||||
Text: "eef",
|
||||
Priority: 50,
|
||||
UID: "shggzCHQWLhGNMNsOGOCOjcVkInOYjTAnORqTkdL",
|
||||
DueDateUnix: 1543636724,
|
||||
Updated: 1565555555,
|
||||
}
|
||||
task6 = &Task{
|
||||
ID: 6,
|
||||
Text: "eef",
|
||||
DueDateUnix: 1543616724,
|
||||
RepeatAfter: 6400,
|
||||
CreatedByID: 2,
|
||||
HexColor: "ffffff",
|
||||
}
|
||||
task7 = &Task{
|
||||
ID: 7,
|
||||
Text: "mmmn",
|
||||
Description: "Zoremis",
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1584600000,
|
||||
UID: "tyzCZuLMSKhwclJOsDyDcUdyVAPBDOPHNTBOLTcW",
|
||||
}
|
||||
task8 = &Task{
|
||||
ID: 8,
|
||||
Text: "b123",
|
||||
EndDateUnix: 1544700000,
|
||||
}
|
||||
task9 = &Task{
|
||||
ID: 9,
|
||||
Done: true,
|
||||
DoneAtUnix: 1573626724,
|
||||
Text: "a123",
|
||||
RepeatAfter: 86000,
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1544700000,
|
||||
}
|
||||
task10 = &Task{
|
||||
ID: 10,
|
||||
Text: "zzz",
|
||||
Priority: 10,
|
||||
PercentDone: 1,
|
||||
}
|
||||
)
|
||||
|
||||
type taskSortTestCase struct {
|
||||
name string
|
||||
wantAsc []*Task
|
||||
wantDesc []*Task
|
||||
sortProperty sortProperty
|
||||
}
|
||||
|
||||
var taskSortTestCases = []taskSortTestCase{
|
||||
{
|
||||
name: "id",
|
||||
sortProperty: taskPropertyID,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task10,
|
||||
task9,
|
||||
task8,
|
||||
task7,
|
||||
task6,
|
||||
task5,
|
||||
task4,
|
||||
task3,
|
||||
task2,
|
||||
task1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "text",
|
||||
sortProperty: taskPropertyText,
|
||||
wantAsc: []*Task{
|
||||
task9,
|
||||
task1,
|
||||
task8,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task10,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task10,
|
||||
task7,
|
||||
task5,
|
||||
task6,
|
||||
task4,
|
||||
task3,
|
||||
task2,
|
||||
task8,
|
||||
task1,
|
||||
task9,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
sortProperty: taskPropertyDescription,
|
||||
wantAsc: []*Task{
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task2,
|
||||
task1,
|
||||
task7,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task7,
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "done",
|
||||
sortProperty: taskPropertyDone,
|
||||
wantAsc: []*Task{
|
||||
// These are done
|
||||
task1,
|
||||
task2,
|
||||
task9,
|
||||
// These are not
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task10,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
// These are not
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task10,
|
||||
// These are done
|
||||
task1,
|
||||
task2,
|
||||
task9,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "done at",
|
||||
sortProperty: taskPropertyDoneAtUnix,
|
||||
wantAsc: []*Task{
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task10,
|
||||
task1,
|
||||
task2,
|
||||
task9,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task9,
|
||||
task2,
|
||||
task1,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "due date",
|
||||
sortProperty: taskPropertyDueDateUnix,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task4,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task6,
|
||||
task5,
|
||||
task3,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task3,
|
||||
task5,
|
||||
task6,
|
||||
task1,
|
||||
task2,
|
||||
task4,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "created by id",
|
||||
sortProperty: taskPropertyCreatedByID,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task2,
|
||||
task6,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task6,
|
||||
task2,
|
||||
task1,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list id",
|
||||
sortProperty: taskPropertyListID,
|
||||
wantAsc: []*Task{
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task1,
|
||||
task4,
|
||||
task2,
|
||||
task3,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task3,
|
||||
task2,
|
||||
task1,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "repeat after",
|
||||
sortProperty: taskPropertyRepeatAfter,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task7,
|
||||
task8,
|
||||
task10,
|
||||
task6,
|
||||
task9,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task9,
|
||||
task6,
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task7,
|
||||
task8,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "priority",
|
||||
sortProperty: taskPropertyPriority,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task4,
|
||||
task10,
|
||||
task5,
|
||||
task3,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task3,
|
||||
task5,
|
||||
task10,
|
||||
task4,
|
||||
task1,
|
||||
task2,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "start date",
|
||||
sortProperty: taskPropertyStartDateUnix,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task3,
|
||||
task5,
|
||||
task6,
|
||||
task8,
|
||||
task10,
|
||||
task2,
|
||||
task7,
|
||||
task9,
|
||||
task4,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task4,
|
||||
task7,
|
||||
task9,
|
||||
task2,
|
||||
task1,
|
||||
task3,
|
||||
task5,
|
||||
task6,
|
||||
task8,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "end date",
|
||||
sortProperty: taskPropertyEndDateUnix,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task10,
|
||||
task8,
|
||||
task9,
|
||||
task7,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "hex color",
|
||||
sortProperty: taskPropertyHexColor,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task4,
|
||||
task5,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task3,
|
||||
task6,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task6,
|
||||
task3,
|
||||
task1,
|
||||
task2,
|
||||
task4,
|
||||
task5,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "percent done",
|
||||
sortProperty: taskPropertyPercentDone,
|
||||
wantAsc: []*Task{
|
||||
task1,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task3,
|
||||
task2,
|
||||
task10,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task10,
|
||||
task2,
|
||||
task3,
|
||||
task1,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "uid",
|
||||
sortProperty: taskPropertyUID,
|
||||
wantAsc: []*Task{
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task6,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task1,
|
||||
task5,
|
||||
task7,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task7,
|
||||
task5,
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task6,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "created",
|
||||
sortProperty: taskPropertyCreated,
|
||||
wantAsc: []*Task{
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task1,
|
||||
task2,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task2,
|
||||
task1,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "updated",
|
||||
sortProperty: taskPropertyUpdated,
|
||||
wantAsc: []*Task{
|
||||
task4,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task5,
|
||||
},
|
||||
wantDesc: []*Task{
|
||||
task5,
|
||||
task3,
|
||||
task2,
|
||||
task1,
|
||||
task4,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestTaskSort(t *testing.T) {
|
||||
|
||||
assertTestSliceMatch := func(t *testing.T, got, want []*Task) {
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Error("Slices do not match in order")
|
||||
t.Error("Got\t| Want")
|
||||
for in, task := range got {
|
||||
fail := ""
|
||||
if task.ID != want[in].ID {
|
||||
fail = "wrong"
|
||||
}
|
||||
t.Errorf("\t%d\t| %d \t%s", task.ID, want[in].ID, fail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, testCase := range taskSortTestCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Run("asc default", func(t *testing.T) {
|
||||
by := []*sortParam{
|
||||
{
|
||||
sortBy: testCase.sortProperty,
|
||||
},
|
||||
}
|
||||
|
||||
got := deepcopy.Copy(testCase.wantAsc).([]*Task)
|
||||
|
||||
// Destroy wanted order to obtain some slice we can sort
|
||||
rand.Shuffle(len(got), func(i, j int) {
|
||||
got[i], got[j] = got[j], got[i]
|
||||
})
|
||||
|
||||
sortTasks(got, by)
|
||||
|
||||
assertTestSliceMatch(t, got, testCase.wantAsc)
|
||||
})
|
||||
t.Run("asc", func(t *testing.T) {
|
||||
by := []*sortParam{
|
||||
{
|
||||
sortBy: testCase.sortProperty,
|
||||
orderBy: orderAscending,
|
||||
},
|
||||
}
|
||||
|
||||
got := deepcopy.Copy(testCase.wantAsc).([]*Task)
|
||||
|
||||
// Destroy wanted order to obtain some slice we can sort
|
||||
rand.Shuffle(len(got), func(i, j int) {
|
||||
got[i], got[j] = got[j], got[i]
|
||||
})
|
||||
|
||||
sortTasks(got, by)
|
||||
|
||||
assertTestSliceMatch(t, got, testCase.wantAsc)
|
||||
})
|
||||
t.Run("desc", func(t *testing.T) {
|
||||
by := []*sortParam{
|
||||
{
|
||||
sortBy: testCase.sortProperty,
|
||||
orderBy: orderDescending,
|
||||
},
|
||||
}
|
||||
|
||||
got := deepcopy.Copy(testCase.wantDesc).([]*Task)
|
||||
|
||||
// Destroy wanted order to obtain some slice we can sort
|
||||
rand.Shuffle(len(got), func(i, j int) {
|
||||
got[i], got[j] = got[j], got[i]
|
||||
})
|
||||
|
||||
sortTasks(got, by)
|
||||
|
||||
assertTestSliceMatch(t, got, testCase.wantDesc)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Other cases
|
||||
t.Run("Order by Done Ascending and Text Descending", func(t *testing.T) {
|
||||
want := []*Task{
|
||||
// Done
|
||||
task2,
|
||||
task1,
|
||||
task9,
|
||||
|
||||
// Not done
|
||||
task10,
|
||||
task7,
|
||||
task5,
|
||||
task6,
|
||||
task4,
|
||||
task3,
|
||||
task8,
|
||||
}
|
||||
sortParams := []*sortParam{
|
||||
{
|
||||
sortBy: taskPropertyDone,
|
||||
orderBy: orderAscending,
|
||||
},
|
||||
{
|
||||
sortBy: taskPropertyText,
|
||||
orderBy: orderDescending,
|
||||
},
|
||||
}
|
||||
|
||||
got := deepcopy.Copy(want).([]*Task)
|
||||
|
||||
// Destroy wanted order to obtain some slice we can sort
|
||||
rand.Shuffle(len(got), func(i, j int) {
|
||||
got[i], got[j] = got[j], got[i]
|
||||
})
|
||||
|
||||
sortTasks(got, sortParams)
|
||||
|
||||
assertTestSliceMatch(t, got, want)
|
||||
})
|
||||
t.Run("Order by Done Descending and Text Ascending", func(t *testing.T) {
|
||||
want := []*Task{
|
||||
// Not done
|
||||
task8,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task10,
|
||||
|
||||
// Done
|
||||
task9,
|
||||
task1,
|
||||
task2,
|
||||
}
|
||||
sortParams := []*sortParam{
|
||||
{
|
||||
sortBy: taskPropertyDone,
|
||||
orderBy: orderDescending,
|
||||
},
|
||||
{
|
||||
sortBy: taskPropertyText,
|
||||
orderBy: orderAscending,
|
||||
},
|
||||
}
|
||||
|
||||
got := deepcopy.Copy(want).([]*Task)
|
||||
|
||||
// Destroy wanted order to obtain some slice we can sort
|
||||
rand.Shuffle(len(got), func(i, j int) {
|
||||
got[i], got[j] = got[j], got[i]
|
||||
})
|
||||
|
||||
sortTasks(got, sortParams)
|
||||
|
||||
assertTestSliceMatch(t, got, want)
|
||||
|
||||
})
|
||||
}
|
|
@ -0,0 +1,635 @@
|
|||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2019 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 models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
assert.NoError(t, db.LoadFixtures())
|
||||
|
||||
// Dummy users
|
||||
user1 := &User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
||||
}
|
||||
user2 := &User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
|
||||
}
|
||||
user6 := &User{
|
||||
ID: 6,
|
||||
Username: "user6",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed", // hash for ""
|
||||
}
|
||||
|
||||
// We use individual variables for the tasks here to be able to rearrange or remove ones more easily
|
||||
task1 := &Task{
|
||||
ID: 1,
|
||||
Text: "task #1",
|
||||
Description: "Lorem Ipsum",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Labels: []*Label{
|
||||
{
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: user2,
|
||||
Updated: 0,
|
||||
Created: 0,
|
||||
},
|
||||
},
|
||||
RelatedTasks: map[RelationKind][]*Task{
|
||||
RelationKindSubtask: {
|
||||
{
|
||||
ID: 29,
|
||||
Text: "task #29 with parent task (1)",
|
||||
CreatedByID: 1,
|
||||
ListID: 1,
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
},
|
||||
},
|
||||
Attachments: []*TaskAttachment{
|
||||
{
|
||||
ID: 1,
|
||||
TaskID: 1,
|
||||
FileID: 1,
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
File: &files.File{
|
||||
ID: 1,
|
||||
Name: "test",
|
||||
Size: 100,
|
||||
CreatedUnix: 1570998791,
|
||||
CreatedByID: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
TaskID: 1,
|
||||
FileID: 9999,
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
},
|
||||
},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task2 := &Task{
|
||||
ID: 2,
|
||||
Text: "task #2 done",
|
||||
Done: true,
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Labels: []*Label{
|
||||
{
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: user2,
|
||||
Updated: 0,
|
||||
Created: 0,
|
||||
},
|
||||
},
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task3 := &Task{
|
||||
ID: 3,
|
||||
Text: "task #3 high prio",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
Priority: 100,
|
||||
}
|
||||
task4 := &Task{
|
||||
ID: 4,
|
||||
Text: "task #4 low prio",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
Priority: 1,
|
||||
}
|
||||
task5 := &Task{
|
||||
ID: 5,
|
||||
Text: "task #5 higher due date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
DueDateUnix: 1543636724,
|
||||
}
|
||||
task6 := &Task{
|
||||
ID: 6,
|
||||
Text: "task #6 lower due date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
DueDateUnix: 1543616724,
|
||||
}
|
||||
task7 := &Task{
|
||||
ID: 7,
|
||||
Text: "task #7 with start date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
}
|
||||
task8 := &Task{
|
||||
ID: 8,
|
||||
Text: "task #8 with end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
EndDateUnix: 1544700000,
|
||||
}
|
||||
task9 := &Task{
|
||||
ID: 9,
|
||||
Text: "task #9 with start and end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1544700000,
|
||||
}
|
||||
task10 := &Task{
|
||||
ID: 10,
|
||||
Text: "task #10 basic",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task11 := &Task{
|
||||
ID: 11,
|
||||
Text: "task #11 basic",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task12 := &Task{
|
||||
ID: 12,
|
||||
Text: "task #12 basic",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task15 := &Task{
|
||||
ID: 15,
|
||||
Text: "task #15",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 6,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task16 := &Task{
|
||||
ID: 16,
|
||||
Text: "task #16",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 7,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task17 := &Task{
|
||||
ID: 17,
|
||||
Text: "task #17",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 8,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task18 := &Task{
|
||||
ID: 18,
|
||||
Text: "task #18",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 9,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task19 := &Task{
|
||||
ID: 19,
|
||||
Text: "task #19",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 10,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task20 := &Task{
|
||||
ID: 20,
|
||||
Text: "task #20",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 11,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task21 := &Task{
|
||||
ID: 21,
|
||||
Text: "task #21",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 12,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task22 := &Task{
|
||||
ID: 22,
|
||||
Text: "task #22",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 13,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task23 := &Task{
|
||||
ID: 23,
|
||||
Text: "task #23",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 14,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task24 := &Task{
|
||||
ID: 24,
|
||||
Text: "task #24",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 15,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task25 := &Task{
|
||||
ID: 25,
|
||||
Text: "task #25",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 16,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task26 := &Task{
|
||||
ID: 26,
|
||||
Text: "task #26",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 17,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task27 := &Task{
|
||||
ID: 27,
|
||||
Text: "task #27 with reminders",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
RemindersUnix: []int64{1543626724, 1543626824},
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task28 := &Task{
|
||||
ID: 28,
|
||||
Text: "task #28 with repeat after",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
RepeatAfter: 3600,
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task29 := &Task{
|
||||
ID: 29,
|
||||
Text: "task #29 with parent task (1)",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{
|
||||
RelationKindParenttask: {
|
||||
{
|
||||
ID: 1,
|
||||
Text: "task #1",
|
||||
Description: "Lorem Ipsum",
|
||||
CreatedByID: 1,
|
||||
ListID: 1,
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
},
|
||||
},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task30 := &Task{
|
||||
ID: 30,
|
||||
Text: "task #30 with assignees",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Assignees: []*User{
|
||||
user1,
|
||||
user2,
|
||||
},
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task31 := &Task{
|
||||
ID: 31,
|
||||
Text: "task #31 with color",
|
||||
HexColor: "f0f0f0",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task32 := &Task{
|
||||
ID: 32,
|
||||
Text: "task #32",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 3,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
task33 := &Task{
|
||||
ID: 33,
|
||||
Text: "task #33 with percent done",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
PercentDone: 0.5,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
ListID int64
|
||||
StartDateSortUnix int64
|
||||
EndDateSortUnix int64
|
||||
Lists []*List
|
||||
SortBy []string // Is a string, since this is the place where a query string comes from the user
|
||||
OrderBy []string
|
||||
CRUDable web.CRUDable
|
||||
Rights web.Rights
|
||||
}
|
||||
type args struct {
|
||||
search string
|
||||
a web.Auth
|
||||
page int
|
||||
}
|
||||
type testcase struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want interface{}
|
||||
wantErr bool
|
||||
}
|
||||
tests := []testcase{
|
||||
{
|
||||
name: "ReadAll Tasks normally",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
task1,
|
||||
task2,
|
||||
task3,
|
||||
task4,
|
||||
task5,
|
||||
task6,
|
||||
task7,
|
||||
task8,
|
||||
task9,
|
||||
task10,
|
||||
task11,
|
||||
task12,
|
||||
task15,
|
||||
task16,
|
||||
task17,
|
||||
task18,
|
||||
task19,
|
||||
task20,
|
||||
task21,
|
||||
task22,
|
||||
task23,
|
||||
task24,
|
||||
task25,
|
||||
task26,
|
||||
task27,
|
||||
task28,
|
||||
task29,
|
||||
task30,
|
||||
task31,
|
||||
task32,
|
||||
task33,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
// For more sorting tests see task_collection_sort_test.go
|
||||
name: "ReadAll Tasks sorted by done asc and id desc",
|
||||
fields: fields{
|
||||
SortBy: []string{"done", "id"},
|
||||
OrderBy: []string{"asc", "desc"},
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
task2,
|
||||
task33,
|
||||
task32,
|
||||
task31,
|
||||
task30,
|
||||
task29,
|
||||
task28,
|
||||
task27,
|
||||
task26,
|
||||
task25,
|
||||
task24,
|
||||
task23,
|
||||
task22,
|
||||
task21,
|
||||
task20,
|
||||
task19,
|
||||
task18,
|
||||
task17,
|
||||
task16,
|
||||
task15,
|
||||
task12,
|
||||
task11,
|
||||
task10,
|
||||
task9,
|
||||
task8,
|
||||
task7,
|
||||
task6,
|
||||
task5,
|
||||
task4,
|
||||
task3,
|
||||
task1,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks with range",
|
||||
fields: fields{
|
||||
StartDateSortUnix: 1544500000,
|
||||
EndDateSortUnix: 1544600000,
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
task7,
|
||||
task9,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks with range",
|
||||
fields: fields{
|
||||
StartDateSortUnix: 1544700000,
|
||||
EndDateSortUnix: 1545000000,
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
task8,
|
||||
task9,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks with range without end date",
|
||||
fields: fields{
|
||||
StartDateSortUnix: 1544700000,
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
task8,
|
||||
task9,
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
lt := &TaskCollection{
|
||||
ListID: tt.fields.ListID,
|
||||
StartDateSortUnix: tt.fields.StartDateSortUnix,
|
||||
EndDateSortUnix: tt.fields.EndDateSortUnix,
|
||||
SortBy: tt.fields.SortBy,
|
||||
OrderBy: tt.fields.OrderBy,
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
got, _, _, err := lt.ReadAll(tt.args.a, tt.args.search, tt.args.page, 50)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Test %s, Task.ReadAll() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if diff, equal := messagediff.PrettyDiff(got, tt.want); !equal {
|
||||
t.Errorf("Test %s, LabelTask.ReadAll() = %v, want %v, \ndiff: %v", tt.name, got, tt.want, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,728 +0,0 @@
|
|||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2019 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 models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
func sortTasksForTesting(by SortBy) (tasks []*Task) {
|
||||
user1 := &User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
||||
}
|
||||
user2 := &User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
|
||||
}
|
||||
user6 := &User{
|
||||
ID: 6,
|
||||
Username: "user6",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed", // hash for ""
|
||||
}
|
||||
|
||||
tasks = []*Task{
|
||||
{
|
||||
ID: 1,
|
||||
Text: "task #1",
|
||||
Description: "Lorem Ipsum",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Labels: []*Label{
|
||||
{
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: user2,
|
||||
Updated: 0,
|
||||
Created: 0,
|
||||
},
|
||||
},
|
||||
RelatedTasks: map[RelationKind][]*Task{
|
||||
RelationKindSubtask: {
|
||||
{
|
||||
ID: 29,
|
||||
Text: "task #29 with parent task (1)",
|
||||
CreatedByID: 1,
|
||||
ListID: 1,
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
},
|
||||
},
|
||||
Attachments: []*TaskAttachment{
|
||||
{
|
||||
ID: 1,
|
||||
TaskID: 1,
|
||||
FileID: 1,
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
File: &files.File{
|
||||
ID: 1,
|
||||
Name: "test",
|
||||
Size: 100,
|
||||
CreatedUnix: 1570998791,
|
||||
CreatedByID: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
TaskID: 1,
|
||||
FileID: 9999,
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
},
|
||||
},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
Text: "task #2 done",
|
||||
Done: true,
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Labels: []*Label{
|
||||
{
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: user2,
|
||||
Updated: 0,
|
||||
Created: 0,
|
||||
},
|
||||
},
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
Text: "task #3 high prio",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
Priority: 100,
|
||||
},
|
||||
{
|
||||
ID: 4,
|
||||
Text: "task #4 low prio",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
Priority: 1,
|
||||
},
|
||||
{
|
||||
ID: 5,
|
||||
Text: "task #5 higher due date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
DueDateUnix: 1543636724,
|
||||
},
|
||||
{
|
||||
ID: 6,
|
||||
Text: "task #6 lower due date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
DueDateUnix: 1543616724,
|
||||
},
|
||||
{
|
||||
ID: 7,
|
||||
Text: "task #7 with start date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
},
|
||||
{
|
||||
ID: 8,
|
||||
Text: "task #8 with end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
{
|
||||
ID: 9,
|
||||
Text: "task #9 with start and end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
{
|
||||
ID: 10,
|
||||
Text: "task #10 basic",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 11,
|
||||
Text: "task #11 basic",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 12,
|
||||
Text: "task #12 basic",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 15,
|
||||
Text: "task #15",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 6,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 16,
|
||||
Text: "task #16",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 7,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 17,
|
||||
Text: "task #17",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 8,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 18,
|
||||
Text: "task #18",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 9,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 19,
|
||||
Text: "task #19",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 10,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 20,
|
||||
Text: "task #20",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 11,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 21,
|
||||
Text: "task #21",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 12,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 22,
|
||||
Text: "task #22",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 13,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 23,
|
||||
Text: "task #23",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 14,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 24,
|
||||
Text: "task #24",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 15,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 25,
|
||||
Text: "task #25",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 16,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 26,
|
||||
Text: "task #26",
|
||||
CreatedByID: 6,
|
||||
CreatedBy: user6,
|
||||
ListID: 17,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 27,
|
||||
Text: "task #27 with reminders",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
RemindersUnix: []int64{1543626724, 1543626824},
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 28,
|
||||
Text: "task #28 with repeat after",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
RepeatAfter: 3600,
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 29,
|
||||
Text: "task #29 with parent task (1)",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{
|
||||
RelationKindParenttask: {
|
||||
{
|
||||
ID: 1,
|
||||
Text: "task #1",
|
||||
Description: "Lorem Ipsum",
|
||||
CreatedByID: 1,
|
||||
ListID: 1,
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
},
|
||||
},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 30,
|
||||
Text: "task #30 with assignees",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Assignees: []*User{
|
||||
user1,
|
||||
user2,
|
||||
},
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 31,
|
||||
Text: "task #31 with color",
|
||||
HexColor: "f0f0f0",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 32,
|
||||
Text: "task #32",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 3,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
{
|
||||
ID: 33,
|
||||
Text: "task #33 with percent done",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
PercentDone: 0.5,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
},
|
||||
}
|
||||
|
||||
switch by {
|
||||
case SortTasksByPriorityDesc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].Priority > tasks[j].Priority
|
||||
})
|
||||
case SortTasksByPriorityAsc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].Priority < tasks[j].Priority
|
||||
})
|
||||
case SortTasksByDueDateDesc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].DueDateUnix > tasks[j].DueDateUnix
|
||||
})
|
||||
case SortTasksByDueDateAsc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].DueDateUnix < tasks[j].DueDateUnix
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func TestTask_ReadAll(t *testing.T) {
|
||||
assert.NoError(t, db.LoadFixtures())
|
||||
|
||||
// Dummy users
|
||||
user1 := &User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
||||
}
|
||||
|
||||
type fields struct {
|
||||
ListID int64
|
||||
Sorting string
|
||||
StartDateSortUnix int64
|
||||
EndDateSortUnix int64
|
||||
Lists []*List
|
||||
CRUDable web.CRUDable
|
||||
Rights web.Rights
|
||||
}
|
||||
type args struct {
|
||||
search string
|
||||
a web.Auth
|
||||
page int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want interface{}
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "ReadAll Tasks normally",
|
||||
fields: fields{},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: sortTasksForTesting(SortTasksByUnsorted),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks sorted by priority (desc)",
|
||||
fields: fields{
|
||||
Sorting: "priority",
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: sortTasksForTesting(SortTasksByPriorityDesc),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks sorted by priority asc",
|
||||
fields: fields{
|
||||
Sorting: "priorityasc",
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: sortTasksForTesting(SortTasksByPriorityAsc),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks sorted by priority desc",
|
||||
fields: fields{
|
||||
Sorting: "prioritydesc",
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: sortTasksForTesting(SortTasksByPriorityDesc),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks sorted by due date default desc",
|
||||
fields: fields{
|
||||
Sorting: "duedate",
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: sortTasksForTesting(SortTasksByDueDateDesc),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks sorted by due date asc",
|
||||
fields: fields{
|
||||
Sorting: "duedateasc",
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: sortTasksForTesting(SortTasksByDueDateAsc),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks sorted by due date desc",
|
||||
fields: fields{
|
||||
Sorting: "duedatedesc",
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
|
||||
want: sortTasksForTesting(SortTasksByDueDateDesc),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks with range",
|
||||
fields: fields{
|
||||
StartDateSortUnix: 1544500000,
|
||||
EndDateSortUnix: 1544600000,
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
{
|
||||
ID: 7,
|
||||
Text: "task #7 with start date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
},
|
||||
{
|
||||
ID: 9,
|
||||
Text: "task #9 with start and end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks with range",
|
||||
fields: fields{
|
||||
StartDateSortUnix: 1544700000,
|
||||
EndDateSortUnix: 1545000000,
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
{
|
||||
ID: 8,
|
||||
Text: "task #8 with end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
{
|
||||
ID: 9,
|
||||
Text: "task #9 with start and end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ReadAll Tasks with range without end date",
|
||||
fields: fields{
|
||||
StartDateSortUnix: 1544700000,
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
{
|
||||
ID: 8,
|
||||
Text: "task #8 with end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
{
|
||||
ID: 9,
|
||||
Text: "task #9 with start and end date",
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
RelatedTasks: map[RelationKind][]*Task{},
|
||||
Created: 1543626724,
|
||||
Updated: 1543626724,
|
||||
StartDateUnix: 1544600000,
|
||||
EndDateUnix: 1544700000,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
lt := &TaskCollection{
|
||||
ListID: tt.fields.ListID,
|
||||
Sorting: tt.fields.Sorting,
|
||||
StartDateSortUnix: tt.fields.StartDateSortUnix,
|
||||
EndDateSortUnix: tt.fields.EndDateSortUnix,
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
got, _, _, err := lt.ReadAll(tt.args.a, tt.args.search, tt.args.page, 50)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Test %s, Task.ReadAll() error = %v, wantErr %v", tt.name, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if diff, equal := messagediff.PrettyDiff(got, tt.want); !equal {
|
||||
t.Errorf("Test %s, LabelTask.ReadAll() = %v, want %v, \ndiff: %v", tt.name, got, tt.want, diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -105,25 +105,13 @@ func (TaskReminder) TableName() string {
|
|||
return "task_reminders"
|
||||
}
|
||||
|
||||
// SortBy declares constants to sort
|
||||
type SortBy int
|
||||
|
||||
// These are possible sort options
|
||||
const (
|
||||
SortTasksByUnsorted SortBy = -1
|
||||
SortTasksByDueDateAsc = iota
|
||||
SortTasksByDueDateDesc
|
||||
SortTasksByPriorityAsc
|
||||
SortTasksByPriorityDesc
|
||||
)
|
||||
|
||||
type taskOptions struct {
|
||||
search string
|
||||
sortby SortBy
|
||||
startDate time.Time
|
||||
endDate time.Time
|
||||
page int
|
||||
perPage int
|
||||
sortby []*sortParam
|
||||
}
|
||||
|
||||
// ReadAll is a dummy function to still have that endpoint documented
|
||||
|
@ -154,16 +142,19 @@ func getRawTasksForLists(lists []*List, opts *taskOptions) (taskMap map[int64]*T
|
|||
listIDs = append(listIDs, l.ID)
|
||||
}
|
||||
|
||||
// Since xorm does not use placeholders for order by, it is possible to expose this with sql injection if we're directly
|
||||
// passing user input to the db.
|
||||
// As a workaround to prevent this, we check for valid column names here prior to passing it to the db.
|
||||
var orderby string
|
||||
switch opts.sortby {
|
||||
case SortTasksByPriorityDesc:
|
||||
orderby = "priority desc"
|
||||
case SortTasksByPriorityAsc:
|
||||
orderby = "priority asc"
|
||||
case SortTasksByDueDateDesc:
|
||||
orderby = "due_date_unix desc"
|
||||
case SortTasksByDueDateAsc:
|
||||
orderby = "due_date_unix asc"
|
||||
for i, param := range opts.sortby {
|
||||
// Validate the params
|
||||
if err := param.validate(); err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
orderby += param.sortBy.String() + " " + param.orderBy.String()
|
||||
if (i + 1) < len(opts.sortby) {
|
||||
orderby += ", "
|
||||
}
|
||||
}
|
||||
|
||||
taskMap = make(map[int64]*Task)
|
||||
|
@ -232,34 +223,13 @@ func getTasksForLists(lists []*List, opts *taskOptions) (tasks []*Task, resultCo
|
|||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
// Because the list is sorted by id which we don't want (since we're dealing with maps)
|
||||
// Because the list is fully unsorted (since we're dealing with maps)
|
||||
// we have to manually sort the tasks again here.
|
||||
sortTasks(tasks, opts.sortby)
|
||||
|
||||
return tasks, resultCount, totalItems, err
|
||||
}
|
||||
|
||||
func sortTasks(tasks []*Task, by SortBy) {
|
||||
switch by {
|
||||
case SortTasksByPriorityDesc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].Priority > tasks[j].Priority
|
||||
})
|
||||
case SortTasksByPriorityAsc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].Priority < tasks[j].Priority
|
||||
})
|
||||
case SortTasksByDueDateDesc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].DueDateUnix > tasks[j].DueDateUnix
|
||||
})
|
||||
case SortTasksByDueDateAsc:
|
||||
sort.Slice(tasks, func(i, j int) bool {
|
||||
return tasks[i].DueDateUnix < tasks[j].DueDateUnix
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// GetTasksByListID gets all todotasks for a list
|
||||
func GetTasksByListID(listID int64) (tasks []*Task, err error) {
|
||||
// make a map so we can put in a lot of other stuff more easily
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag at
|
||||
// 2019-12-01 13:20:36.822585642 +0100 CET m=+0.129079038
|
||||
// 2019-12-05 22:15:49.761451764 +0100 CET m=+0.171539379
|
||||
|
||||
package swagger
|
||||
|
||||
|
@ -407,7 +407,7 @@ var doc = `{
|
|||
"JWTKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Returns a list by its ID.",
|
||||
"description": "Returns a team by its ID.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -415,13 +415,13 @@ var doc = `{
|
|||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"list"
|
||||
"team"
|
||||
],
|
||||
"summary": "Gets one list",
|
||||
"summary": "Gets one team",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "List ID",
|
||||
"description": "Team ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
|
@ -429,13 +429,13 @@ var doc = `{
|
|||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The list",
|
||||
"description": "The team",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.List"
|
||||
"$ref": "#/definitions/models.Team"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "The user does not have access to the list",
|
||||
"description": "The user does not have access to the team",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.vikunja.io.web.HTTPError"
|
||||
}
|
||||
|
@ -984,7 +984,7 @@ var doc = `{
|
|||
"tags": [
|
||||
"task"
|
||||
],
|
||||
"summary": "Get tasks on a list",
|
||||
"summary": "Get tasks in a list",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
@ -1013,8 +1013,14 @@ var doc = `{
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The sorting parameter. Possible values to sort by are priority, prioritydesc, priorityasc, duedate, duedatedesc, duedateasc.",
|
||||
"name": "sort",
|
||||
"description": "The sorting parameter. You can pass this multiple times to get the tasks ordered by multiple different parametes, along with ` + "`" + `order_by` + "`" + `. Possible values to sort by are ` + "`" + `id` + "`" + `, ` + "`" + `text` + "`" + `, ` + "`" + `description` + "`" + `, ` + "`" + `done` + "`" + `, ` + "`" + `done_at_unix` + "`" + `, ` + "`" + `due_date_unix` + "`" + `, ` + "`" + `created_by_id` + "`" + `, ` + "`" + `list_id` + "`" + `, ` + "`" + `repeat_after` + "`" + `, ` + "`" + `priority` + "`" + `, ` + "`" + `start_date_unix` + "`" + `, ` + "`" + `end_date_unix` + "`" + `, ` + "`" + `hex_color` + "`" + `, ` + "`" + `percent_done` + "`" + `, ` + "`" + `uid` + "`" + `, ` + "`" + `created` + "`" + `, ` + "`" + `updated` + "`" + `. Default is ` + "`" + `id` + "`" + `.",
|
||||
"name": "sort_by",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The ordering parameter. Possible values to order by are ` + "`" + `asc` + "`" + ` or ` + "`" + `desc` + "`" + `. Default is ` + "`" + `asc` + "`" + `.",
|
||||
"name": "order_by",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
|
@ -4633,13 +4639,6 @@ var doc = `{
|
|||
"type": "object",
|
||||
"$ref": "#/definitions/models.User"
|
||||
},
|
||||
"tasks": {
|
||||
"description": "An array of tasks which belong to the list.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.Task"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the list. You'll see this in the namespace overview.",
|
||||
"type": "string",
|
||||
|
|
|
@ -389,7 +389,7 @@
|
|||
"JWTKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Returns a list by its ID.",
|
||||
"description": "Returns a team by its ID.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
@ -397,13 +397,13 @@
|
|||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"list"
|
||||
"team"
|
||||
],
|
||||
"summary": "Gets one list",
|
||||
"summary": "Gets one team",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "List ID",
|
||||
"description": "Team ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
|
@ -411,13 +411,13 @@
|
|||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The list",
|
||||
"description": "The team",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.List"
|
||||
"$ref": "#/definitions/models.Team"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "The user does not have access to the list",
|
||||
"description": "The user does not have access to the team",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/code.vikunja.io/web.HTTPError"
|
||||
}
|
||||
|
@ -966,7 +966,7 @@
|
|||
"tags": [
|
||||
"task"
|
||||
],
|
||||
"summary": "Get tasks on a list",
|
||||
"summary": "Get tasks in a list",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
@ -995,8 +995,14 @@
|
|||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The sorting parameter. Possible values to sort by are priority, prioritydesc, priorityasc, duedate, duedatedesc, duedateasc.",
|
||||
"name": "sort",
|
||||
"description": "The sorting parameter. You can pass this multiple times to get the tasks ordered by multiple different parametes, along with `order_by`. Possible values to sort by are `id`, `text`, `description`, `done`, `done_at_unix`, `due_date_unix`, `created_by_id`, `list_id`, `repeat_after`, `priority`, `start_date_unix`, `end_date_unix`, `hex_color`, `percent_done`, `uid`, `created`, `updated`. Default is `id`.",
|
||||
"name": "sort_by",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The ordering parameter. Possible values to order by are `asc` or `desc`. Default is `asc`.",
|
||||
"name": "order_by",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
|
@ -4614,13 +4620,6 @@
|
|||
"type": "object",
|
||||
"$ref": "#/definitions/models.User"
|
||||
},
|
||||
"tasks": {
|
||||
"description": "An array of tasks which belong to the list.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/models.Task"
|
||||
}
|
||||
},
|
||||
"title": {
|
||||
"description": "The title of the list. You'll see this in the namespace overview.",
|
||||
"type": "string",
|
||||
|
|
|
@ -236,11 +236,6 @@ definitions:
|
|||
$ref: '#/definitions/models.User'
|
||||
description: The user who created this list.
|
||||
type: object
|
||||
tasks:
|
||||
description: An array of tasks which belong to the list.
|
||||
items:
|
||||
$ref: '#/definitions/models.Task'
|
||||
type: array
|
||||
title:
|
||||
description: The title of the list. You'll see this in the namespace overview.
|
||||
maxLength: 250
|
||||
|
@ -1138,9 +1133,9 @@ paths:
|
|||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Returns a list by its ID.
|
||||
description: Returns a team by its ID.
|
||||
parameters:
|
||||
- description: List ID
|
||||
- description: Team ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
|
@ -1149,11 +1144,11 @@ paths:
|
|||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: The list
|
||||
description: The team
|
||||
schema:
|
||||
$ref: '#/definitions/models.List'
|
||||
$ref: '#/definitions/models.Team'
|
||||
"403":
|
||||
description: The user does not have access to the list
|
||||
description: The user does not have access to the team
|
||||
schema:
|
||||
$ref: '#/definitions/code.vikunja.io/web.HTTPError'
|
||||
"500":
|
||||
|
@ -1162,9 +1157,9 @@ paths:
|
|||
$ref: '#/definitions/models.Message'
|
||||
security:
|
||||
- JWTKeyAuth: []
|
||||
summary: Gets one list
|
||||
summary: Gets one team
|
||||
tags:
|
||||
- list
|
||||
- team
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
|
@ -1667,10 +1662,19 @@ paths:
|
|||
in: query
|
||||
name: s
|
||||
type: string
|
||||
- description: The sorting parameter. Possible values to sort by are priority,
|
||||
prioritydesc, priorityasc, duedate, duedatedesc, duedateasc.
|
||||
- description: The sorting parameter. You can pass this multiple times to get
|
||||
the tasks ordered by multiple different parametes, along with `order_by`.
|
||||
Possible values to sort by are `id`, `text`, `description`, `done`, `done_at_unix`,
|
||||
`due_date_unix`, `created_by_id`, `list_id`, `repeat_after`, `priority`,
|
||||
`start_date_unix`, `end_date_unix`, `hex_color`, `percent_done`, `uid`,
|
||||
`created`, `updated`. Default is `id`.
|
||||
in: query
|
||||
name: sort
|
||||
name: sort_by
|
||||
type: string
|
||||
- description: The ordering parameter. Possible values to order by are `asc`
|
||||
or `desc`. Default is `asc`.
|
||||
in: query
|
||||
name: order_by
|
||||
type: string
|
||||
- description: The start date parameter to filter by. Expects a unix timestamp.
|
||||
If no end date, but a start date is specified, the end date is set to the
|
||||
|
@ -1699,7 +1703,7 @@ paths:
|
|||
$ref: '#/definitions/models.Message'
|
||||
security:
|
||||
- JWTKeyAuth: []
|
||||
summary: Get tasks on a list
|
||||
summary: Get tasks in a list
|
||||
tags:
|
||||
- task
|
||||
/lists/{listID}/teams/{teamID}:
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*~
|
||||
*.out
|
||||
*.log
|
|
@ -0,0 +1,11 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
script:
|
||||
- go test ./...
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Joel
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,8 @@
|
|||
deepCopy
|
||||
========
|
||||
[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy)
|
||||
|
||||
DeepCopy makes deep copies of things: unexported field values are not copied.
|
||||
|
||||
## Usage
|
||||
cpy := deepcopy.Copy(orig)
|
|
@ -0,0 +1,125 @@
|
|||
// deepcopy makes deep copies of things. A standard copy will copy the
|
||||
// pointers: deep copy copies the values pointed to. Unexported field
|
||||
// values are not copied.
|
||||
//
|
||||
// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved.
|
||||
// License: MIT, for more details check the included LICENSE file.
|
||||
package deepcopy
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Interface for delegating copy process to type
|
||||
type Interface interface {
|
||||
DeepCopy() interface{}
|
||||
}
|
||||
|
||||
// Iface is an alias to Copy; this exists for backwards compatibility reasons.
|
||||
func Iface(iface interface{}) interface{} {
|
||||
return Copy(iface)
|
||||
}
|
||||
|
||||
// Copy creates a deep copy of whatever is passed to it and returns the copy
|
||||
// in an interface{}. The returned value will need to be asserted to the
|
||||
// correct type.
|
||||
func Copy(src interface{}) interface{} {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Make the interface a reflect.Value
|
||||
original := reflect.ValueOf(src)
|
||||
|
||||
// Make a copy of the same type as the original.
|
||||
cpy := reflect.New(original.Type()).Elem()
|
||||
|
||||
// Recursively copy the original.
|
||||
copyRecursive(original, cpy)
|
||||
|
||||
// Return the copy as an interface.
|
||||
return cpy.Interface()
|
||||
}
|
||||
|
||||
// copyRecursive does the actual copying of the interface. It currently has
|
||||
// limited support for what it can handle. Add as needed.
|
||||
func copyRecursive(original, cpy reflect.Value) {
|
||||
// check for implement deepcopy.Interface
|
||||
if original.CanInterface() {
|
||||
if copier, ok := original.Interface().(Interface); ok {
|
||||
cpy.Set(reflect.ValueOf(copier.DeepCopy()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handle according to original's Kind
|
||||
switch original.Kind() {
|
||||
case reflect.Ptr:
|
||||
// Get the actual value being pointed to.
|
||||
originalValue := original.Elem()
|
||||
|
||||
// if it isn't valid, return.
|
||||
if !originalValue.IsValid() {
|
||||
return
|
||||
}
|
||||
cpy.Set(reflect.New(originalValue.Type()))
|
||||
copyRecursive(originalValue, cpy.Elem())
|
||||
|
||||
case reflect.Interface:
|
||||
// If this is a nil, don't do anything
|
||||
if original.IsNil() {
|
||||
return
|
||||
}
|
||||
// Get the value for the interface, not the pointer.
|
||||
originalValue := original.Elem()
|
||||
|
||||
// Get the value by calling Elem().
|
||||
copyValue := reflect.New(originalValue.Type()).Elem()
|
||||
copyRecursive(originalValue, copyValue)
|
||||
cpy.Set(copyValue)
|
||||
|
||||
case reflect.Struct:
|
||||
t, ok := original.Interface().(time.Time)
|
||||
if ok {
|
||||
cpy.Set(reflect.ValueOf(t))
|
||||
return
|
||||
}
|
||||
// Go through each field of the struct and copy it.
|
||||
for i := 0; i < original.NumField(); i++ {
|
||||
// The Type's StructField for a given field is checked to see if StructField.PkgPath
|
||||
// is set to determine if the field is exported or not because CanSet() returns false
|
||||
// for settable fields. I'm not sure why. -mohae
|
||||
if original.Type().Field(i).PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
copyRecursive(original.Field(i), cpy.Field(i))
|
||||
}
|
||||
|
||||
case reflect.Slice:
|
||||
if original.IsNil() {
|
||||
return
|
||||
}
|
||||
// Make a new slice and copy each element.
|
||||
cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
|
||||
for i := 0; i < original.Len(); i++ {
|
||||
copyRecursive(original.Index(i), cpy.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
if original.IsNil() {
|
||||
return
|
||||
}
|
||||
cpy.Set(reflect.MakeMap(original.Type()))
|
||||
for _, key := range original.MapKeys() {
|
||||
originalValue := original.MapIndex(key)
|
||||
copyValue := reflect.New(originalValue.Type()).Elem()
|
||||
copyRecursive(originalValue, copyValue)
|
||||
copyKey := Copy(key.Interface())
|
||||
cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
|
||||
}
|
||||
|
||||
default:
|
||||
cpy.Set(original)
|
||||
}
|
||||
}
|
|
@ -1,3 +1 @@
|
|||
module github.com/prometheus/procfs
|
||||
|
||||
go 1.12
|
||||
|
|
|
@ -114,6 +114,8 @@ github.com/mattn/go-sqlite3
|
|||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||
# github.com/mitchellh/mapstructure v1.1.2
|
||||
github.com/mitchellh/mapstructure
|
||||
# github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/mohae/deepcopy
|
||||
# github.com/olekukonko/tablewriter v0.0.1
|
||||
github.com/olekukonko/tablewriter
|
||||
# github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
|
|
Loading…
Reference in New Issue
Any special resons why this is a bool? I know there can only be two types of sort orders, but a bool here is IMHO a bit overkill since bool has nothing to do with sort order.
What would you use instead? Note how it's not aliased but typed, i.e. you can not accidentally convert one to the other.
Makes sense, thanks for clarifying.