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:
konrad 2020-12-23 15:32:28 +00:00
parent fa68e89c04
commit 8d1a09b5a2
107 changed files with 2428 additions and 1279 deletions

8
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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)
},
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
})
}
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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,
})

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}