forked from vikunja/vikunja
Improve pagination (#105)
This commit is contained in:
parent
89f385a53d
commit
8948a5f219
@ -11,8 +11,8 @@ service:
|
||||
# Vikunja will also look in this path for a config file, so you could provide only this variable to point to a folder
|
||||
# with a config file which will then be used.
|
||||
rootpath: <rootpath>
|
||||
# The number of items which gets returned per page
|
||||
pagecount: 50
|
||||
# The max number of items which can be returned per page
|
||||
maxitemsperpage: 50
|
||||
# If set to true, enables a /metrics endpoint for prometheus to collect metrics about the system
|
||||
# You'll need to use redis for this in order to enable common metrics over multiple nodes
|
||||
enablemetrics: false
|
||||
|
@ -27,7 +27,7 @@ You can feed this function directly into xorm's `Limit`-Function like so:
|
||||
|
||||
{{< highlight golang >}}
|
||||
lists := []List{}
|
||||
err := x.Limit(getLimitFromPageIndex(pageIndex)).Find(&lists)
|
||||
err := x.Limit(getLimitFromPageIndex(pageIndex, itemsPerPage)).Find(&lists)
|
||||
{{< /highlight >}}
|
||||
|
||||
// TODO: Add a full example from start to finish, like a tutorial on how to create a new endpoint?
|
||||
|
@ -54,8 +54,8 @@ service:
|
||||
# Vikunja will also look in this path for a config file, so you could provide only this variable to point to a folder
|
||||
# with a config file which will then be used.
|
||||
rootpath: <the path of the executable>
|
||||
# The number of items which gets returned per page
|
||||
pagecount: 50
|
||||
# The max number of items which can be returned per page
|
||||
maxitemsperpage: 50
|
||||
# If set to true, enables a /metrics endpoint for prometheus to collect metrics about the system
|
||||
# You'll need to use redis for this in order to enable common metrics over multiple nodes
|
||||
enablemetrics: false
|
||||
|
14
go.mod
14
go.mod
@ -18,7 +18,7 @@ module code.vikunja.io/api
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.34.0 // indirect
|
||||
code.vikunja.io/web v0.0.0-20190628075253-b457b5a1a332
|
||||
code.vikunja.io/web v0.0.0-20191023202526-f337750c3573
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
|
||||
github.com/beevik/etree v1.1.0 // indirect
|
||||
@ -46,10 +46,11 @@ require (
|
||||
github.com/jgautheron/goconst v0.0.0-20170703170152-9740945f5dcb
|
||||
github.com/json-iterator/go v1.1.7 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
github.com/labstack/echo/v4 v4.1.7-0.20190627175217-8fb7b5be270f
|
||||
github.com/labstack/gommon v0.2.9
|
||||
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/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
|
||||
@ -73,12 +74,13 @@ require (
|
||||
github.com/ugorji/go v1.1.7 // indirect
|
||||
github.com/ulule/limiter/v3 v3.3.0
|
||||
github.com/urfave/cli v1.22.1 // indirect
|
||||
github.com/valyala/fasttemplate v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422
|
||||
golang.org/x/net v0.0.0-20191011234655-491137f69257 // indirect
|
||||
golang.org/x/net v0.0.0-20191021144547-ec77196f6094 // indirect
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a // indirect
|
||||
golang.org/x/sys v0.0.0-20191023151326-f89234f9a2c2 // indirect
|
||||
golang.org/x/tools v0.0.0-20191023202404-2b779830f9d3 // 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
|
||||
|
41
go.sum
41
go.sum
@ -7,6 +7,20 @@ code.vikunja.io/web v0.0.0-20190628071027-b5c16e24b0a7 h1:P9ncMaJE7RbYqBXF9lwT0h
|
||||
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=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
@ -170,10 +184,14 @@ github.com/labstack/echo/v4 v4.1.6 h1:WOvLa4T1KzWCRpANwz0HGgWDelXSSGwIKtKBbFdHTv
|
||||
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/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
@ -193,6 +211,8 @@ github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0X
|
||||
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=
|
||||
@ -200,6 +220,7 @@ 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=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-oci8 v0.0.0-20181115070430-6eefff3c767c/go.mod h1:/M9VLO+lUPmxvoOK2PfWRZ8mTtB4q1Hy9lEGijv9Nr8=
|
||||
@ -312,6 +333,8 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
|
||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
@ -326,6 +349,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||
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/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI=
|
||||
@ -352,6 +376,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
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/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -375,9 +401,16 @@ golang.org/x/sys v0.0.0-20190621203818-d432491b9138 h1:t8BZD9RDjkm9/h7yYN6kE8oae
|
||||
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/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@ -396,6 +429,14 @@ golang.org/x/tools v0.0.0-20190628034336-212fb13d595e h1:ZlQjfVdpDxeqxRfmO30CdqW
|
||||
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/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=
|
||||
|
@ -38,7 +38,7 @@ const (
|
||||
ServiceFrontendurl Key = `service.frontendurl`
|
||||
ServiceEnableCaldav Key = `service.enablecaldav`
|
||||
ServiceRootpath Key = `service.rootpath`
|
||||
ServicePageCount Key = `service.pagecount`
|
||||
ServiceMaxItemsPerPage Key = `service.maxitemsperpage`
|
||||
ServiceEnableMetrics Key = `service.enablemetrics`
|
||||
ServiceMotd Key = `service.motd`
|
||||
ServiceEnableLinkSharing Key = `service.enablelinksharing`
|
||||
@ -146,7 +146,7 @@ func InitDefaultConfig() {
|
||||
}
|
||||
exPath := filepath.Dir(ex)
|
||||
ServiceRootpath.setDefault(exPath)
|
||||
ServicePageCount.setDefault(50)
|
||||
ServiceMaxItemsPerPage.setDefault(50)
|
||||
ServiceEnableMetrics.setDefault(false)
|
||||
ServiceMotd.setDefault("")
|
||||
ServiceEnableLinkSharing.setDefault(true)
|
||||
|
@ -124,15 +124,16 @@ func (l *Label) Delete() (err error) {
|
||||
// @tags labels
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 labels by label text."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.Label "The labels"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels [get]
|
||||
func (l *Label) ReadAll(search string, a web.Auth, page int) (ls interface{}, err error) {
|
||||
func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls interface{}, resultCount int, numberOfEntries int64, err error) {
|
||||
if _, is := a.(*LinkSharing); is {
|
||||
return nil, ErrGenericForbidden{}
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
u := &User{ID: a.GetID()}
|
||||
@ -140,13 +141,15 @@ func (l *Label) ReadAll(search string, a web.Auth, page int) (ls interface{}, er
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||
Search: search,
|
||||
User: u,
|
||||
TaskIDs: taskIDs,
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
GetUnusedLabels: true,
|
||||
GroupByLabelIDsOnly: true,
|
||||
})
|
||||
@ -198,15 +201,17 @@ func getLabelByIDSimple(labelID int64) (*Label, error) {
|
||||
func getUserTaskIDs(u *User) (taskIDs []int64, err error) {
|
||||
|
||||
// Get all lists
|
||||
lists, err := getRawListsForUser("", u, -1)
|
||||
lists, _, _, err := getRawListsForUser("", u, -1, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tasks, err := getRawTasksForLists(lists, &taskOptions{
|
||||
tasks, _, _, err := getRawTasksForLists(lists, &taskOptions{
|
||||
startDate: time.Unix(0, 0),
|
||||
endDate: time.Unix(0, 0),
|
||||
sortby: SortTasksByUnsorted,
|
||||
page: -1,
|
||||
perPage: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -101,21 +101,22 @@ func (lt *LabelTask) Create(a web.Auth) (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param task path int true "Task ID"
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 labels by label text."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.Label "The labels"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{task}/labels [get]
|
||||
func (lt *LabelTask) ReadAll(search string, a web.Auth, page int) (labels interface{}, err error) {
|
||||
func (lt *LabelTask) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
// Check if the user has the right to see the task
|
||||
task := Task{ID: lt.TaskID}
|
||||
canRead, err := task.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !canRead {
|
||||
return nil, ErrNoRightToSeeTask{lt.TaskID, a.GetID()}
|
||||
return nil, 0, 0, ErrNoRightToSeeTask{lt.TaskID, a.GetID()}
|
||||
}
|
||||
|
||||
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||
@ -137,6 +138,7 @@ type LabelByTaskIDsOptions struct {
|
||||
User *User
|
||||
Search string
|
||||
Page int
|
||||
PerPage int
|
||||
TaskIDs []int64
|
||||
GetUnusedLabels bool
|
||||
GroupByLabelIDsOnly bool
|
||||
@ -144,7 +146,7 @@ type LabelByTaskIDsOptions struct {
|
||||
|
||||
// Helper function to get all labels for a set of tasks
|
||||
// Used when getting all labels for one task as well when getting all lables
|
||||
func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, err error) {
|
||||
func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, resultCount int, totalEntries int64, err error) {
|
||||
// Include unused labels. Needed to be able to show a list of all unused labels a user
|
||||
// has access to.
|
||||
var uidOrNil interface{}
|
||||
@ -172,10 +174,10 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, err
|
||||
Or(builder.In("label_task.task_id", opts.TaskIDs)).
|
||||
And("labels.title LIKE ?", "%"+opts.Search+"%").
|
||||
GroupBy(groupBy).
|
||||
Limit(getLimitFromPageIndex(opts.Page)).
|
||||
Limit(getLimitFromPageIndex(opts.Page, opts.PerPage)).
|
||||
Find(&labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Get all created by users
|
||||
@ -186,7 +188,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, err
|
||||
users := make(map[int64]*User)
|
||||
err = x.In("id", userids).Find(&users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Obfuscate all user emails
|
||||
@ -199,7 +201,19 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, err
|
||||
labels[in].CreatedBy = users[l.CreatedByID]
|
||||
}
|
||||
|
||||
return labels, err
|
||||
// Get the total number of entries
|
||||
totalEntries, err = x.Table("labels").
|
||||
Join("LEFT", "label_task", "label_task.label_id = labels.id").
|
||||
Where(requestOrNil, uidOrNil).
|
||||
Or(builder.In("label_task.task_id", opts.TaskIDs)).
|
||||
And("labels.title LIKE ?", "%"+opts.Search+"%").
|
||||
GroupBy(groupBy).
|
||||
Count(&Label{})
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return labels, len(labels), totalEntries, err
|
||||
}
|
||||
|
||||
// Create or update a bunch of task labels
|
||||
|
@ -89,7 +89,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
gotLabels, err := l.ReadAll(tt.args.search, tt.args.a, tt.args.page)
|
||||
gotLabels, _, _, err := l.ReadAll(tt.args.a, tt.args.search, tt.args.page, 0)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("LabelTask.ReadAll() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -117,7 +117,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
gotLs, err := l.ReadAll(tt.args.search, tt.args.a, tt.args.page)
|
||||
gotLs, _, _, err := l.ReadAll(tt.args.a, tt.args.search, tt.args.page, 0)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Label.ReadAll() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -136,29 +136,30 @@ func (share *LinkSharing) ReadOne() (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param list path int true "List ID"
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 shares by hash."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.LinkSharing "The share links"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{list}/shares [get]
|
||||
func (share *LinkSharing) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (share *LinkSharing) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, totalItems int64, err error) {
|
||||
list := &List{ID: share.ListID}
|
||||
can, err := list.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !can {
|
||||
return nil, ErrGenericForbidden{}
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
var shares []*LinkSharing
|
||||
err = x.
|
||||
Where("list_id = ? AND hash LIKE ?", share.ListID, "%"+search+"%").
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Find(&shares)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Find all users and add them
|
||||
@ -170,14 +171,22 @@ func (share *LinkSharing) ReadAll(search string, a web.Auth, page int) (interfac
|
||||
users := make(map[int64]*User)
|
||||
err = x.In("id", userIDs).Find(&users)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
for _, s := range shares {
|
||||
s.SharedBy = users[s.SharedByID]
|
||||
}
|
||||
|
||||
return shares, err
|
||||
// Total count
|
||||
totalItems, err = x.
|
||||
Where("list_id = ? AND hash LIKE ?", share.ListID, "%"+search+"%").
|
||||
Count(&LinkSharing{})
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return shares, len(shares), totalItems, err
|
||||
}
|
||||
|
||||
// Delete removes a link share
|
||||
|
@ -77,35 +77,36 @@ func GetListsByNamespaceID(nID int64, doer *User) (lists []*List, err error) {
|
||||
// @tags list
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 lists by title."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.List "The lists"
|
||||
// @Failure 403 {object} code.vikunja.io/web.HTTPError "The user does not have access to the list"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists [get]
|
||||
func (l *List) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, totalItems int64, err error) {
|
||||
// Check if we're dealing with a share auth
|
||||
shareAuth, ok := a.(*LinkSharing)
|
||||
if ok {
|
||||
list := &List{ID: shareAuth.ListID}
|
||||
err := list.GetSimpleByID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
lists := []*List{list}
|
||||
err = AddListDetails(lists)
|
||||
return lists, err
|
||||
return lists, 0, 0, err
|
||||
}
|
||||
|
||||
lists, err := getRawListsForUser(search, &User{ID: a.GetID()}, page)
|
||||
lists, resultCount, totalItems, err := getRawListsForUser(search, &User{ID: a.GetID()}, page, perPage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Add more list details
|
||||
err = AddListDetails(lists)
|
||||
return lists, err
|
||||
return lists, resultCount, totalItems, err
|
||||
}
|
||||
|
||||
// ReadOne gets one list by its ID
|
||||
@ -177,10 +178,10 @@ func GetListSimplByTaskID(taskID int64) (l *List, err error) {
|
||||
}
|
||||
|
||||
// Gets the lists only, without any tasks or so
|
||||
func getRawListsForUser(search string, u *User, page int) (lists []*List, err error) {
|
||||
func getRawListsForUser(search string, u *User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
||||
fullUser, err := GetUserByID(u.ID)
|
||||
if err != nil {
|
||||
return lists, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Gets all Lists where the user is either owner or in a team which has access to the list
|
||||
@ -201,11 +202,33 @@ func getRawListsForUser(search string, u *User, page int) (lists []*List, err er
|
||||
Or("ul.user_id = ?", fullUser.ID).
|
||||
Or("un.user_id = ?", fullUser.ID).
|
||||
GroupBy("l.id").
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("l.title LIKE ?", "%"+search+"%").
|
||||
Find(&lists)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return lists, err
|
||||
totalItems, err = x.
|
||||
Table("list").
|
||||
Alias("l").
|
||||
Join("INNER", []string{"namespaces", "n"}, "l.namespace_id = n.id").
|
||||
Join("LEFT", []string{"team_namespaces", "tn"}, "tn.namespace_id = n.id").
|
||||
Join("LEFT", []string{"team_members", "tm"}, "tm.team_id = tn.team_id").
|
||||
Join("LEFT", []string{"team_list", "tl"}, "l.id = tl.list_id").
|
||||
Join("LEFT", []string{"team_members", "tm2"}, "tm2.team_id = tl.team_id").
|
||||
Join("LEFT", []string{"users_list", "ul"}, "ul.list_id = l.id").
|
||||
Join("LEFT", []string{"users_namespace", "un"}, "un.namespace_id = l.namespace_id").
|
||||
Where("tm.user_id = ?", fullUser.ID).
|
||||
Or("tm2.user_id = ?", fullUser.ID).
|
||||
Or("l.owner_id = ?", fullUser.ID).
|
||||
Or("ul.user_id = ?", fullUser.ID).
|
||||
Or("un.user_id = ?", fullUser.ID).
|
||||
GroupBy("l.id").
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("l.title LIKE ?", "%"+search+"%").
|
||||
Count(&List{})
|
||||
return lists, len(lists), totalItems, err
|
||||
}
|
||||
|
||||
// AddListDetails adds owner user objects and list tasks to all lists in the slice
|
||||
|
@ -36,14 +36,15 @@ func TestList_ReadAll(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
lists2 := List{}
|
||||
lists3, err := lists2.ReadAll("", u, 1)
|
||||
lists3, _, _, err := lists2.ReadAll(u, "", 1, 50)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, reflect.TypeOf(lists3).Kind(), reflect.Slice)
|
||||
s := reflect.ValueOf(lists3)
|
||||
assert.Equal(t, 16, s.Len())
|
||||
|
||||
// Try getting lists for a nonexistant user
|
||||
_, err = lists2.ReadAll("", &User{ID: 984234}, 1)
|
||||
_, _, _, err = lists2.ReadAll(&User{ID: 984234}, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
}
|
||||
|
@ -154,22 +154,23 @@ func (tl *TeamList) Delete() (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "List ID"
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 teams by its name."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.TeamWithRight "The teams with their right."
|
||||
// @Failure 403 {object} code.vikunja.io/web.HTTPError "No right to see the list."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{id}/teams [get]
|
||||
func (tl *TeamList) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (tl *TeamList) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, totalItems int64, err error) {
|
||||
// Check if the user can read the namespace
|
||||
l := &List{ID: tl.ListID}
|
||||
canRead, err := l.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !canRead {
|
||||
return nil, ErrNeedToHaveListReadAccess{ListID: tl.ListID, UserID: a.GetID()}
|
||||
return nil, 0, 0, ErrNeedToHaveListReadAccess{ListID: tl.ListID, UserID: a.GetID()}
|
||||
}
|
||||
|
||||
// Get the teams
|
||||
@ -178,11 +179,24 @@ func (tl *TeamList) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
Table("teams").
|
||||
Join("INNER", "team_list", "team_id = teams.id").
|
||||
Where("team_list.list_id = ?", tl.ListID).
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("teams.name LIKE ?", "%"+search+"%").
|
||||
Find(&all)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return all, err
|
||||
totalItems, err = x.
|
||||
Table("teams").
|
||||
Join("INNER", "team_list", "team_id = teams.id").
|
||||
Where("team_list.list_id = ?", tl.ListID).
|
||||
Where("teams.name LIKE ?", "%"+search+"%").
|
||||
Count(&TeamWithRight{})
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return all, len(all), totalItems, err
|
||||
}
|
||||
|
||||
// Update updates a team <-> list relation
|
||||
|
@ -69,27 +69,27 @@ func TestTeamList(t *testing.T) {
|
||||
assert.True(t, IsErrListDoesNotExist(err))
|
||||
|
||||
// Test Read all
|
||||
teams, err := tl.ReadAll("", u, 1)
|
||||
teams, _, _, err := tl.ReadAll(u, "", 1, 50)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, reflect.TypeOf(teams).Kind(), reflect.Slice)
|
||||
s := reflect.ValueOf(teams)
|
||||
assert.Equal(t, s.Len(), 1)
|
||||
|
||||
// Test Read all for nonexistant list
|
||||
_, err = tl4.ReadAll("", u, 1)
|
||||
_, _, _, err = tl4.ReadAll(u, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrListDoesNotExist(err))
|
||||
|
||||
// Test Read all for a list where the user is owner of the namespace this list belongs to
|
||||
tl5 := tl
|
||||
tl5.ListID = 2
|
||||
_, err = tl5.ReadAll("", u, 1)
|
||||
_, _, _, err = tl5.ReadAll(u, "", 1, 50)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test read all for a list where the user not has access
|
||||
tl6 := tl
|
||||
tl6.ListID = 5
|
||||
_, err = tl6.ReadAll("", u, 1)
|
||||
_, _, _, err = tl6.ReadAll(u, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNeedToHaveListReadAccess(err))
|
||||
|
||||
|
@ -159,22 +159,23 @@ func (lu *ListUser) Delete() (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "List ID"
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 users by its name."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.UserWithRight "The users with the right they have."
|
||||
// @Failure 403 {object} code.vikunja.io/web.HTTPError "No right to see the list."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{id}/users [get]
|
||||
func (lu *ListUser) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (lu *ListUser) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
// Check if the user has access to the list
|
||||
l := &List{ID: lu.ListID}
|
||||
canRead, err := l.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !canRead {
|
||||
return nil, ErrNeedToHaveListReadAccess{UserID: a.GetID(), ListID: lu.ListID}
|
||||
return nil, 0, 0, ErrNeedToHaveListReadAccess{UserID: a.GetID(), ListID: lu.ListID}
|
||||
}
|
||||
|
||||
// Get all users
|
||||
@ -182,16 +183,25 @@ func (lu *ListUser) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
err = x.
|
||||
Join("INNER", "users_list", "user_id = users.id").
|
||||
Where("users_list.list_id = ?", lu.ListID).
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("users.username LIKE ?", "%"+search+"%").
|
||||
Find(&all)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Obfuscate all user emails
|
||||
for _, u := range all {
|
||||
u.Email = ""
|
||||
}
|
||||
|
||||
return all, err
|
||||
numberOfTotalItems, err = x.
|
||||
Join("INNER", "users_list", "user_id = users.id").
|
||||
Where("users_list.list_id = ?", lu.ListID).
|
||||
Where("users.username LIKE ?", "%"+search+"%").
|
||||
Count(&UserWithRight{})
|
||||
|
||||
return all, len(all), numberOfTotalItems, err
|
||||
}
|
||||
|
||||
// Update updates a user <-> list relation
|
||||
|
@ -203,7 +203,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
got, err := ul.ReadAll(tt.args.search, tt.args.a, tt.args.page)
|
||||
got, _, _, err := ul.ReadAll(tt.args.a, tt.args.search, tt.args.page, 50)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ListUser.ReadAll() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
@ -69,14 +69,18 @@ func SetEngine() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getLimitFromPageIndex(page int) (limit, start int) {
|
||||
func getLimitFromPageIndex(page int, perPage int) (limit, start int) {
|
||||
|
||||
// Get everything when page index is -1
|
||||
if page < 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
limit = config.ServicePageCount.GetInt()
|
||||
limit = config.ServiceMaxItemsPerPage.GetInt()
|
||||
if perPage > 0 {
|
||||
limit = perPage
|
||||
}
|
||||
|
||||
start = limit * (page - 1)
|
||||
return
|
||||
}
|
||||
|
@ -131,20 +131,21 @@ type NamespaceWithLists struct {
|
||||
// @tags namespace
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 namespaces by name."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.NamespaceWithLists "The Namespaces."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /namespaces [get]
|
||||
func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
if _, is := a.(*LinkSharing); is {
|
||||
return nil, ErrGenericForbidden{}
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
doer, err := getUserWithError(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
all := []*NamespaceWithLists{}
|
||||
@ -167,11 +168,11 @@ func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
Or("namespaces.owner_id = ?", doer.ID).
|
||||
Or("users_namespace.user_id = ?", doer.ID).
|
||||
GroupBy("namespaces.id").
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("namespaces.name LIKE ?", "%"+search+"%").
|
||||
Find(&all)
|
||||
if err != nil {
|
||||
return all, err
|
||||
return all, 0, 0, err
|
||||
}
|
||||
|
||||
// Get all users
|
||||
@ -187,7 +188,7 @@ func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
Find(&users)
|
||||
|
||||
if err != nil {
|
||||
return all, err
|
||||
return all, 0, 0, err
|
||||
}
|
||||
|
||||
// Make a list of namespace ids
|
||||
@ -202,7 +203,7 @@ func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
In("namespace_id", namespaceids).
|
||||
Find(&lists)
|
||||
if err != nil {
|
||||
return all, err
|
||||
return all, 0, 0, err
|
||||
}
|
||||
|
||||
// Get all lists individually shared with our user (not via a namespace)
|
||||
@ -218,7 +219,7 @@ func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
GroupBy("l.id").
|
||||
Find(&individualLists)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Make the namespace -1 so we now later which one it was
|
||||
@ -234,9 +235,13 @@ func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
}
|
||||
|
||||
// More details for the lists
|
||||
AddListDetails(lists)
|
||||
err = AddListDetails(lists)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Put objects in our namespace list
|
||||
// TODO: Refactor this to use maps for better efficiency
|
||||
for i, n := range all {
|
||||
|
||||
// Users
|
||||
@ -255,7 +260,22 @@ func (n *Namespace) ReadAll(search string, a web.Auth, page int) (interface{}, e
|
||||
}
|
||||
}
|
||||
|
||||
return all, nil
|
||||
numberOfTotalItems, err = x.
|
||||
Table("namespaces").
|
||||
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
|
||||
Join("LEFT", "team_members", "team_members.team_id = team_namespaces.team_id").
|
||||
Join("LEFT", "users_namespace", "users_namespace.namespace_id = namespaces.id").
|
||||
Where("team_members.user_id = ?", doer.ID).
|
||||
Or("namespaces.owner_id = ?", doer.ID).
|
||||
Or("users_namespace.user_id = ?", doer.ID).
|
||||
GroupBy("namespaces.id").
|
||||
Where("namespaces.name LIKE ?", "%"+search+"%").
|
||||
Count(&NamespaceWithLists{})
|
||||
if err != nil {
|
||||
return all, 0, 0, err
|
||||
}
|
||||
|
||||
return all, len(all), numberOfTotalItems, nil
|
||||
}
|
||||
|
||||
// Create implements the creation method via the interface
|
||||
|
@ -139,22 +139,23 @@ func (tn *TeamNamespace) Delete() (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Namespace ID"
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 teams by its name."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.TeamWithRight "The teams with the right they have."
|
||||
// @Failure 403 {object} code.vikunja.io/web.HTTPError "No right to see the namespace."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /namespaces/{id}/teams [get]
|
||||
func (tn *TeamNamespace) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (tn *TeamNamespace) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
// Check if the user can read the namespace
|
||||
n := Namespace{ID: tn.NamespaceID}
|
||||
canRead, err := n.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !canRead {
|
||||
return nil, ErrNeedToHaveNamespaceReadAccess{NamespaceID: tn.NamespaceID, UserID: a.GetID()}
|
||||
return nil, 0, 0, ErrNeedToHaveNamespaceReadAccess{NamespaceID: tn.NamespaceID, UserID: a.GetID()}
|
||||
}
|
||||
|
||||
// Get the teams
|
||||
@ -163,11 +164,20 @@ func (tn *TeamNamespace) ReadAll(search string, a web.Auth, page int) (interface
|
||||
err = x.Table("teams").
|
||||
Join("INNER", "team_namespaces", "team_id = teams.id").
|
||||
Where("team_namespaces.namespace_id = ?", tn.NamespaceID).
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("teams.name LIKE ?", "%"+search+"%").
|
||||
Find(&all)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return all, err
|
||||
numberOfTotalItems, err = x.Table("teams").
|
||||
Join("INNER", "team_namespaces", "team_id = teams.id").
|
||||
Where("team_namespaces.namespace_id = ?", tn.NamespaceID).
|
||||
Where("teams.name LIKE ?", "%"+search+"%").
|
||||
Count(&TeamWithRight{})
|
||||
|
||||
return all, len(all), numberOfTotalItems, err
|
||||
}
|
||||
|
||||
// Update updates a team <-> namespace relation
|
||||
|
@ -68,20 +68,20 @@ func TestTeamNamespace(t *testing.T) {
|
||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
|
||||
// Check readall
|
||||
teams, err := tn.ReadAll("", dummyuser, 1)
|
||||
teams, _, _, err := tn.ReadAll(dummyuser, "", 1, 50)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, reflect.TypeOf(teams).Kind(), reflect.Slice)
|
||||
s := reflect.ValueOf(teams)
|
||||
assert.Equal(t, s.Len(), 1)
|
||||
|
||||
// Check readall for a nonexistant namespace
|
||||
_, err = tn4.ReadAll("", dummyuser, 1)
|
||||
_, _, _, err = tn4.ReadAll(dummyuser, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
|
||||
// Check with no right to read the namespace
|
||||
nouser := &User{ID: 393}
|
||||
_, err = tn.ReadAll("", nouser, 1)
|
||||
_, _, _, err = tn.ReadAll(nouser, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNeedToHaveNamespaceReadAccess(err))
|
||||
|
||||
|
@ -118,7 +118,7 @@ func TestNamespace_Create(t *testing.T) {
|
||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
|
||||
// Get all namespaces of a user
|
||||
nsps, err := n.ReadAll("", doer, 1)
|
||||
nsps, _, _, err := n.ReadAll(doer, "", 1, 50)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, reflect.TypeOf(nsps).Kind(), reflect.Slice)
|
||||
s := reflect.ValueOf(nsps)
|
||||
|
@ -145,22 +145,23 @@ func (nu *NamespaceUser) Delete() (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Namespace ID"
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 users by its name."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.UserWithRight "The users with the right they have."
|
||||
// @Failure 403 {object} code.vikunja.io/web.HTTPError "No right to see the namespace."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /namespaces/{id}/users [get]
|
||||
func (nu *NamespaceUser) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (nu *NamespaceUser) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
// Check if the user has access to the namespace
|
||||
l := Namespace{ID: nu.NamespaceID}
|
||||
canRead, err := l.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !canRead {
|
||||
return nil, ErrNeedToHaveNamespaceReadAccess{}
|
||||
return nil, 0, 0, ErrNeedToHaveNamespaceReadAccess{}
|
||||
}
|
||||
|
||||
// Get all users
|
||||
@ -168,16 +169,25 @@ func (nu *NamespaceUser) ReadAll(search string, a web.Auth, page int) (interface
|
||||
err = x.
|
||||
Join("INNER", "users_namespace", "user_id = users.id").
|
||||
Where("users_namespace.namespace_id = ?", nu.NamespaceID).
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("users.username LIKE ?", "%"+search+"%").
|
||||
Find(&all)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
// Obfuscate all user emails
|
||||
for _, u := range all {
|
||||
u.Email = ""
|
||||
}
|
||||
|
||||
return all, err
|
||||
numberOfTotalItems, err = x.
|
||||
Join("INNER", "users_namespace", "user_id = users.id").
|
||||
Where("users_namespace.namespace_id = ?", nu.NamespaceID).
|
||||
Where("users.username LIKE ?", "%"+search+"%").
|
||||
Count(&UserWithRight{})
|
||||
|
||||
return all, len(all), numberOfTotalItems, err
|
||||
}
|
||||
|
||||
// Update updates a user <-> namespace relation
|
||||
|
@ -202,7 +202,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
got, err := un.ReadAll(tt.args.search, tt.args.a, tt.args.page)
|
||||
got, _, _, err := un.ReadAll(tt.args.a, tt.args.search, tt.args.page, 50)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("NamespaceUser.ReadAll() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -219,25 +219,26 @@ func (t *Task) addNewAssigneeByID(newAssigneeID int64, list *List) (err error) {
|
||||
// @tags assignees
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 assignees by their username."
|
||||
// @Param taskID path int true "Task ID"
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.User "The assignees"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{taskID}/assignees [get]
|
||||
func (la *TaskAssginee) ReadAll(search string, a web.Auth, page int) (interface{}, error) {
|
||||
func (la *TaskAssginee) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
task, err := GetListSimplByTaskID(la.TaskID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
can, err := task.CanRead(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if !can {
|
||||
return nil, ErrGenericForbidden{}
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
var taskAssignees []*User
|
||||
@ -245,9 +246,18 @@ func (la *TaskAssginee) ReadAll(search string, a web.Auth, page int) (interface{
|
||||
Select("users.*").
|
||||
Join("INNER", "users", "task_assignees.user_id = users.id").
|
||||
Where("task_id = ? AND users.username LIKE ?", la.TaskID, "%"+search+"%").
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Find(&taskAssignees)
|
||||
return taskAssignees, err
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
numberOfTotalItems, err = x.Table("task_assignees").
|
||||
Select("users.*").
|
||||
Join("INNER", "users", "task_assignees.user_id = users.id").
|
||||
Where("task_id = ? AND users.username LIKE ?", la.TaskID, "%"+search+"%").
|
||||
Count(&User{})
|
||||
return taskAssignees, len(taskAssignees), numberOfTotalItems, err
|
||||
}
|
||||
|
||||
// BulkAssignees is a helper struct used to update multiple assignees at once.
|
||||
|
@ -100,21 +100,23 @@ func (ta *TaskAttachment) ReadOne() (err error) {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path int true "Task ID"
|
||||
// @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."
|
||||
// @Security JWTKeyAuth
|
||||
// @Success 200 {array} models.TaskAttachment "All attachments for this task"
|
||||
// @Failure 403 {object} models.Message "No access to this task."
|
||||
// @Failure 404 {object} models.Message "The task does not exist."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{id}/attachments [get]
|
||||
func (ta *TaskAttachment) ReadAll(s string, a web.Auth, page int) (interface{}, error) {
|
||||
func (ta *TaskAttachment) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
attachments := []*TaskAttachment{}
|
||||
|
||||
err := x.
|
||||
Limit(getLimitFromPageIndex(page)).
|
||||
err = x.
|
||||
Limit(getLimitFromPageIndex(page, perPage)).
|
||||
Where("task_id = ?", ta.TaskID).
|
||||
Find(&attachments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
fileIDs := make([]int64, 0, len(attachments))
|
||||
@ -127,13 +129,13 @@ func (ta *TaskAttachment) ReadAll(s string, a web.Auth, page int) (interface{},
|
||||
fs := make(map[int64]*files.File)
|
||||
err = x.In("id", fileIDs).Find(&fs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
us := make(map[int64]*User)
|
||||
err = x.In("id", userIDs).Find(&us)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
for _, r := range attachments {
|
||||
@ -146,7 +148,10 @@ func (ta *TaskAttachment) ReadAll(s string, a web.Auth, page int) (interface{},
|
||||
r.CreatedBy = us[r.CreatedByID]
|
||||
}
|
||||
|
||||
return attachments, err
|
||||
numberOfTotalItems, err = x.
|
||||
Where("task_id = ?", ta.TaskID).
|
||||
Count(&TaskAttachment{})
|
||||
return attachments, len(attachments), numberOfTotalItems, err
|
||||
}
|
||||
|
||||
// Delete removes an attachment
|
||||
|
@ -119,7 +119,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
||||
func TestTaskAttachment_ReadAll(t *testing.T) {
|
||||
files.InitTestFileFixtures(t)
|
||||
ta := &TaskAttachment{TaskID: 1}
|
||||
as, err := ta.ReadAll("", &User{ID: 1}, 0)
|
||||
as, _, _, err := ta.ReadAll(&User{ID: 1}, "", 0, 50)
|
||||
attachments, _ := as.([]*TaskAttachment)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, attachments, 3)
|
||||
|
@ -728,7 +728,7 @@ func TestTask_ReadAll(t *testing.T) {
|
||||
CRUDable: tt.fields.CRUDable,
|
||||
Rights: tt.fields.Rights,
|
||||
}
|
||||
got, err := lt.ReadAll(tt.args.search, tt.args.a, tt.args.page)
|
||||
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
|
||||
|
@ -123,7 +123,8 @@ const (
|
||||
// @tags task
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param p query int false "The page number. Used for pagination. If not provided, the first page of results is returned."
|
||||
// @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 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."
|
||||
@ -132,7 +133,7 @@ const (
|
||||