forked from vikunja/vikunja
Use db sessions everywere (#750)
Fix lint Fix lint Fix loading tasks with search Fix loading lists Fix loading task Fix loading lists and namespaces Fix tests Fix user commands Fix upload Fix migration handlers Fix all manual root handlers Fix session in avatar Fix session in list duplication & routes Use sessions in migration code Make sure the openid stuff uses a session Add alias for db type in db package Use sessions for file Use a session for everything in users Use a session for everything in users Make sure to use a session everywhere in models Create new session from db Add session handling for user list Add session handling for unsplash Add session handling for teams and related Add session handling for tasks and related entities Add session handling for task reminders Add session handling for task relations Add session handling for task comments Add session handling for task collections Add session handling for task attachments Add session handling for task assignees Add session handling for saved filters Add session handling for namespace and related types Add session handling for namespace and related types Add session handling for list users Add session handling for list tests Add session handling to list teams and related entities Add session handling for link shares and related entities Add session handling for labels and related entities Add session handling for kanban and related entities Add session handling for bulk task and related entities Add session handling for lists and related entities Add session configuration for web handler Update web handler Co-authored-by: kolaente <k@knt.li> Reviewed-on: vikunja/api#750 Co-Authored-By: konrad <konrad@kola-entertainments.de> Co-Committed-By: konrad <konrad@kola-entertainments.de>
This commit is contained in:
parent
fa68e89c04
commit
8d1a09b5a2
8
go.mod
8
go.mod
@ -18,7 +18,7 @@ module code.vikunja.io/api
|
||||
|
||||
require (
|
||||
4d63.com/tz v1.2.0
|
||||
code.vikunja.io/web v0.0.0-20200809154828-8767618f181f
|
||||
code.vikunja.io/web v0.0.0-20201223143420-588abb73703a
|
||||
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 // indirect
|
||||
gitea.com/xorm/xorm-redis-cache v0.2.0
|
||||
github.com/adlio/trello v1.8.0
|
||||
@ -41,6 +41,7 @@ require (
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.4.1
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||
github.com/golang/snappy v0.0.2 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20201107091007-3b93a8888063
|
||||
github.com/iancoleman/strcase v0.1.2
|
||||
github.com/imdario/mergo v0.3.11
|
||||
@ -52,6 +53,7 @@ require (
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/magefile/mage v1.10.0
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.5
|
||||
github.com/mitchellh/mapstructure v1.3.2 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
@ -76,8 +78,10 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||
golang.org/x/image v0.0.0-20201208152932-35266b937fa6
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5
|
||||
golang.org/x/net v0.0.0-20201216054612-986b41b23924 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 // indirect
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
@ -91,7 +95,7 @@ require (
|
||||
src.techknowlogick.com/xormigrate v1.4.0
|
||||
xorm.io/builder v0.3.7
|
||||
xorm.io/core v0.7.3
|
||||
xorm.io/xorm v1.0.2
|
||||
xorm.io/xorm v1.0.5
|
||||
)
|
||||
|
||||
replace (
|
||||
|
25
go.sum
25
go.sum
@ -38,8 +38,12 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
code.vikunja.io/web v0.0.0-20200809154828-8767618f181f h1:Zgtk9lbJkGbKjdTC78mg/c2uNkesxDJs1YUIL9zGvco=
|
||||
code.vikunja.io/web v0.0.0-20200809154828-8767618f181f/go.mod h1:vDWiCtftF6LNCCrem7mjstPWMgzLUvMW/L4YwIQ1Voo=
|
||||
code.vikunja.io/web v0.0.0-20201218134444-505d0e77fac7 h1:iS3TFA+y1If6DEbqzad5Ge7TI1NxZr9BevC/dU4ygEo=
|
||||
code.vikunja.io/web v0.0.0-20201218134444-505d0e77fac7/go.mod h1:vDWiCtftF6LNCCrem7mjstPWMgzLUvMW/L4YwIQ1Voo=
|
||||
code.vikunja.io/web v0.0.0-20201222144643-6fa2fb587215 h1:O5zMWgcnVDVLaQUawgdsv/jX/4SUUAvSedvRR+5+x2o=
|
||||
code.vikunja.io/web v0.0.0-20201222144643-6fa2fb587215/go.mod h1:OgFO06HN1KpA4S7Dw/QAIeygiUPSeGJJn1ykz/sjZdU=
|
||||
code.vikunja.io/web v0.0.0-20201223143420-588abb73703a h1:LaWCucY5Pp30EIMgGOvdVFNss5OhIAwrAO8PuFVRUfw=
|
||||
code.vikunja.io/web v0.0.0-20201223143420-588abb73703a/go.mod h1:OgFO06HN1KpA4S7Dw/QAIeygiUPSeGJJn1ykz/sjZdU=
|
||||
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363 h1:o4lAkfETerCnr1kF9/qwkwjICnU+YLHNDCM8h2xj7as=
|
||||
dmitri.shuralyov.com/go/generated v0.0.0-20170818220700-b1254a446363/go.mod h1:WG7q7swWsS2f9PYpt5DoEP/EBYWx8We5UoRltn9vJl8=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
@ -152,6 +156,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200910202707-1e08a3fab204 h1:tI48fqaIkxxYuIylVv1tdDfBp6836GKSfmmzgSyP1CY=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200910202707-1e08a3fab204/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
@ -293,6 +298,8 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pO
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
@ -491,6 +498,7 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
||||
@ -516,6 +524,8 @@ github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+v
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
@ -852,8 +862,6 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
|
||||
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@ -944,6 +952,8 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2l
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY=
|
||||
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
@ -1028,8 +1038,13 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuF
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e h1:AyodaIpKjppX+cBfTASF2E1US3H2JFBj920Ot3rtDjs=
|
||||
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201221093633-bc327ba9c2f0 h1:n+DPcgTwkgWzIFpLmoimYR2K2b0Ga5+Os4kayIN0vGo=
|
||||
golang.org/x/sys v0.0.0-20201221093633-bc327ba9c2f0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201223074533-0d417f636930 h1:vRgIt+nup/B/BwIS0g2oC0haq0iqbV3ZA+u6+0TlNCo=
|
||||
golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=
|
||||
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@ -1284,3 +1299,5 @@ xorm.io/xorm v1.0.1 h1:/lITxpJtkZauNpdzj+L9CN/3OQxZaABrbergMcJu+Cw=
|
||||
xorm.io/xorm v1.0.1/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY=
|
||||
xorm.io/xorm v1.0.2 h1:kZlCh9rqd1AzGwWitcrEEqHE1h1eaZE/ujU5/2tWEtg=
|
||||
xorm.io/xorm v1.0.2/go.mod h1:o4vnEsQ5V2F1/WK6w4XTwmiWJeGj82tqjAnHe44wVHY=
|
||||
xorm.io/xorm v1.0.5 h1:LRr5PfOUb4ODPR63YwbowkNDwcolT2LnkwP/TUaMaB0=
|
||||
xorm.io/xorm v1.0.5/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/initialize"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
@ -31,6 +32,7 @@ import (
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/term"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -91,13 +93,13 @@ func getPasswordFromFlagOrInput() (pw string) {
|
||||
return
|
||||
}
|
||||
|
||||
func getUserFromArg(arg string) *user.User {
|
||||
func getUserFromArg(s *xorm.Session, arg string) *user.User {
|
||||
id, err := strconv.ParseInt(arg, 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid user id: %s", err)
|
||||
}
|
||||
|
||||
u, err := user.GetUserByID(id)
|
||||
u, err := user.GetUserByID(s, id)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not get user: %s", err)
|
||||
}
|
||||
@ -116,8 +118,16 @@ var userListCmd = &cobra.Command{
|
||||
initialize.FullInit()
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
users, err := user.ListUsers("")
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
users, err := user.ListUsers(s, "")
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Error getting users: %s", err)
|
||||
}
|
||||
|
||||
if err := s.Commit(); err != nil {
|
||||
log.Fatalf("Error getting users: %s", err)
|
||||
}
|
||||
|
||||
@ -153,21 +163,30 @@ var userCreateCmd = &cobra.Command{
|
||||
initialize.FullInit()
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
u := &user.User{
|
||||
Username: userFlagUsername,
|
||||
Email: userFlagEmail,
|
||||
Password: getPasswordFromFlagOrInput(),
|
||||
}
|
||||
newUser, err := user.CreateUser(u)
|
||||
newUser, err := user.CreateUser(s, u)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Error creating new user: %s", err)
|
||||
}
|
||||
|
||||
err = models.CreateNewNamespaceForUser(newUser)
|
||||
err = models.CreateNewNamespaceForUser(s, newUser)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Error creating new namespace for user: %s", err)
|
||||
}
|
||||
|
||||
if err := s.Commit(); err != nil {
|
||||
log.Fatalf("Error saving everything: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("\nUser was created successfully.\n")
|
||||
},
|
||||
}
|
||||
@ -180,7 +199,10 @@ var userUpdateCmd = &cobra.Command{
|
||||
initialize.FullInit()
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
u := getUserFromArg(args[0])
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
u := getUserFromArg(s, args[0])
|
||||
|
||||
if userFlagUsername != "" {
|
||||
u.Username = userFlagUsername
|
||||
@ -192,11 +214,16 @@ var userUpdateCmd = &cobra.Command{
|
||||
u.AvatarProvider = userFlagAvatar
|
||||
}
|
||||
|
||||
_, err := user.UpdateUser(u)
|
||||
_, err := user.UpdateUser(s, u)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Error updating the user: %s", err)
|
||||
}
|
||||
|
||||
if err := s.Commit(); err != nil {
|
||||
log.Fatalf("Error saving everything: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println("User updated successfully.")
|
||||
},
|
||||
}
|
||||
@ -209,22 +236,31 @@ var userResetPasswordCmd = &cobra.Command{
|
||||
},
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
u := getUserFromArg(args[0])
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
u := getUserFromArg(s, args[0])
|
||||
|
||||
// By default we reset as usual, only with specific flag directly.
|
||||
if userFlagResetPasswordDirectly {
|
||||
err := user.UpdateUserPassword(u, getPasswordFromFlagOrInput())
|
||||
err := user.UpdateUserPassword(s, u, getPasswordFromFlagOrInput())
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Could not update user password: %s", err)
|
||||
}
|
||||
fmt.Println("Password updated successfully.")
|
||||
} else {
|
||||
err := user.RequestUserPasswordResetToken(u)
|
||||
err := user.RequestUserPasswordResetToken(s, u)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Could not send password reset email: %s", err)
|
||||
}
|
||||
fmt.Println("Password reset email sent successfully.")
|
||||
}
|
||||
|
||||
if err := s.Commit(); err != nil {
|
||||
log.Fatalf("Could not send password reset email: %s", err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@ -236,7 +272,10 @@ var userChangeEnabledCmd = &cobra.Command{
|
||||
},
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
u := getUserFromArg(args[0])
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
u := getUserFromArg(s, args[0])
|
||||
|
||||
if userFlagEnableUser {
|
||||
u.IsActive = true
|
||||
@ -245,11 +284,16 @@ var userChangeEnabledCmd = &cobra.Command{
|
||||
} else {
|
||||
u.IsActive = !u.IsActive
|
||||
}
|
||||
_, err := user.UpdateUser(u)
|
||||
_, err := user.UpdateUser(s, u)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
log.Fatalf("Could not enable the user")
|
||||
}
|
||||
|
||||
if err := s.Commit(); err != nil {
|
||||
log.Fatalf("Error saving everything: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("User status successfully changed, user is now active: %t.\n", u.IsActive)
|
||||
},
|
||||
}
|
||||
|
11
pkg/db/db.go
11
pkg/db/db.go
@ -31,6 +31,7 @@ import (
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/caches"
|
||||
"xorm.io/xorm/schemas"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql" // Because.
|
||||
_ "github.com/lib/pq" // Because.
|
||||
@ -211,3 +212,13 @@ func WipeEverything() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewSession creates a new xorm session
|
||||
func NewSession() *xorm.Session {
|
||||
return x.NewSession()
|
||||
}
|
||||
|
||||
// Type returns the db type of the currently configured db
|
||||
func Type() schemas.DBType {
|
||||
return x.Dialect().URI().DBType
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/c2h5oh/datasize"
|
||||
"github.com/spf13/afero"
|
||||
@ -93,27 +94,44 @@ func CreateWithMime(f io.Reader, realname string, realsize uint64, a web.Auth, m
|
||||
Mime: mime,
|
||||
}
|
||||
|
||||
_, err = x.Insert(file)
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
_, err = s.Insert(file)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// Save the file to storage with its new ID as path
|
||||
err = file.Save(f)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Delete removes a file from the DB and the file system
|
||||
func (f *File) Delete() (err error) {
|
||||
deleted, err := x.Where("id = ?", f.ID).Delete(f)
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
deleted, err := s.Where("id = ?", f.ID).Delete(f)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return err
|
||||
}
|
||||
if deleted == 0 {
|
||||
_ = s.Rollback()
|
||||
return ErrFileDoesNotExist{FileID: f.ID}
|
||||
}
|
||||
|
||||
err = afs.Remove(f.getFileName())
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ package models
|
||||
import (
|
||||
"code.vikunja.io/web"
|
||||
"github.com/imdario/mergo"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// BulkTask is the definition of a bulk update task
|
||||
@ -29,9 +30,9 @@ type BulkTask struct {
|
||||
Task
|
||||
}
|
||||
|
||||
func (bt *BulkTask) checkIfTasksAreOnTheSameList() (err error) {
|
||||
func (bt *BulkTask) checkIfTasksAreOnTheSameList(s *xorm.Session) (err error) {
|
||||
// Get the tasks
|
||||
err = bt.GetTasksByIDs()
|
||||
err = bt.GetTasksByIDs(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -52,16 +53,16 @@ func (bt *BulkTask) checkIfTasksAreOnTheSameList() (err error) {
|
||||
}
|
||||
|
||||
// CanUpdate checks if a user is allowed to update a task
|
||||
func (bt *BulkTask) CanUpdate(a web.Auth) (bool, error) {
|
||||
func (bt *BulkTask) CanUpdate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
|
||||
err := bt.checkIfTasksAreOnTheSameList()
|
||||
err := bt.checkIfTasksAreOnTheSameList(s)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// A user can update an task if he has write acces to its list
|
||||
l := &List{ID: bt.Tasks[0].ListID}
|
||||
return l.CanWrite(a)
|
||||
return l.CanWrite(s, a)
|
||||
}
|
||||
|
||||
// Update updates a bunch of tasks at once
|
||||
@ -77,23 +78,14 @@ func (bt *BulkTask) CanUpdate(a web.Auth) (bool, error) {
|
||||
// @Failure 403 {object} web.HTTPError "The user does not have access to the task (aka its list)"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/bulk [post]
|
||||
func (bt *BulkTask) Update() (err error) {
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
err = sess.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
func (bt *BulkTask) Update(s *xorm.Session) (err error) {
|
||||
for _, oldtask := range bt.Tasks {
|
||||
|
||||
// When a repeating task is marked as done, we update all deadlines and reminders and set it as undone
|
||||
updateDone(oldtask, &bt.Task)
|
||||
|
||||
// Update the assignees
|
||||
if err := oldtask.updateTaskAssignees(sess, bt.Assignees); err != nil {
|
||||
if err := oldtask.updateTaskAssignees(s, bt.Assignees); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -109,7 +101,7 @@ func (bt *BulkTask) Update() (err error) {
|
||||
oldtask.Done = false
|
||||
}
|
||||
|
||||
_, err = sess.ID(oldtask.ID).
|
||||
_, err = s.ID(oldtask.ID).
|
||||
Cols("title",
|
||||
"description",
|
||||
"done",
|
||||
@ -121,15 +113,9 @@ func (bt *BulkTask) Update() (err error) {
|
||||
"end_date").
|
||||
Update(oldtask)
|
||||
if err != nil {
|
||||
_ = sess.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = sess.Commit()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -57,18 +57,22 @@ func TestBulkTask_Update(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
s := db.NewSession()
|
||||
|
||||
bt := &BulkTask{
|
||||
IDs: tt.fields.IDs,
|
||||
Tasks: tt.fields.Tasks,
|
||||
Task: tt.fields.Task,
|
||||
}
|
||||
allowed, _ := bt.CanUpdate(tt.fields.User)
|
||||
allowed, _ := bt.CanUpdate(s, tt.fields.User)
|
||||
if !allowed != tt.wantForbidden {
|
||||
t.Errorf("BulkTask.Update() want forbidden, got %v, want %v", allowed, tt.wantForbidden)
|
||||
}
|
||||
if err := bt.Update(); (err != nil) != tt.wantErr {
|
||||
if err := bt.Update(s); (err != nil) != tt.wantErr {
|
||||
t.Errorf("BulkTask.Update() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
|
||||
s.Close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -97,14 +97,14 @@ func getDefaultBucket(s *xorm.Session, listID int64) (bucket *Bucket, err error)
|
||||
// @Success 200 {array} models.Bucket "The buckets with their tasks"
|
||||
// @Failure 500 {object} models.Message "Internal server error"
|
||||
// @Router /lists/{id}/buckets [get]
|
||||
func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
func (b *Bucket) ReadAll(s *xorm.Session, auth web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
|
||||
// Note: I'm ignoring pagination for now since I've yet to figure out a way on how to make it work
|
||||
// I'll probably just don't do it and instead make individual tasks archivable.
|
||||
|
||||
// Get all buckets for this list
|
||||
buckets := []*Bucket{}
|
||||
err = x.Where("list_id = ?", b.ListID).Find(&buckets)
|
||||
err = s.Where("list_id = ?", b.ListID).Find(&buckets)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -119,7 +119,7 @@ func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (r
|
||||
|
||||
// Get all users
|
||||
users := make(map[int64]*user.User)
|
||||
err = x.In("id", userIDs).Find(&users)
|
||||
err = s.In("id", userIDs).Find(&users)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -132,7 +132,7 @@ func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (r
|
||||
b.TaskCollection.ListID = b.ListID
|
||||
b.TaskCollection.OrderBy = []string{string(orderAscending)}
|
||||
b.TaskCollection.SortBy = []string{taskPropertyPosition}
|
||||
ts, _, _, err := b.TaskCollection.ReadAll(auth, "", -1, 0)
|
||||
ts, _, _, err := b.TaskCollection.ReadAll(s, auth, "", -1, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -168,10 +168,10 @@ func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (r
|
||||
// @Failure 404 {object} web.HTTPError "The list does not exist."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{id}/buckets [put]
|
||||
func (b *Bucket) Create(a web.Auth) (err error) {
|
||||
func (b *Bucket) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||
b.CreatedByID = a.GetID()
|
||||
|
||||
_, err = x.Insert(b)
|
||||
_, err = s.Insert(b)
|
||||
return
|
||||
}
|
||||
|
||||
@ -190,8 +190,8 @@ func (b *Bucket) Create(a web.Auth) (err error) {
|
||||
// @Failure 404 {object} web.HTTPError "The bucket does not exist."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{listID}/buckets/{bucketID} [post]
|
||||
func (b *Bucket) Update() (err error) {
|
||||
_, err = x.Where("id = ?", b.ID).Update(b)
|
||||
func (b *Bucket) Update(s *xorm.Session) (err error) {
|
||||
_, err = s.Where("id = ?", b.ID).Update(b)
|
||||
return
|
||||
}
|
||||
|
||||
@ -208,14 +208,11 @@ func (b *Bucket) Update() (err error) {
|
||||
// @Failure 404 {object} web.HTTPError "The bucket does not exist."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /lists/{listID}/buckets/{bucketID} [delete]
|
||||
func (b *Bucket) Delete() (err error) {
|
||||
|
||||
s := x.NewSession()
|
||||
func (b *Bucket) Delete(s *xorm.Session) (err error) {
|
||||
|
||||
// Prevent removing the last bucket
|
||||
total, err := s.Where("list_id = ?", b.ListID).Count(&Bucket{})
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return
|
||||
}
|
||||
if total <= 1 {
|
||||
@ -228,23 +225,19 @@ func (b *Bucket) Delete() (err error) {
|
||||
// Remove the bucket itself
|
||||
_, err = s.Where("id = ?", b.ID).Delete(&Bucket{})
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// Get the default bucket
|
||||
defaultBucket, err := getDefaultBucket(s, b.ListID)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
// Remove all associations of tasks to that bucket
|
||||
_, err = s.Where("bucket_id = ?", b.ID).Cols("bucket_id").Update(&Task{BucketID: defaultBucket.ID})
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return
|
||||
}
|
||||
|
||||
return s.Commit()
|
||||
_, err = s.
|
||||
Where("bucket_id = ?", b.ID).
|
||||
Cols("bucket_id").
|
||||
Update(&Task{BucketID: defaultBucket.ID})
|
||||
return
|
||||
}
|
||||
|
@ -16,30 +16,33 @@
|
||||
|
||||
package models
|
||||
|
||||
import "code.vikunja.io/web"
|
||||
import (
|
||||
"code.vikunja.io/web"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// CanCreate checks if a user can create a new bucket
|
||||
func (b *Bucket) CanCreate(a web.Auth) (bool, error) {
|
||||
func (b *Bucket) CanCreate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
l := &List{ID: b.ListID}
|
||||
return l.CanWrite(a)
|
||||
return l.CanWrite(s, a)
|
||||
}
|
||||
|
||||
// CanUpdate checks if a user can update an existing bucket
|
||||
func (b *Bucket) CanUpdate(a web.Auth) (bool, error) {
|
||||
return b.canDoBucket(a)
|
||||
func (b *Bucket) CanUpdate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
return b.canDoBucket(s, a)
|
||||
}
|
||||
|
||||
// CanDelete checks if a user can delete an existing bucket
|
||||
func (b *Bucket) CanDelete(a web.Auth) (bool, error) {
|
||||
return b.canDoBucket(a)
|
||||
func (b *Bucket) CanDelete(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
return b.canDoBucket(s, a)
|
||||
}
|
||||
|
||||
// canDoBucket checks if the bucket exists and if the user has the right to act on it
|
||||
func (b *Bucket) canDoBucket(a web.Auth) (bool, error) {
|
||||
bb, err := getBucketByID(x.NewSession(), b.ID)
|
||||
func (b *Bucket) canDoBucket(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
bb, err := getBucketByID(s, b.ID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
l := &List{ID: bb.ListID}
|
||||
return l.CanWrite(a)
|
||||
return l.CanWrite(s, a)
|
||||
}
|
||||
|
@ -27,10 +27,12 @@ import (
|
||||
func TestBucket_ReadAll(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
testuser := &user.User{ID: 1}
|
||||
b := &Bucket{ListID: 1}
|
||||
bucketsInterface, _, _, err := b.ReadAll(testuser, "", 0, 0)
|
||||
bucketsInterface, _, _, err := b.ReadAll(s, testuser, "", 0, 0)
|
||||
assert.NoError(t, err)
|
||||
|
||||
buckets, is := bucketsInterface.([]*Bucket)
|
||||
@ -66,6 +68,8 @@ func TestBucket_ReadAll(t *testing.T) {
|
||||
})
|
||||
t.Run("filtered", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
testuser := &user.User{ID: 1}
|
||||
b := &Bucket{
|
||||
@ -76,7 +80,7 @@ func TestBucket_ReadAll(t *testing.T) {
|
||||
FilterValue: []string{"done"},
|
||||
},
|
||||
}
|
||||
bucketsInterface, _, _, err := b.ReadAll(testuser, "", 0, 0)
|
||||
bucketsInterface, _, _, err := b.ReadAll(s, testuser, "", 0, 0)
|
||||
assert.NoError(t, err)
|
||||
|
||||
buckets := bucketsInterface.([]*Bucket)
|
||||
@ -88,16 +92,21 @@ func TestBucket_ReadAll(t *testing.T) {
|
||||
func TestBucket_Delete(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
b := &Bucket{
|
||||
ID: 2, // The second bucket only has 3 tasks
|
||||
ListID: 1,
|
||||
}
|
||||
err := b.Delete()
|
||||
err := b.Delete(s)
|
||||
assert.NoError(t, err)
|
||||
err = s.Commit()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Assert all tasks have been moved to bucket 1 as that one is the first
|
||||
tasks := []*Task{}
|
||||
err = x.Where("bucket_id = ?", 1).Find(&tasks)
|
||||
err = s.Where("bucket_id = ?", 1).Find(&tasks)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, tasks, 15)
|
||||
db.AssertMissing(t, "buckets", map[string]interface{}{
|
||||
@ -107,13 +116,19 @@ func TestBucket_Delete(t *testing.T) {
|
||||
})
|
||||
t.Run("last bucket in list", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
s := db.NewSession()
|
||||
defer s.Close()
|
||||
|
||||
b := &Bucket{
|
||||
ID: 34,
|
||||
ListID: 18,
|
||||
}
|
||||
err := b.Delete()
|
||||
err := b.Delete(s)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrCannotRemoveLastBucket(err))
|
||||
err = s.Commit()
|
||||
assert.NoError(t, err)
|
||||
|
||||
db.AssertExists(t, "buckets", map[string]interface{}{
|
||||
"id": 34,
|
||||
"list_id": 18,
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// Label represents a label
|
||||
@ -64,7 +65,7 @@ func (Label) TableName() string {
|
||||
// @Failure 400 {object} web.HTTPError "Invalid label object provided."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels [put]
|
||||
func (l *Label) Create(a web.Auth) (err error) {
|
||||
func (l *Label) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||
u, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return
|
||||
@ -73,7 +74,7 @@ func (l *Label) Create(a web.Auth) (err error) {
|
||||
l.CreatedBy = u
|
||||
l.CreatedByID = u.ID
|
||||
|
||||
_, err = x.Insert(l)
|
||||
_, err = s.Insert(l)
|
||||
return
|
||||
}
|
||||
|
||||
@ -92,8 +93,8 @@ func (l *Label) Create(a web.Auth) (err error) {
|
||||
// @Failure 404 {object} web.HTTPError "Label not found."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels/{id} [put]
|
||||
func (l *Label) Update() (err error) {
|
||||
_, err = x.
|
||||
func (l *Label) Update(s *xorm.Session) (err error) {
|
||||
_, err = s.
|
||||
ID(l.ID).
|
||||
Cols(
|
||||
"title",
|
||||
@ -105,7 +106,7 @@ func (l *Label) Update() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
err = l.ReadOne()
|
||||
err = l.ReadOne(s)
|
||||
return
|
||||
}
|
||||
|
||||
@ -122,8 +123,8 @@ func (l *Label) Update() (err error) {
|
||||
// @Failure 404 {object} web.HTTPError "Label not found."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels/{id} [delete]
|
||||
func (l *Label) Delete() (err error) {
|
||||
_, err = x.ID(l.ID).Delete(&Label{})
|
||||
func (l *Label) Delete(s *xorm.Session) (err error) {
|
||||
_, err = s.ID(l.ID).Delete(&Label{})
|
||||
return err
|
||||
}
|
||||
|
||||
@ -140,7 +141,7 @@ func (l *Label) Delete() (err error) {
|
||||
// @Success 200 {array} models.Label "The labels"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels [get]
|
||||
func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls interface{}, resultCount int, numberOfEntries int64, err error) {
|
||||
func (l *Label) ReadAll(s *xorm.Session, a web.Auth, search string, page int, perPage int) (ls interface{}, resultCount int, numberOfEntries int64, err error) {
|
||||
if _, is := a.(*LinkSharing); is {
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
@ -148,12 +149,12 @@ func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls in
|
||||
u := &user.User{ID: a.GetID()}
|
||||
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(u)
|
||||
taskIDs, err := getUserTaskIDs(s, u)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||
return getLabelsByTaskIDs(s, &LabelByTaskIDsOptions{
|
||||
Search: search,
|
||||
User: u,
|
||||
TaskIDs: taskIDs,
|
||||
@ -177,25 +178,25 @@ func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls in
|
||||
// @Failure 404 {object} web.HTTPError "Label not found"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels/{id} [get]
|
||||
func (l *Label) ReadOne() (err error) {
|
||||
label, err := getLabelByIDSimple(l.ID)
|
||||
func (l *Label) ReadOne(s *xorm.Session) (err error) {
|
||||
label, err := getLabelByIDSimple(s, l.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*l = *label
|
||||
|
||||
user, err := user.GetUserByID(l.CreatedByID)
|
||||
u, err := user.GetUserByID(s, l.CreatedByID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.CreatedBy = user
|
||||
l.CreatedBy = u
|
||||
return
|
||||
}
|
||||
|
||||
func getLabelByIDSimple(labelID int64) (*Label, error) {
|
||||
func getLabelByIDSimple(s *xorm.Session, labelID int64) (*Label, error) {
|
||||
label := Label{}
|
||||
exists, err := x.ID(labelID).Get(&label)
|
||||
exists, err := s.ID(labelID).Get(&label)
|
||||
if err != nil {
|
||||
return &label, err
|
||||
}
|
||||
@ -207,18 +208,21 @@ func getLabelByIDSimple(labelID int64) (*Label, error) {
|
||||
}
|
||||
|
||||
// Helper method to get all task ids a user has
|
||||
func getUserTaskIDs(u *user.User) (taskIDs []int64, err error) {
|
||||
func getUserTaskIDs(s *xorm.Session, u *user.User) (taskIDs []int64, err error) {
|
||||
|
||||
// Get all lists
|
||||
lists, _, _, err := getRawListsForUser(&listOptions{
|
||||
user: u,
|
||||
page: -1,
|
||||
})
|
||||
lists, _, _, err := getRawListsForUser(
|
||||
s,
|
||||
&listOptions{
|
||||
user: u,
|
||||
page: -1,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tasks, _, _, err := getRawTasksForLists(lists, u, &taskOptions{
|
||||
tasks, _, _, err := getRawTasksForLists(s, lists, u, &taskOptions{
|
||||
page: -1,
|
||||
perPage: 0,
|
||||
})
|
||||
|
@ -20,26 +20,27 @@ import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// CanUpdate checks if a user can update a label
|
||||
func (l *Label) CanUpdate(a web.Auth) (bool, error) {
|
||||
return l.isLabelOwner(a) // Only owners should be allowed to update a label
|
||||
func (l *Label) CanUpdate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
return l.isLabelOwner(s, a) // Only owners should be allowed to update a label
|
||||
}
|
||||
|
||||
// CanDelete checks if a user can delete a label
|
||||
func (l *Label) CanDelete(a web.Auth) (bool, error) {
|
||||
return l.isLabelOwner(a) // Only owners should be allowed to delete a label
|
||||
func (l *Label) CanDelete(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
return l.isLabelOwner(s, a) // Only owners should be allowed to delete a label
|
||||
}
|
||||
|
||||
// CanRead checks if a user can read a label
|
||||
func (l *Label) CanRead(a web.Auth) (bool, int, error) {
|
||||
return l.hasAccessToLabel(a)
|
||||
func (l *Label) CanRead(s *xorm.Session, a web.Auth) (bool, int, error) {
|
||||
return l.hasAccessToLabel(s, a)
|
||||
}
|
||||
|
||||
// CanCreate checks if the user can create a label
|
||||
// Currently a dummy.
|
||||
func (l *Label) CanCreate(a web.Auth) (bool, error) {
|
||||
func (l *Label) CanCreate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
if _, is := a.(*LinkSharing); is {
|
||||
return false, nil
|
||||
}
|
||||
@ -47,13 +48,13 @@ func (l *Label) CanCreate(a web.Auth) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (l *Label) isLabelOwner(a web.Auth) (bool, error) {
|
||||
func (l *Label) isLabelOwner(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
|
||||
if _, is := a.(*LinkSharing); is {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
lorig, err := getLabelByIDSimple(l.ID)
|
||||
lorig, err := getLabelByIDSimple(s, l.ID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -61,19 +62,19 @@ func (l *Label) isLabelOwner(a web.Auth) (bool, error) {
|
||||
}
|
||||
|
||||
// Helper method to check if a user can see a specific label
|
||||
func (l *Label) hasAccessToLabel(a web.Auth) (has bool, maxRight int, err error) {
|
||||
func (l *Label) hasAccessToLabel(s *xorm.Session, a web.Auth) (has bool, maxRight int, err error) {
|
||||
|
||||
// TODO: add an extra check for link share handling
|
||||
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(&user.User{ID: a.GetID()})
|
||||
taskIDs, err := getUserTaskIDs(s, &user.User{ID: a.GetID()})
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
|
||||
// Get all labels associated with these tasks
|
||||
ll := &LabelTask{}
|
||||
has, err = x.Table("labels").
|
||||
has, err = s.Table("labels").
|
||||
Select("label_task.*").
|
||||
Join("LEFT", "label_task", "label_task.label_id = labels.id").
|
||||
Where("label_task.label_id is not null OR labels.created_by_id = ?", a.GetID()).
|
||||
@ -87,7 +88,7 @@ func (l *Label) hasAccessToLabel(a web.Auth) (has bool, maxRight int, err error)
|
||||
// Since the right depends on the task the label is associated with, we need to check that too.
|
||||
if ll.TaskID > 0 {
|
||||
t := &Task{ID: ll.TaskID}
|
||||
_, maxRight, err = t.CanRead(a)
|
||||
_, maxRight, err = t.CanRead(s, a)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -22,10 +22,10 @@ import (
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// LabelTask represents a relation between a label and a task
|
||||
@ -61,8 +61,8 @@ func (LabelTask) TableName() string {
|
||||
// @Failure 404 {object} web.HTTPError "Label not found."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{task}/labels/{label} [delete]
|
||||
func (lt *LabelTask) Delete() (err error) {
|
||||
_, err = x.Delete(&LabelTask{LabelID: lt.LabelID, TaskID: lt.TaskID})
|
||||
func (lt *LabelTask) Delete(s *xorm.Session) (err error) {
|
||||
_, err = s.Delete(&LabelTask{LabelID: lt.LabelID, TaskID: lt.TaskID})
|
||||
return err
|
||||
}
|
||||
|
||||
@ -81,9 +81,9 @@ func (lt *LabelTask) Delete() (err error) {
|
||||
// @Failure 404 {object} web.HTTPError "The label does not exist."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{task}/labels [put]
|
||||
func (lt *LabelTask) Create(a web.Auth) (err error) {
|
||||
func (lt *LabelTask) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||
// Check if the label is already added
|
||||
exists, err := x.Exist(&LabelTask{LabelID: lt.LabelID, TaskID: lt.TaskID})
|
||||
exists, err := s.Exist(&LabelTask{LabelID: lt.LabelID, TaskID: lt.TaskID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -92,12 +92,12 @@ func (lt *LabelTask) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Insert it
|
||||
_, err = x.Insert(lt)
|
||||
_, err = s.Insert(lt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = updateListByTaskID(lt.TaskID)
|
||||
err = updateListByTaskID(s, lt.TaskID)
|
||||
return
|
||||
}
|
||||
|
||||
@ -115,10 +115,10 @@ func (lt *LabelTask) Create(a web.Auth) (err error) {
|
||||
// @Success 200 {array} models.Label "The labels"
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{task}/labels [get]
|
||||
func (lt *LabelTask) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
|
||||
func (lt *LabelTask) ReadAll(s *xorm.Session, 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)
|
||||
canRead, _, err := task.CanRead(s, a)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
@ -126,7 +126,7 @@ func (lt *LabelTask) ReadAll(a web.Auth, search string, page int, perPage int) (
|
||||
return nil, 0, 0, ErrNoRightToSeeTask{lt.TaskID, a.GetID()}
|
||||
}
|
||||
|
||||
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||
return getLabelsByTaskIDs(s, &LabelByTaskIDsOptions{
|
||||
User: &user.User{ID: a.GetID()},
|
||||
Search: search,
|
||||
Page: page,
|
||||
@ -153,7 +153,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, resultCount int, totalEntries int64, err error) {
|
||||
func getLabelsByTaskIDs(s *xorm.Session, opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, resultCount int, totalEntries int64, err error) {
|
||||
// We still need the task ID when we want to get all labels for a task, but because of this, we get the same label
|
||||
// multiple times when it is associated to more than one task.
|
||||
// Because of this whole thing, we need this extra switch here to only group by Task IDs if needed.
|
||||
@ -194,7 +194,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
||||
|
||||
limit, start := getLimitFromPageIndex(opts.Page, opts.PerPage)
|
||||
|
||||
query := x.Table("labels").
|
||||
query := s.Table("labels").
|
||||
Select(selectStmt).
|
||||
Join("LEFT", "label_task", "label_task.label_id = labels.id").
|
||||
Where(cond).
|
||||
@ -214,7 +214,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
||||
userids = append(userids, l.CreatedByID)
|
||||
}
|
||||
users := make(map[int64]*user.User)
|
||||
err = x.In("id", userids).Find(&users)
|
||||
err = s.In("id", userids).Find(&users)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
@ -230,7 +230,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
||||
}
|
||||
|
||||
// Get the total number of entries
|
||||
totalEntries, err = x.Table("labels").
|
||||
totalEntries, err = s.Table("labels").
|
||||
Select("count(DISTINCT labels.id)").
|
||||
Join("LEFT", "label_task", "label_task.label_id = labels.id").
|
||||
Where(cond).
|
||||
@ -244,11 +244,11 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
||||
}
|
||||
|
||||
// Create or update a bunch of task labels
|
||||
func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
||||
func (t *Task) updateTaskLabels(s *xorm.Session, creator web.Auth, labels []*Label) (err error) {
|
||||
|
||||
// If we don't have any new labels, delete everything right away. Saves us some hassle.
|
||||
if len(labels) == 0 && len(t.Labels) > 0 {
|
||||
_, err = x.Where("task_id = ?", t.ID).
|
||||
_, err = s.Where("task_id = ?", t.ID).
|
||||
Delete(LabelTask{})
|
||||
return err
|
||||
}
|
||||
@ -289,7 +289,7 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
||||
|
||||
// Delete all labels not passed
|
||||
if len(labelsToDelete) > 0 {
|
||||
_, err = x.In("label_id", labelsToDelete).
|
||||
_, err = s.In("label_id", labelsToDelete).
|
||||
And("task_id = ?", t.ID).
|
||||
Delete(LabelTask{})
|
||||
if err != nil {
|
||||
@ -306,13 +306,13 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
||||
}
|
||||
|
||||
// Add the new label
|
||||
label, err := getLabelByIDSimple(l.ID)
|
||||
label, err := getLabelByIDSimple(s, l.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if the user has the rights to see the label he is about to add
|
||||
hasAccessToLabel, _, err := label.hasAccessToLabel(creator)
|
||||
hasAccessToLabel, _, err := label.hasAccessToLabel(s, creator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -322,14 +322,14 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
||||
}
|
||||
|
||||
// Insert it
|
||||
_, err = x.Insert(&LabelTask{LabelID: l.ID, TaskID: t.ID})
|
||||
_, err = s.Insert(&LabelTask{LabelID: l.ID, TaskID: t.ID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.Labels = append(t.Labels, label)
|
||||
}
|
||||
|
||||
err = updateListLastUpdated(&List{ID: t.ListID})
|
||||
err = updateListLastUpdated(s, &List{ID: t.ListID})
|
||||
return
|
||||
}
|
||||
|
||||
@ -356,12 +356,12 @@ type LabelTaskBulk struct {
|
||||
// @Failure 400 {object} web.HTTPError "Invalid label object provided."
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /tasks/{taskID}/labels/bulk [post]
|
||||
func (ltb *LabelTaskBulk) Create(a web.Auth) (err error) {
|
||||
task, err := GetTaskByIDSimple(ltb.TaskID)
|
||||
func (ltb *LabelTaskBulk) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||
task, err := GetTaskByIDSimple(s, ltb.TaskID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
labels, _, _, err := getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||
labels, _, _, err := getLabelsByTaskIDs(s, &LabelByTaskIDsOptions{
|
||||
TaskIDs: []int64{ltb.TaskID},
|
||||
})
|
||||
if err != nil {
|
||||
@ -370,5 +370,5 @@ func (ltb *LabelTaskBulk) Create(a web.Auth) (err error) {
|
||||
for _, l := range labels {
|
||||
task.Labels = append(task.Labels, &l.Label)
|
||||
}
|
||||
return task.updateTaskLabels(a, ltb.Labels)
|
||||
return task.updateTaskLabels(s, a, ltb.Labels)
|
||||
}
|
||||
|
@ -18,21 +18,22 @@ package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/web"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
// CanCreate checks if a user can add a label to a task
|
||||
func (lt *LabelTask) CanCreate(a web.Auth) (bool, error) {
|
||||
label, err := getLabelByIDSimple(lt.LabelID)
|
||||
func (lt *LabelTask) CanCreate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
label, err := getLabelByIDSimple(s, lt.LabelID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
hasAccessTolabel, _, err := label.hasAccessToLabel(a)
|
||||
hasAccessTolabel, _, err := label.hasAccessToLabel(s, a)
|
||||
if err != nil || !hasAccessTolabel { // If the user doesn't have access to the label, we can error out here
|
||||
return false, err
|
||||
}
|
||||
|
||||
canDoLabelTask, err := canDoLabelTask(lt.TaskID, a)
|
||||
canDoLabelTask, err := canDoLabelTask(s, lt.TaskID, a)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -41,8 +42,8 @@ func (lt *LabelTask) CanCreate(a web.Auth) (bool, error) {
|
||||
}
|
||||
|
||||
// CanDelete checks if a user can delete a label from a task
|
||||
func (lt *LabelTask) CanDelete(a web.Auth) (bool, error) {
|
||||
canDoLabelTask, err := canDoLabelTask(lt.TaskID, a)
|
||||
func (lt *LabelTask) CanDelete(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
canDoLabelTask, err := canDoLabelTask(s, lt.TaskID, a)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -52,7 +53,7 @@ func (lt *LabelTask) CanDelete(a web.Auth) (bool, error) {
|
||||
|
||||
// We don't care here if the label exists or not. The only relevant thing here is if the relation already exists,
|
||||
// throw an error.
|
||||
exists, err := x.Exist(&LabelTask{LabelID: lt.LabelID, TaskID: lt.TaskID})
|
||||
exists, err := s.Exist(&LabelTask{LabelID: lt.LabelID, TaskID: lt.TaskID})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -60,18 +61,18 @@ func (lt *LabelTask) CanDelete(a web.Auth) (bool, error) {
|
||||
}
|
||||
|
||||
// CanCreate determines if a user can update a labeltask
|
||||
func (ltb *LabelTaskBulk) CanCreate(a web.Auth) (bool, error) {
|
||||
return canDoLabelTask(ltb.TaskID, a)
|
||||
func (ltb *LabelTaskBulk) CanCreate(s *xorm.Session, a web.Auth) (bool, error) {
|
||||
return canDoLabelTask(s, ltb.TaskID, a)
|
||||
}
|
||||