Refactor User and DB handling #123
|
@ -16,7 +16,12 @@ In general, this api repo has the following structure:
|
||||||
* `docs`
|
* `docs`
|
||||||
* `pkg`
|
* `pkg`
|
||||||
* `caldav`
|
* `caldav`
|
||||||
|
* `cmd`
|
||||||
* `config`
|
* `config`
|
||||||
|
* `db`
|
||||||
|
* `fixtures`
|
||||||
|
* `files`
|
||||||
|
* `integration`
|
||||||
* `log`
|
* `log`
|
||||||
* `mail`
|
* `mail`
|
||||||
* `metrics`
|
* `metrics`
|
||||||
|
@ -29,8 +34,11 @@ In general, this api repo has the following structure:
|
||||||
* `red`
|
* `red`
|
||||||
* `routes`
|
* `routes`
|
||||||
* `api/v1`
|
* `api/v1`
|
||||||
|
* `static`
|
||||||
* `swagger`
|
* `swagger`
|
||||||
|
* `user`
|
||||||
* `utils`
|
* `utils`
|
||||||
|
* `version`
|
||||||
* `REST-Tests`
|
* `REST-Tests`
|
||||||
* `templates`
|
* `templates`
|
||||||
* `vendor`
|
* `vendor`
|
||||||
|
@ -70,6 +78,21 @@ how to interpret which env variables for config etc.
|
||||||
|
|
||||||
If you want to add a new config parameter, you should add default value in this package.
|
If you want to add a new config parameter, you should add default value in this package.
|
||||||
|
|
||||||
|
### db
|
||||||
|
|
||||||
|
This package contains the db connection handling and db fixtures for testing.
|
||||||
|
Each other package gets its db connection object from this package.
|
||||||
|
|
||||||
|
### files
|
||||||
|
|
||||||
|
This package is responsible for all file-related things.
|
||||||
|
This means it handles saving and retrieving files from the db and the underlying file system.
|
||||||
|
|
||||||
|
### integration
|
||||||
|
|
||||||
|
All integration tests live here.
|
||||||
|
See [integration tests]({{< ref "test.md" >}}#integration-tests) for more details.
|
||||||
|
|
||||||
### log
|
### log
|
||||||
|
|
||||||
Similar to `config`, this will set up the logging, based on differen logging backends.
|
Similar to `config`, this will set up the logging, based on differen logging backends.
|
||||||
|
@ -127,11 +150,19 @@ To add a new route, see [adding a new route]({{< ref "../practical-instructions/
|
||||||
This is where all http-handler functions for the api are stored.
|
This is where all http-handler functions for the api are stored.
|
||||||
Every handler function which does not use the standard web handler should live here.
|
Every handler function which does not use the standard web handler should live here.
|
||||||
|
|
||||||
|
### static
|
||||||
|
|
||||||
|
All static files generated by `make generate` live here.
|
||||||
|
|
||||||
### swagger
|
### swagger
|
||||||
|
|
||||||
This is where the [generated]({{< ref "make.md#generate-swagger-definitions-from-code-comments">}} [api docs]({{< ref "../usage/api.md">}}) live.
|
This is where the [generated]({{< ref "make.md#generate-swagger-definitions-from-code-comments">}} [api docs]({{< ref "../usage/api.md">}}) live.
|
||||||
You usually don't need to touch this package.
|
You usually don't need to touch this package.
|
||||||
|
|
||||||
|
### user
|
||||||
|
|
||||||
|
All user-related things like registration etc. live in this package.
|
||||||
|
|
||||||
### utils
|
### utils
|
||||||
|
|
||||||
A small package, containing some helper functions:
|
A small package, containing some helper functions:
|
||||||
|
@ -141,6 +172,12 @@ A small package, containing some helper functions:
|
||||||
|
|
||||||
See their function definitions for instructions on how to use them.
|
See their function definitions for instructions on how to use them.
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
The single purpouse of this package is to hold the current vikunja version which gets overridden through build flags
|
||||||
|
each time `make release` or `make build` is run.
|
||||||
|
It is a seperate package to avoid import cycles with other packages.
|
||||||
|
|
||||||
## REST-Tests
|
## REST-Tests
|
||||||
|
|
||||||
Holds all kinds of test files to directly test the api from inside of [jetbrains ide's](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html).
|
Holds all kinds of test files to directly test the api from inside of [jetbrains ide's](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html).
|
||||||
|
|
|
@ -42,3 +42,29 @@ The integration tests use the same config and fixtures as the unit tests and the
|
||||||
see at the beginning of this document.
|
see at the beginning of this document.
|
||||||
|
|
||||||
To run integration tests, use `make integration-test`.
|
To run integration tests, use `make integration-test`.
|
||||||
|
|
||||||
|
# Initializing db fixtures when writing tests
|
||||||
|
|
||||||
|
All db fixtures for all tests live in the `pkg/db/fixtures/` folder as yaml files.
|
||||||
|
Each file has the same name as the table the fixtures are for.
|
||||||
|
You should put new fixtures in this folder.
|
||||||
|
|
||||||
|
When initializing db fixtures, you are responsible for defining which tables your package needs in your test init function.
|
||||||
|
Usually, this is done as follows (this code snippet is taken from the `user` package):
|
||||||
|
|
||||||
|
```go
|
||||||
|
err = db.InitTestFixtures("users")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In your actual tests, you then load the fixtures into the in-memory db like so:
|
||||||
|
|
||||||
|
```go
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
```
|
||||||
|
|
||||||
|
This will load all fixtures you defined in your test init method.
|
||||||
|
You should always use this method to load fixtures, the only exception is when your package tests require extra test
|
||||||
|
fixtures other than db fixtures (like files).
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -59,7 +59,6 @@ require (
|
||||||
github.com/onsi/gomega v1.4.3 // indirect
|
github.com/onsi/gomega v1.4.3 // indirect
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/pelletier/go-toml v1.4.0 // indirect
|
github.com/pelletier/go-toml v1.4.0 // indirect
|
||||||
github.com/pkg/errors v0.8.1 // indirect
|
|
||||||
github.com/prometheus/client_golang v0.9.2
|
github.com/prometheus/client_golang v0.9.2
|
||||||
github.com/samedi/caldav-go v3.0.0+incompatible
|
github.com/samedi/caldav-go v3.0.0+incompatible
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b
|
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
package caldav
|
package caldav
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/api/pkg/utils"
|
"code.vikunja.io/api/pkg/utils"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -49,7 +49,7 @@ type Todo struct {
|
||||||
Summary string
|
Summary string
|
||||||
Description string
|
Description string
|
||||||
CompletedUnix int64
|
CompletedUnix int64
|
||||||
Organizer *models.User
|
Organizer *user.User
|
||||||
Priority int64 // 0-9, 1 is highest
|
Priority int64 // 0-9, 1 is highest
|
||||||
RelatedToUID string
|
RelatedToUID string
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
migrator "code.vikunja.io/api/pkg/modules/migration"
|
migrator "code.vikunja.io/api/pkg/modules/migration"
|
||||||
"code.vikunja.io/api/pkg/red"
|
"code.vikunja.io/api/pkg/red"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"os"
|
"os"
|
||||||
|
@ -76,6 +77,10 @@ func initialize() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
err = user.InitDB()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err.Error())
|
||||||
|
}
|
||||||
err = files.SetEngine()
|
err = files.SetEngine()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err.Error())
|
log.Fatal(err.Error())
|
||||||
|
|
28
pkg/db/db.go
28
pkg/db/db.go
|
@ -23,7 +23,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-xorm/core"
|
"github.com/go-xorm/core"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -85,33 +84,6 @@ func CreateDBEngine() (engine *xorm.Engine, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTestEngine creates an instance of the db engine which lives in memory
|
|
||||||
func CreateTestEngine() (engine *xorm.Engine, err error) {
|
|
||||||
|
|
||||||
if x != nil {
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.Getenv("VIKUNJA_TESTS_USE_CONFIG") == "1" {
|
|
||||||
config.InitConfig()
|
|
||||||
engine, err = CreateDBEngine()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
engine, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
engine.SetMapper(core.GonicMapper{})
|
|
||||||
engine.ShowSQL(os.Getenv("UNIT_TESTS_VERBOSE") == "1")
|
|
||||||
engine.SetLogger(xorm.NewSimpleLogger(log.GetLogWriter("database")))
|
|
||||||
x = engine
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterTableStructsForCache registers tables in gob encoding for redis cache
|
// RegisterTableStructsForCache registers tables in gob encoding for redis cache
|
||||||
func RegisterTableStructsForCache(val interface{}) {
|
func RegisterTableStructsForCache(val interface{}) {
|
||||||
gob.Register(val)
|
gob.Register(val)
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is part of Vikunja.
|
||||||
|
//
|
||||||
|
// Vikunja is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Vikunja is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/config"
|
||||||
|
"code.vikunja.io/api/pkg/log"
|
||||||
|
"github.com/go-xorm/core"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateTestEngine creates an instance of the db engine which lives in memory
|
||||||
|
func CreateTestEngine() (engine *xorm.Engine, err error) {
|
||||||
|
|
||||||
|
if x != nil {
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.Getenv("VIKUNJA_TESTS_USE_CONFIG") == "1" {
|
||||||
|
config.InitConfig()
|
||||||
|
engine, err = CreateDBEngine()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
engine, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
engine.SetMapper(core.GonicMapper{})
|
||||||
|
engine.ShowSQL(os.Getenv("UNIT_TESTS_VERBOSE") == "1")
|
||||||
|
engine.SetLogger(xorm.NewSimpleLogger(log.GetLogWriter("database")))
|
||||||
|
x = engine
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitTestFixtures populates the db with all fixtures from the fixtures folder
|
||||||
|
func InitTestFixtures(tablenames ...string) (err error) {
|
||||||
|
// Create all fixtures
|
||||||
|
config.InitDefaultConfig()
|
||||||
|
// We need to set the root path even if we're not using the config, otherwise fixtures are not loaded correctly
|
||||||
|
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
||||||
|
|
||||||
|
// Sync fixtures
|
||||||
|
err = InitFixtures(tablenames...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -18,15 +18,36 @@
|
||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/config"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/testfixtures.v2"
|
"gopkg.in/testfixtures.v2"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
var fixtures *testfixtures.Context
|
var fixtures *testfixtures.Context
|
||||||
|
|
||||||
// InitFixtures initialize test fixtures for a test database
|
// InitFixtures initialize test fixtures for a test database
|
||||||
func InitFixtures(helper testfixtures.Helper, dir string) (err error) {
|
func InitFixtures(tablenames ...string) (err error) {
|
||||||
|
|
||||||
|
var helper testfixtures.Helper = &testfixtures.SQLite{}
|
||||||
|
if config.DatabaseType.GetString() == "mysql" {
|
||||||
|
helper = &testfixtures.MySQL{}
|
||||||
|
}
|
||||||
|
dir := filepath.Join(config.ServiceRootpath.GetString(), "pkg", "db", "fixtures")
|
||||||
|
|
||||||
testfixtures.SkipDatabaseNameCheck(true)
|
testfixtures.SkipDatabaseNameCheck(true)
|
||||||
fixtures, err = testfixtures.NewFolder(x.DB().DB, helper, dir)
|
|
||||||
|
// If fixture table names are specified, load them
|
||||||
|
// Otherwise, load all fixtures
|
||||||
|
if len(tablenames) > 0 {
|
||||||
|
for i, name := range tablenames {
|
||||||
|
tablenames[i] = filepath.Join(dir, name+".yml")
|
||||||
|
}
|
||||||
|
fixtures, err = testfixtures.NewFiles(x.DB().DB, helper, tablenames...)
|
||||||
|
} else {
|
||||||
|
fixtures, err = testfixtures.NewFolder(x.DB().DB, helper, dir)
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,3 +55,9 @@ func InitFixtures(helper testfixtures.Helper, dir string) (err error) {
|
||||||
func LoadFixtures() error {
|
func LoadFixtures() error {
|
||||||
return fixtures.Load()
|
return fixtures.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadAndAssertFixtures loads all fixtures defined before and asserts they are correctly loaded
|
||||||
|
func LoadAndAssertFixtures(t *testing.T) {
|
||||||
|
err := LoadFixtures()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
|
@ -22,9 +22,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"gopkg.in/testfixtures.v2"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,10 +43,9 @@ func InitTestFileHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initFixtures(t *testing.T) {
|
func initFixtures(t *testing.T) {
|
||||||
// Init db fixtures
|
// DB fixtures
|
||||||
err := db.LoadFixtures()
|
db.LoadAndAssertFixtures(t)
|
||||||
assert.NoError(t, err)
|
// File fixtures
|
||||||
|
|
||||||
InitTestFileFixtures(t)
|
InitTestFileFixtures(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,17 +70,7 @@ func InitTests() {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.InitDefaultConfig()
|
err = db.InitTestFixtures("files")
|
||||||
// We need to set the root path even if we're not using the config, otherwise fixtures are not loaded correctly
|
|
||||||
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
|
||||||
|
|
||||||
// Sync fixtures
|
|
||||||
var fixturesHelper testfixtures.Helper = &testfixtures.SQLite{}
|
|
||||||
if config.DatabaseType.GetString() == "mysql" {
|
|
||||||
fixturesHelper = &testfixtures.MySQL{}
|
|
||||||
}
|
|
||||||
fixturesDir := filepath.Join(config.ServiceRootpath.GetString(), "pkg", "files", "fixtures")
|
|
||||||
err = db.InitFixtures(fixturesHelper, fixturesDir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
"code.vikunja.io/api/pkg/routes"
|
"code.vikunja.io/api/pkg/routes"
|
||||||
v1 "code.vikunja.io/api/pkg/routes/api/v1"
|
v1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
@ -38,34 +39,34 @@ import (
|
||||||
|
|
||||||
// These are the test users, the same way they are in the test database
|
// These are the test users, the same way they are in the test database
|
||||||
var (
|
var (
|
||||||
testuser1 = models.User{
|
testuser1 = user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
Email: "user1@example.com",
|
Email: "user1@example.com",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
}
|
}
|
||||||
testuser2 = models.User{
|
testuser2 = user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
Email: "user2@example.com",
|
Email: "user2@example.com",
|
||||||
}
|
}
|
||||||
testuser3 = models.User{
|
testuser3 = user.User{
|
||||||
ID: 3,
|
ID: 3,
|
||||||
Username: "user3",
|
Username: "user3",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
Email: "user3@example.com",
|
Email: "user3@example.com",
|
||||||
PasswordResetToken: "passwordresettesttoken",
|
PasswordResetToken: "passwordresettesttoken",
|
||||||
}
|
}
|
||||||
testuser4 = models.User{
|
testuser4 = user.User{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Username: "user4",
|
Username: "user4",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
Email: "user4@example.com",
|
Email: "user4@example.com",
|
||||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||||
}
|
}
|
||||||
testuser5 = models.User{
|
testuser5 = user.User{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Username: "user5",
|
Username: "user5",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -81,7 +82,8 @@ func setupTestEnv() (e *echo.Echo, err error) {
|
||||||
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
||||||
// Some tests use the file engine, so we'll need to initialize that
|
// Some tests use the file engine, so we'll need to initialize that
|
||||||
files.InitTests()
|
files.InitTests()
|
||||||
models.SetupTests(config.ServiceRootpath.GetString())
|
user.InitTests()
|
||||||
|
models.SetupTests()
|
||||||
|
|
||||||
err = db.LoadFixtures()
|
err = db.LoadFixtures()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -114,7 +116,7 @@ func newTestRequest(t *testing.T, method string, handler func(ctx echo.Context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func addUserTokenToContext(t *testing.T, user *models.User, c echo.Context) {
|
func addUserTokenToContext(t *testing.T, user *user.User, c echo.Context) {
|
||||||
// Get the token as a string
|
// Get the token as a string
|
||||||
token, err := v1.NewUserJWTAuthtoken(user)
|
token, err := v1.NewUserJWTAuthtoken(user)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -152,7 +154,7 @@ func testRequestSetup(t *testing.T, method string, payload string, queryParams u
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestRequestWithUser(t *testing.T, method string, handler echo.HandlerFunc, user *models.User, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
func newTestRequestWithUser(t *testing.T, method string, handler echo.HandlerFunc, user *user.User, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
|
||||||
rec, c := testRequestSetup(t, method, payload, queryParams, urlParams)
|
rec, c := testRequestSetup(t, method, payload, queryParams, urlParams)
|
||||||
addUserTokenToContext(t, user, c)
|
addUserTokenToContext(t, user, c)
|
||||||
err = handler(c)
|
err = handler(c)
|
||||||
|
@ -185,7 +187,7 @@ func assertHandlerErrorCode(t *testing.T, err error, expectedErrorCode int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type webHandlerTest struct {
|
type webHandlerTest struct {
|
||||||
user *models.User
|
user *user.User
|
||||||
linkShare *models.LinkSharing
|
linkShare *models.LinkSharing
|
||||||
strFunc func() handler.CObject
|
strFunc func() handler.CObject
|
||||||
t *testing.T
|
t *testing.T
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -36,7 +36,7 @@ func TestLogin(t *testing.T) {
|
||||||
t.Run("Empty payload", func(t *testing.T) {
|
t.Run("Empty payload", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Not existing user", func(t *testing.T) {
|
t.Run("Not existing user", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
||||||
|
@ -44,7 +44,7 @@ func TestLogin(t *testing.T) {
|
||||||
"password": "1234"
|
"password": "1234"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeWrongUsernameOrPassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeWrongUsernameOrPassword)
|
||||||
})
|
})
|
||||||
t.Run("Wrong password", func(t *testing.T) {
|
t.Run("Wrong password", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
||||||
|
@ -52,7 +52,7 @@ func TestLogin(t *testing.T) {
|
||||||
"password": "wrong"
|
"password": "wrong"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeWrongUsernameOrPassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeWrongUsernameOrPassword)
|
||||||
})
|
})
|
||||||
t.Run("user with unconfirmed email", func(t *testing.T) {
|
t.Run("user with unconfirmed email", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
||||||
|
@ -60,6 +60,6 @@ func TestLogin(t *testing.T) {
|
||||||
"password": "1234"
|
"password": "1234"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeEmailNotConfirmed)
|
assertHandlerErrorCode(t, err, user.ErrCodeEmailNotConfirmed)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -37,7 +37,7 @@ func TestRegister(t *testing.T) {
|
||||||
t.Run("Empty payload", func(t *testing.T) {
|
t.Run("Empty payload", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Empty username", func(t *testing.T) {
|
t.Run("Empty username", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||||
|
@ -46,7 +46,7 @@ func TestRegister(t *testing.T) {
|
||||||
"email": "email@example.com"
|
"email": "email@example.com"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Empty password", func(t *testing.T) {
|
t.Run("Empty password", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||||
|
@ -55,7 +55,7 @@ func TestRegister(t *testing.T) {
|
||||||
"email": "email@example.com"
|
"email": "email@example.com"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Empty email", func(t *testing.T) {
|
t.Run("Empty email", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||||
|
@ -64,7 +64,7 @@ func TestRegister(t *testing.T) {
|
||||||
"email": ""
|
"email": ""
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Already existing username", func(t *testing.T) {
|
t.Run("Already existing username", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||||
|
@ -73,7 +73,7 @@ func TestRegister(t *testing.T) {
|
||||||
"email": "email@example.com"
|
"email": "email@example.com"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrorCodeUsernameExists)
|
assertHandlerErrorCode(t, err, user.ErrorCodeUsernameExists)
|
||||||
})
|
})
|
||||||
t.Run("Already existing email", func(t *testing.T) {
|
t.Run("Already existing email", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||||
|
@ -82,6 +82,6 @@ func TestRegister(t *testing.T) {
|
||||||
"email": "user1@example.com"
|
"email": "user1@example.com"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrorCodeUserEmailExists)
|
assertHandlerErrorCode(t, err, user.ErrorCodeUserEmailExists)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -39,7 +39,7 @@ func TestUserChangePassword(t *testing.T) {
|
||||||
"old_password": "invalid"
|
"old_password": "invalid"
|
||||||
}`, nil, nil)
|
}`, nil, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeWrongUsernameOrPassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeWrongUsernameOrPassword)
|
||||||
})
|
})
|
||||||
t.Run("Empty old password", func(t *testing.T) {
|
t.Run("Empty old password", func(t *testing.T) {
|
||||||
_, err := newTestRequestWithUser(t, http.MethodPost, apiv1.UserChangePassword, &testuser1, `{
|
_, err := newTestRequestWithUser(t, http.MethodPost, apiv1.UserChangePassword, &testuser1, `{
|
||||||
|
@ -47,7 +47,7 @@ func TestUserChangePassword(t *testing.T) {
|
||||||
"old_password": ""
|
"old_password": ""
|
||||||
}`, nil, nil)
|
}`, nil, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeEmptyOldPassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeEmptyOldPassword)
|
||||||
})
|
})
|
||||||
t.Run("Empty new password", func(t *testing.T) {
|
t.Run("Empty new password", func(t *testing.T) {
|
||||||
_, err := newTestRequestWithUser(t, http.MethodPost, apiv1.UserChangePassword, &testuser1, `{
|
_, err := newTestRequestWithUser(t, http.MethodPost, apiv1.UserChangePassword, &testuser1, `{
|
||||||
|
@ -55,6 +55,6 @@ func TestUserChangePassword(t *testing.T) {
|
||||||
"old_password": "1234"
|
"old_password": "1234"
|
||||||
}`, nil, nil)
|
}`, nil, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeEmptyNewPassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeEmptyNewPassword)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -35,16 +35,16 @@ func TestUserConfirmEmail(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, http.StatusPreconditionFailed, err.(*echo.HTTPError).Code)
|
assert.Equal(t, http.StatusPreconditionFailed, err.(*echo.HTTPError).Code)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidEmailConfirmToken)
|
assertHandlerErrorCode(t, err, user.ErrCodeInvalidEmailConfirmToken)
|
||||||
})
|
})
|
||||||
t.Run("Empty token", func(t *testing.T) {
|
t.Run("Empty token", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{"token": ""}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{"token": ""}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidEmailConfirmToken)
|
assertHandlerErrorCode(t, err, user.ErrCodeInvalidEmailConfirmToken)
|
||||||
})
|
})
|
||||||
t.Run("Invalid token", func(t *testing.T) {
|
t.Run("Invalid token", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{"token": "invalidToken"}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{"token": "invalidToken"}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidEmailConfirmToken)
|
assertHandlerErrorCode(t, err, user.ErrCodeInvalidEmailConfirmToken)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -34,7 +34,7 @@ func TestUserRequestResetPasswordToken(t *testing.T) {
|
||||||
t.Run("Empty payload", func(t *testing.T) {
|
t.Run("Empty payload", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Invalid email address", func(t *testing.T) {
|
t.Run("Invalid email address", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{"email": "user1example.com"}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{"email": "user1example.com"}`)
|
||||||
|
@ -44,6 +44,6 @@ func TestUserRequestResetPasswordToken(t *testing.T) {
|
||||||
t.Run("No user with that email address", func(t *testing.T) {
|
t.Run("No user with that email address", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{"email": "user1000@example.com"}`)
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{"email": "user1000@example.com"}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeUserDoesNotExist)
|
assertHandlerErrorCode(t, err, user.ErrCodeUserDoesNotExist)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -45,7 +45,7 @@ func TestUserPasswordReset(t *testing.T) {
|
||||||
"token": "passwordresettesttoken"
|
"token": "passwordresettesttoken"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||||
})
|
})
|
||||||
t.Run("Invalid password reset token", func(t *testing.T) {
|
t.Run("Invalid password reset token", func(t *testing.T) {
|
||||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserResetPassword, `{
|
_, err := newTestRequest(t, http.MethodPost, apiv1.UserResetPassword, `{
|
||||||
|
@ -53,6 +53,6 @@ func TestUserPasswordReset(t *testing.T) {
|
||||||
"token": "invalidtoken"
|
"token": "invalidtoken"
|
||||||
}`)
|
}`)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidPasswordResetToken)
|
assertHandlerErrorCode(t, err, user.ErrCodeInvalidPasswordResetToken)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import (
|
||||||
"code.vikunja.io/api/pkg/files"
|
"code.vikunja.io/api/pkg/files"
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/modules/migration"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"os"
|
"os"
|
||||||
|
@ -138,5 +140,7 @@ func initSchema(tx *xorm.Engine) error {
|
||||||
schemeBeans := []interface{}{}
|
schemeBeans := []interface{}{}
|
||||||
schemeBeans = append(schemeBeans, models.GetTables()...)
|
schemeBeans = append(schemeBeans, models.GetTables()...)
|
||||||
schemeBeans = append(schemeBeans, files.GetTables()...)
|
schemeBeans = append(schemeBeans, files.GetTables()...)
|
||||||
|
schemeBeans = append(schemeBeans, migration.GetTables()...)
|
||||||
|
schemeBeans = append(schemeBeans, user.GetTables()...)
|
||||||
return tx.Sync2(schemeBeans...)
|
return tx.Sync2(schemeBeans...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -9,7 +11,7 @@ func TestBulkTask_Update(t *testing.T) {
|
||||||
IDs []int64
|
IDs []int64
|
||||||
Tasks []*Task
|
Tasks []*Task
|
||||||
Task Task
|
Task Task
|
||||||
User *User
|
User *user.User
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -24,7 +26,7 @@ func TestBulkTask_Update(t *testing.T) {
|
||||||
Task: Task{
|
Task: Task{
|
||||||
Text: "bulkupdated",
|
Text: "bulkupdated",
|
||||||
},
|
},
|
||||||
User: &User{ID: 1},
|
User: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -34,7 +36,7 @@ func TestBulkTask_Update(t *testing.T) {
|
||||||
Task: Task{
|
Task: Task{
|
||||||
Text: "bulkupdated",
|
Text: "bulkupdated",
|
||||||
},
|
},
|
||||||
User: &User{ID: 1},
|
User: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
|
@ -45,13 +47,15 @@ func TestBulkTask_Update(t *testing.T) {
|
||||||
Task: Task{
|
Task: Task{
|
||||||
Text: "bulkupdated",
|
Text: "bulkupdated",
|
||||||
},
|
},
|
||||||
User: &User{ID: 1},
|
User: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
bt := &BulkTask{
|
bt := &BulkTask{
|
||||||
IDs: tt.fields.IDs,
|
IDs: tt.fields.IDs,
|
||||||
Tasks: tt.fields.Tasks,
|
Tasks: tt.fields.Tasks,
|
||||||
|
|
|
@ -46,273 +46,6 @@ func (err ErrGenericForbidden) HTTPError() web.HTTPError {
|
||||||
return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrorCodeGenericForbidden, Message: "You're not allowed to do this."}
|
return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrorCodeGenericForbidden, Message: "You're not allowed to do this."}
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================
|
|
||||||
// User Operation Errors
|
|
||||||
// =====================
|
|
||||||
|
|
||||||
// ErrUsernameExists represents a "UsernameAlreadyExists" kind of error.
|
|
||||||
type ErrUsernameExists struct {
|
|
||||||
UserID int64
|
|
||||||
Username string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrUsernameExists checks if an error is a ErrUsernameExists.
|
|
||||||
func IsErrUsernameExists(err error) bool {
|
|
||||||
_, ok := err.(ErrUsernameExists)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrUsernameExists) Error() string {
|
|
||||||
return fmt.Sprintf("User with that username already exists [user id: %d, username: %s]", err.UserID, err.Username)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorCodeUsernameExists holds the unique world-error code of this error
|
|
||||||
const ErrorCodeUsernameExists = 1001
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrUsernameExists) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUsernameExists, Message: "A user with this username already exists."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUserEmailExists represents a "UserEmailExists" kind of error.
|
|
||||||
type ErrUserEmailExists struct {
|
|
||||||
UserID int64
|
|
||||||
Email string
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrUserEmailExists checks if an error is a ErrUserEmailExists.
|
|
||||||
func IsErrUserEmailExists(err error) bool {
|
|
||||||
_, ok := err.(ErrUserEmailExists)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrUserEmailExists) Error() string {
|
|
||||||
return fmt.Sprintf("User with that email already exists [user id: %d, email: %s]", err.UserID, err.Email)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorCodeUserEmailExists holds the unique world-error code of this error
|
|
||||||
const ErrorCodeUserEmailExists = 1002
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrUserEmailExists) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUserEmailExists, Message: "A user with this email address already exists."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNoUsernamePassword represents a "NoUsernamePassword" kind of error.
|
|
||||||
type ErrNoUsernamePassword struct{}
|
|
||||||
|
|
||||||
// IsErrNoUsernamePassword checks if an error is a ErrNoUsernamePassword.
|
|
||||||
func IsErrNoUsernamePassword(err error) bool {
|
|
||||||
_, ok := err.(ErrNoUsernamePassword)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrNoUsernamePassword) Error() string {
|
|
||||||
return fmt.Sprintf("No username and password provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeNoUsernamePassword holds the unique world-error code of this error
|
|
||||||
const ErrCodeNoUsernamePassword = 1004
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrNoUsernamePassword) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeNoUsernamePassword, Message: "Please specify a username and a password."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrUserDoesNotExist represents a "UserDoesNotExist" kind of error.
|
|
||||||
type ErrUserDoesNotExist struct {
|
|
||||||
UserID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrUserDoesNotExist checks if an error is a ErrUserDoesNotExist.
|
|
||||||
func IsErrUserDoesNotExist(err error) bool {
|
|
||||||
_, ok := err.(ErrUserDoesNotExist)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrUserDoesNotExist) Error() string {
|
|
||||||
return fmt.Sprintf("User does not exist [user id: %d]", err.UserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeUserDoesNotExist holds the unique world-error code of this error
|
|
||||||
const ErrCodeUserDoesNotExist = 1005
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrUserDoesNotExist) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeUserDoesNotExist, Message: "The user does not exist."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCouldNotGetUserID represents a "ErrCouldNotGetUserID" kind of error.
|
|
||||||
type ErrCouldNotGetUserID struct{}
|
|
||||||
|
|
||||||
// IsErrCouldNotGetUserID checks if an error is a ErrCouldNotGetUserID.
|
|
||||||
func IsErrCouldNotGetUserID(err error) bool {
|
|
||||||
_, ok := err.(ErrCouldNotGetUserID)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrCouldNotGetUserID) Error() string {
|
|
||||||
return fmt.Sprintf("Could not get user ID")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeCouldNotGetUserID holds the unique world-error code of this error
|
|
||||||
const ErrCodeCouldNotGetUserID = 1006
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrCouldNotGetUserID) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeCouldNotGetUserID, Message: "Could not get user id."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrNoPasswordResetToken represents an error where no password reset token exists for that user
|
|
||||||
type ErrNoPasswordResetToken struct {
|
|
||||||
UserID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrNoPasswordResetToken) Error() string {
|
|
||||||
return fmt.Sprintf("No token to reset a password [UserID: %d]", err.UserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeNoPasswordResetToken holds the unique world-error code of this error
|
|
||||||
const ErrCodeNoPasswordResetToken = 1008
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrNoPasswordResetToken) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeNoPasswordResetToken, Message: "No token to reset a user's password provided."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrInvalidPasswordResetToken is an error where the password reset token is invalid
|
|
||||||
type ErrInvalidPasswordResetToken struct {
|
|
||||||
Token string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrInvalidPasswordResetToken) Error() string {
|
|
||||||
return fmt.Sprintf("Invalid token to reset a password [Token: %s]", err.Token)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeInvalidPasswordResetToken holds the unique world-error code of this error
|
|
||||||
const ErrCodeInvalidPasswordResetToken = 1009
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrInvalidPasswordResetToken) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidPasswordResetToken, Message: "Invalid token to reset a user's password."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrInvalidPasswordResetToken checks if an error is a ErrInvalidPasswordResetToken.
|
|
||||||
func IsErrInvalidPasswordResetToken(err error) bool {
|
|
||||||
_, ok := err.(ErrInvalidPasswordResetToken)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrInvalidEmailConfirmToken is an error where the email confirm token is invalid
|
|
||||||
type ErrInvalidEmailConfirmToken struct {
|
|
||||||
Token string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrInvalidEmailConfirmToken) Error() string {
|
|
||||||
return fmt.Sprintf("Invalid email confirm token [Token: %s]", err.Token)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeInvalidEmailConfirmToken holds the unique world-error code of this error
|
|
||||||
const ErrCodeInvalidEmailConfirmToken = 1010
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrInvalidEmailConfirmToken) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidEmailConfirmToken, Message: "Invalid email confirm token."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrInvalidEmailConfirmToken checks if an error is a ErrInvalidEmailConfirmToken.
|
|
||||||
func IsErrInvalidEmailConfirmToken(err error) bool {
|
|
||||||
_, ok := err.(ErrInvalidEmailConfirmToken)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrWrongUsernameOrPassword is an error where the email was not confirmed
|
|
||||||
type ErrWrongUsernameOrPassword struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrWrongUsernameOrPassword) Error() string {
|
|
||||||
return fmt.Sprintf("Wrong username or password")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeWrongUsernameOrPassword holds the unique world-error code of this error
|
|
||||||
const ErrCodeWrongUsernameOrPassword = 1011
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrWrongUsernameOrPassword) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeWrongUsernameOrPassword, Message: "Wrong username or password."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrWrongUsernameOrPassword checks if an error is a IsErrEmailNotConfirmed.
|
|
||||||
func IsErrWrongUsernameOrPassword(err error) bool {
|
|
||||||
_, ok := err.(ErrWrongUsernameOrPassword)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrEmailNotConfirmed is an error where the email was not confirmed
|
|
||||||
type ErrEmailNotConfirmed struct {
|
|
||||||
UserID int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrEmailNotConfirmed) Error() string {
|
|
||||||
return fmt.Sprintf("Email is not confirmed [UserID: %d]", err.UserID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeEmailNotConfirmed holds the unique world-error code of this error
|
|
||||||
const ErrCodeEmailNotConfirmed = 1012
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrEmailNotConfirmed) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmailNotConfirmed, Message: "Please confirm your email address."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsErrEmailNotConfirmed checks if an error is a IsErrEmailNotConfirmed.
|
|
||||||
func IsErrEmailNotConfirmed(err error) bool {
|
|
||||||
_, ok := err.(ErrEmailNotConfirmed)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrEmptyNewPassword represents a "EmptyNewPassword" kind of error.
|
|
||||||
type ErrEmptyNewPassword struct{}
|
|
||||||
|
|
||||||
// IsErrEmptyNewPassword checks if an error is a ErrEmptyNewPassword.
|
|
||||||
func IsErrEmptyNewPassword(err error) bool {
|
|
||||||
_, ok := err.(ErrEmptyNewPassword)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrEmptyNewPassword) Error() string {
|
|
||||||
return fmt.Sprintf("New password is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeEmptyNewPassword holds the unique world-error code of this error
|
|
||||||
const ErrCodeEmptyNewPassword = 1013
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrEmptyNewPassword) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyNewPassword, Message: "Please specify new password."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrEmptyOldPassword represents a "EmptyOldPassword" kind of error.
|
|
||||||
type ErrEmptyOldPassword struct{}
|
|
||||||
|
|
||||||
// IsErrEmptyOldPassword checks if an error is a ErrEmptyOldPassword.
|
|
||||||
func IsErrEmptyOldPassword(err error) bool {
|
|
||||||
_, ok := err.(ErrEmptyOldPassword)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (err ErrEmptyOldPassword) Error() string {
|
|
||||||
return fmt.Sprintf("Old password is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrCodeEmptyOldPassword holds the unique world-error code of this error
|
|
||||||
const ErrCodeEmptyOldPassword = 1014
|
|
||||||
|
|
||||||
// HTTPError holds the http error description
|
|
||||||
func (err ErrEmptyOldPassword) HTTPError() web.HTTPError {
|
|
||||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyOldPassword, Message: "Please specify old password."}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================
|
// ===================
|
||||||
// Empty things errors
|
// Empty things errors
|
||||||
// ===================
|
// ===================
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../../files/fixtures/files.yml
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -34,7 +35,7 @@ type Label struct {
|
||||||
|
|
||||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||||
// The user who created this label
|
// The user who created this label
|
||||||
CreatedBy *User `xorm:"-" json:"created_by"`
|
CreatedBy *user.User `xorm:"-" json:"created_by"`
|
||||||
|
|
||||||
// A unix timestamp when this label was created. You cannot change this value.
|
// A unix timestamp when this label was created. You cannot change this value.
|
||||||
Created int64 `xorm:"created not null" json:"created"`
|
Created int64 `xorm:"created not null" json:"created"`
|
||||||
|
@ -63,7 +64,7 @@ func (Label) TableName() string {
|
||||||
// @Failure 500 {object} models.Message "Internal error"
|
// @Failure 500 {object} models.Message "Internal error"
|
||||||
// @Router /labels [put]
|
// @Router /labels [put]
|
||||||
func (l *Label) Create(a web.Auth) (err error) {
|
func (l *Label) Create(a web.Auth) (err error) {
|
||||||
u, err := getUserWithError(a)
|
u, err := user.GetFromAuth(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -136,7 +137,7 @@ func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls in
|
||||||
return nil, 0, 0, ErrGenericForbidden{}
|
return nil, 0, 0, ErrGenericForbidden{}
|
||||||
}
|
}
|
||||||
|
|
||||||
u := &User{ID: a.GetID()}
|
u := &user.User{ID: a.GetID()}
|
||||||
|
|
||||||
// Get all tasks
|
// Get all tasks
|
||||||
taskIDs, err := getUserTaskIDs(u)
|
taskIDs, err := getUserTaskIDs(u)
|
||||||
|
@ -175,7 +176,7 @@ func (l *Label) ReadOne() (err error) {
|
||||||
}
|
}
|
||||||
*l = *label
|
*l = *label
|
||||||
|
|
||||||
user, err := GetUserByID(l.CreatedByID)
|
user, err := user.GetUserByID(l.CreatedByID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -198,7 +199,7 @@ func getLabelByIDSimple(labelID int64) (*Label, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to get all task ids a user has
|
// Helper method to get all task ids a user has
|
||||||
func getUserTaskIDs(u *User) (taskIDs []int64, err error) {
|
func getUserTaskIDs(u *user.User) (taskIDs []int64, err error) {
|
||||||
|
|
||||||
// Get all lists
|
// Get all lists
|
||||||
lists, _, _, err := getRawListsForUser("", u, -1, 0)
|
lists, _, _, err := getRawListsForUser("", u, -1, 0)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
)
|
)
|
||||||
|
@ -65,7 +66,7 @@ func (l *Label) hasAccessToLabel(a web.Auth) (bool, error) {
|
||||||
// TODO: add an extra check for link share handling
|
// TODO: add an extra check for link share handling
|
||||||
|
|
||||||
// Get all tasks
|
// Get all tasks
|
||||||
taskIDs, err := getUserTaskIDs(&User{ID: a.GetID()})
|
taskIDs, err := getUserTaskIDs(&user.User{ID: a.GetID()})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
)
|
)
|
||||||
|
@ -120,7 +121,7 @@ func (lt *LabelTask) ReadAll(a web.Auth, search string, page int, perPage int) (
|
||||||
}
|
}
|
||||||
|
|
||||||
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||||
User: &User{ID: a.GetID()},
|
User: &user.User{ID: a.GetID()},
|
||||||
Search: search,
|
Search: search,
|
||||||
Page: page,
|
Page: page,
|
||||||
TaskIDs: []int64{lt.TaskID},
|
TaskIDs: []int64{lt.TaskID},
|
||||||
|
@ -135,7 +136,7 @@ type labelWithTaskID struct {
|
||||||
|
|
||||||
// LabelByTaskIDsOptions is a struct to not clutter the function with too many optional parameters.
|
// LabelByTaskIDsOptions is a struct to not clutter the function with too many optional parameters.
|
||||||
type LabelByTaskIDsOptions struct {
|
type LabelByTaskIDsOptions struct {
|
||||||
User *User
|
User *user.User
|
||||||
Search string
|
Search string
|
||||||
Page int
|
Page int
|
||||||
PerPage int
|
PerPage int
|
||||||
|
@ -185,7 +186,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
||||||
for _, l := range labels {
|
for _, l := range labels {
|
||||||
userids = append(userids, l.CreatedByID)
|
userids = append(userids, l.CreatedByID)
|
||||||
}
|
}
|
||||||
users := make(map[int64]*User)
|
users := make(map[int64]*user.User)
|
||||||
err = x.In("id", userids).Find(&users)
|
err = x.In("id", userids).Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
|
@ -290,7 +291,7 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !hasAccessToLabel {
|
if !hasAccessToLabel {
|
||||||
user, _ := creator.(*User)
|
user, _ := creator.(*user.User)
|
||||||
return ErrUserHasNoAccessToLabel{LabelID: l.ID, UserID: user.ID}
|
return ErrUserHasNoAccessToLabel{LabelID: l.ID, UserID: user.ID}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"gopkg.in/d4l3k/messagediff.v1"
|
"gopkg.in/d4l3k/messagediff.v1"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -37,7 +39,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantLabels: []*labelWithTaskID{
|
wantLabels: []*labelWithTaskID{
|
||||||
{
|
{
|
||||||
|
@ -46,7 +48,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Title: "Label #4 - visible via other task",
|
Title: "Label #4 - visible via other task",
|
||||||
CreatedByID: 2,
|
CreatedByID: 2,
|
||||||
CreatedBy: &User{
|
CreatedBy: &user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -62,7 +64,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||||
TaskID: 14,
|
TaskID: 14,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrNoRightToSeeTask,
|
errType: IsErrNoRightToSeeTask,
|
||||||
|
@ -73,7 +75,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||||
TaskID: 9999,
|
TaskID: 9999,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrTaskDoesNotExist,
|
errType: IsErrTaskDoesNotExist,
|
||||||
|
@ -81,6 +83,8 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
l := &LabelTask{
|
l := &LabelTask{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
TaskID: tt.fields.TaskID,
|
TaskID: tt.fields.TaskID,
|
||||||
|
@ -131,17 +135,17 @@ func TestLabelTask_Create(t *testing.T) {
|
||||||
LabelID: 1,
|
LabelID: 1,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "already existing",
|
name: "already existing",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
LabelID: 1,
|
LabelID: 4,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrLabelIsAlreadyOnTask,
|
errType: IsErrLabelIsAlreadyOnTask,
|
||||||
|
@ -153,7 +157,7 @@ func TestLabelTask_Create(t *testing.T) {
|
||||||
LabelID: 9999,
|
LabelID: 9999,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
|
@ -164,7 +168,7 @@ func TestLabelTask_Create(t *testing.T) {
|
||||||
LabelID: 1,
|
LabelID: 1,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
|
@ -173,6 +177,8 @@ func TestLabelTask_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
l := &LabelTask{
|
l := &LabelTask{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
TaskID: tt.fields.TaskID,
|
TaskID: tt.fields.TaskID,
|
||||||
|
@ -217,9 +223,9 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||||
name: "normal",
|
name: "normal",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
LabelID: 1,
|
LabelID: 4,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "delete nonexistant",
|
name: "delete nonexistant",
|
||||||
|
@ -227,7 +233,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
LabelID: 1,
|
LabelID: 1,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -236,7 +242,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
LabelID: 9999,
|
LabelID: 9999,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -245,7 +251,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||||
TaskID: 9999,
|
TaskID: 9999,
|
||||||
LabelID: 1,
|
LabelID: 1,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -254,12 +260,14 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||||
TaskID: 14,
|
TaskID: 14,
|
||||||
LabelID: 1,
|
LabelID: 1,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
l := &LabelTask{
|
l := &LabelTask{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
TaskID: tt.fields.TaskID,
|
TaskID: tt.fields.TaskID,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"gopkg.in/d4l3k/messagediff.v1"
|
"gopkg.in/d4l3k/messagediff.v1"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -32,7 +33,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||||
Description string
|
Description string
|
||||||
HexColor string
|
HexColor string
|
||||||
CreatedByID int64
|
CreatedByID int64
|
||||||
CreatedBy *User
|
CreatedBy *user.User
|
||||||
Created int64
|
Created int64
|
||||||
Updated int64
|
Updated int64
|
||||||
CRUDable web.CRUDable
|
CRUDable web.CRUDable
|
||||||
|
@ -43,7 +44,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||||
a web.Auth
|
a web.Auth
|
||||||
page int
|
page int
|
||||||
}
|
}
|
||||||
user1 := &User{
|
user1 := &user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -60,7 +61,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "normal",
|
name: "normal",
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
wantLs: []*labelWithTaskID{
|
wantLs: []*labelWithTaskID{
|
||||||
{
|
{
|
||||||
|
@ -85,7 +86,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Title: "Label #4 - visible via other task",
|
Title: "Label #4 - visible via other task",
|
||||||
CreatedByID: 2,
|
CreatedByID: 2,
|
||||||
CreatedBy: &User{
|
CreatedBy: &user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -98,7 +99,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "invalid user",
|
name: "invalid user",
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: -1},
|
a: &user.User{ID: -1},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
@ -136,13 +137,13 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||||
Description string
|
Description string
|
||||||
HexColor string
|
HexColor string
|
||||||
CreatedByID int64
|
CreatedByID int64
|
||||||
CreatedBy *User
|
CreatedBy *user.User
|
||||||
Created int64
|
Created int64
|
||||||
Updated int64
|
Updated int64
|
||||||
CRUDable web.CRUDable
|
CRUDable web.CRUDable
|
||||||
Rights web.Rights
|
Rights web.Rights
|
||||||
}
|
}
|
||||||
user1 := &User{
|
user1 := &user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -169,7 +170,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||||
CreatedByID: 1,
|
CreatedByID: 1,
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Get nonexistant label",
|
name: "Get nonexistant label",
|
||||||
|
@ -179,7 +180,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrLabelDoesNotExist,
|
errType: IsErrLabelDoesNotExist,
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "no rights",
|
name: "no rights",
|
||||||
|
@ -187,7 +188,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||||
ID: 3,
|
ID: 3,
|
||||||
},
|
},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Get label #4 - other user",
|
name: "Get label #4 - other user",
|
||||||
|
@ -198,14 +199,14 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Title: "Label #4 - visible via other task",
|
Title: "Label #4 - visible via other task",
|
||||||
CreatedByID: 2,
|
CreatedByID: 2,
|
||||||
CreatedBy: &User{
|
CreatedBy: &user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
@ -248,7 +249,7 @@ func TestLabel_Create(t *testing.T) {
|
||||||
Description string
|
Description string
|
||||||
HexColor string
|
HexColor string
|
||||||
CreatedByID int64
|
CreatedByID int64
|
||||||
CreatedBy *User
|
CreatedBy *user.User
|
||||||
Created int64
|
Created int64
|
||||||
Updated int64
|
Updated int64
|
||||||
CRUDable web.CRUDable
|
CRUDable web.CRUDable
|
||||||
|
@ -272,7 +273,7 @@ func TestLabel_Create(t *testing.T) {
|
||||||
HexColor: "ffccff",
|
HexColor: "ffccff",
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -308,7 +309,7 @@ func TestLabel_Update(t *testing.T) {
|
||||||
Description string
|
Description string
|
||||||
HexColor string
|
HexColor string
|
||||||
CreatedByID int64
|
CreatedByID int64
|
||||||
CreatedBy *User
|
CreatedBy *user.User
|
||||||
Created int64
|
Created int64
|
||||||
Updated int64
|
Updated int64
|
||||||
CRUDable web.CRUDable
|
CRUDable web.CRUDable
|
||||||
|
@ -327,7 +328,7 @@ func TestLabel_Update(t *testing.T) {
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Title: "new and better",
|
Title: "new and better",
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "nonexisting",
|
name: "nonexisting",
|
||||||
|
@ -335,7 +336,7 @@ func TestLabel_Update(t *testing.T) {
|
||||||
ID: 99999,
|
ID: 99999,
|
||||||
Title: "new and better",
|
Title: "new and better",
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
@ -345,7 +346,7 @@ func TestLabel_Update(t *testing.T) {
|
||||||
ID: 3,
|
ID: 3,
|
||||||
Title: "new and better",
|
Title: "new and better",
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -354,7 +355,7 @@ func TestLabel_Update(t *testing.T) {
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Title: "new and better",
|
Title: "new and better",
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -390,7 +391,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||||
Description string
|
Description string
|
||||||
HexColor string
|
HexColor string
|
||||||
CreatedByID int64
|
CreatedByID int64
|
||||||
CreatedBy *User
|
CreatedBy *user.User
|
||||||
Created int64
|
Created int64
|
||||||
Updated int64
|
Updated int64
|
||||||
CRUDable web.CRUDable
|
CRUDable web.CRUDable
|
||||||
|
@ -409,14 +410,14 @@ func TestLabel_Delete(t *testing.T) {
|
||||||
fields: fields{
|
fields: fields{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "nonexisting",
|
name: "nonexisting",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
ID: 99999,
|
ID: 99999,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true, // When the label does not exist, it is forbidden. We should fix this, but for everything.
|
wantForbidden: true, // When the label does not exist, it is forbidden. We should fix this, but for everything.
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -424,7 +425,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||||
fields: fields{
|
fields: fields{
|
||||||
ID: 3,
|
ID: 3,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -432,7 +433,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||||
fields: fields{
|
fields: fields{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
},
|
},
|
||||||
auth: &User{ID: 1},
|
auth: &user.User{ID: 1},
|
||||||
wantForbidden: true,
|
wantForbidden: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/api/pkg/utils"
|
"code.vikunja.io/api/pkg/utils"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
@ -48,8 +49,8 @@ type LinkSharing struct {
|
||||||
SharingType SharingType `xorm:"int(11) INDEX not null default 0" json:"sharing_type" valid:"length(0|2)" maximum:"2" default:"0"`
|
SharingType SharingType `xorm:"int(11) INDEX not null default 0" json:"sharing_type" valid:"length(0|2)" maximum:"2" default:"0"`
|
||||||
|
|
||||||
// The user who shared this list
|
// The user who shared this list
|
||||||
SharedBy *User `xorm:"-" json:"shared_by"`
|
SharedBy *user.User `xorm:"-" json:"shared_by"`
|
||||||
SharedByID int64 `xorm:"int(11) INDEX not null" json:"-"`
|
SharedByID int64 `xorm:"int(11) INDEX not null" json:"-"`
|
||||||
|
|
||||||
// A unix timestamp when this list was shared. You cannot change this value.
|
// A unix timestamp when this list was shared. You cannot change this value.
|
||||||
Created int64 `xorm:"created not null" json:"created"`
|
Created int64 `xorm:"created not null" json:"created"`
|
||||||
|
@ -100,7 +101,7 @@ func (share *LinkSharing) Create(a web.Auth) (err error) {
|
||||||
share.SharedByID = a.GetID()
|
share.SharedByID = a.GetID()
|
||||||
share.Hash = utils.MakeRandomString(40)
|
share.Hash = utils.MakeRandomString(40)
|
||||||
_, err = x.Insert(share)
|
_, err = x.Insert(share)
|
||||||
share.SharedBy, _ = a.(*User)
|
share.SharedBy, _ = a.(*user.User)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +169,7 @@ func (share *LinkSharing) ReadAll(a web.Auth, search string, page int, perPage i
|
||||||
userIDs = append(userIDs, s.SharedByID)
|
userIDs = append(userIDs, s.SharedByID)
|
||||||
}
|
}
|
||||||
|
|
||||||
users := make(map[int64]*User)
|
users := make(map[int64]*user.User)
|
||||||
err = x.In("id", userIDs).Find(&users)
|
err = x.In("id", userIDs).Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
|
|
|
@ -18,6 +18,7 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/metrics"
|
"code.vikunja.io/api/pkg/metrics"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ type List struct {
|
||||||
NamespaceID int64 `xorm:"int(11) INDEX not null" json:"-" param:"namespace"`
|
NamespaceID int64 `xorm:"int(11) INDEX not null" json:"-" param:"namespace"`
|
||||||
|
|
||||||
// The user who created this list.
|
// The user who created this list.
|
||||||
Owner *User `xorm:"-" json:"owner" valid:"-"`
|
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
|
||||||
// An array of tasks which belong to the list.
|
// An array of tasks which belong to the list.
|
||||||
// Deprecated: you should use the dedicated task list endpoint because it has support for pagination and filtering
|
// Deprecated: you should use the dedicated task list endpoint because it has support for pagination and filtering
|
||||||
Tasks []*Task `xorm:"-" json:"-"`
|
Tasks []*Task `xorm:"-" json:"-"`
|
||||||
|
@ -51,7 +52,7 @@ type List struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetListsByNamespaceID gets all lists in a namespace
|
// GetListsByNamespaceID gets all lists in a namespace
|
||||||
func GetListsByNamespaceID(nID int64, doer *User) (lists []*List, err error) {
|
func GetListsByNamespaceID(nID int64, doer *user.User) (lists []*List, err error) {
|
||||||
if nID == -1 {
|
if nID == -1 {
|
||||||
err = x.Select("l.*").
|
err = x.Select("l.*").
|
||||||
Table("list").
|
Table("list").
|
||||||
|
@ -103,7 +104,7 @@ func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result
|
||||||
return lists, 0, 0, err
|
return lists, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lists, resultCount, totalItems, err := getRawListsForUser(search, &User{ID: a.GetID()}, page, perPage)
|
lists, resultCount, totalItems, err := getRawListsForUser(search, &user.User{ID: a.GetID()}, page, perPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
@ -127,7 +128,7 @@ func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result
|
||||||
// @Router /lists/{id} [get]
|
// @Router /lists/{id} [get]
|
||||||
func (l *List) ReadOne() (err error) {
|
func (l *List) ReadOne() (err error) {
|
||||||
// Get list owner
|
// Get list owner
|
||||||
l.Owner, err = GetUserByID(l.OwnerID)
|
l.Owner, err = user.GetUserByID(l.OwnerID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,8 +177,8 @@ func GetListSimplByTaskID(taskID int64) (l *List, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the lists only, without any tasks or so
|
// Gets the lists only, without any tasks or so
|
||||||
func getRawListsForUser(search string, u *User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
func getRawListsForUser(search string, u *user.User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
||||||
fullUser, err := GetUserByID(u.ID)
|
fullUser, err := user.GetUserByID(u.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
@ -237,7 +238,7 @@ func AddListDetails(lists []*List) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all list owners
|
// Get all list owners
|
||||||
owners := []*User{}
|
owners := []*user.User{}
|
||||||
err = x.In("id", ownerIDs).Find(&owners)
|
err = x.In("id", ownerIDs).Find(&owners)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -348,7 +349,7 @@ func updateListByTaskID(taskID int64) (err error) {
|
||||||
// @Failure 500 {object} models.Message "Internal error"
|
// @Failure 500 {object} models.Message "Internal error"
|
||||||
// @Router /namespaces/{namespaceID}/lists [put]
|
// @Router /namespaces/{namespaceID}/lists [put]
|
||||||
func (l *List) Create(a web.Auth) (err error) {
|
func (l *List) Create(a web.Auth) (err error) {
|
||||||
doer, err := getUserWithError(a)
|
doer, err := user.GetFromAuth(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/go-xorm/builder"
|
"github.com/go-xorm/builder"
|
||||||
)
|
)
|
||||||
|
@ -39,7 +40,7 @@ func (l *List) CanWrite(a web.Auth) (bool, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user is either owner or can write to the list
|
// Check if the user is either owner or can write to the list
|
||||||
if originalList.isOwner(&User{ID: a.GetID()}) {
|
if originalList.isOwner(&user.User{ID: a.GetID()}) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ func (l *List) CanRead(a web.Auth) (bool, error) {
|
||||||
(shareAuth.Right == RightRead || shareAuth.Right == RightWrite || shareAuth.Right == RightAdmin), nil
|
(shareAuth.Right == RightRead || shareAuth.Right == RightWrite || shareAuth.Right == RightAdmin), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.isOwner(&User{ID: a.GetID()}) {
|
if l.isOwner(&user.User{ID: a.GetID()}) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
return l.checkRight(a, RightRead, RightWrite, RightAdmin)
|
return l.checkRight(a, RightRead, RightWrite, RightAdmin)
|
||||||
|
@ -100,14 +101,14 @@ func (l *List) IsAdmin(a web.Auth) (bool, error) {
|
||||||
// Check all the things
|
// Check all the things
|
||||||
// Check if the user is either owner or can write to the list
|
// Check if the user is either owner or can write to the list
|
||||||
// Owners are always admins
|
// Owners are always admins
|
||||||
if originalList.isOwner(&User{ID: a.GetID()}) {
|
if originalList.isOwner(&user.User{ID: a.GetID()}) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
return originalList.checkRight(a, RightAdmin)
|
return originalList.checkRight(a, RightAdmin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Little helper function to check if a user is list owner
|
// Little helper function to check if a user is list owner
|
||||||
func (l *List) isOwner(u *User) bool {
|
func (l *List) isOwner(u *user.User) bool {
|
||||||
return l.OwnerID == u.ID
|
return l.OwnerID == u.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -25,6 +27,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTeamList(t *testing.T) {
|
func TestTeamList(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
// Dummy relation
|
// Dummy relation
|
||||||
tl := TeamList{
|
tl := TeamList{
|
||||||
TeamID: 1,
|
TeamID: 1,
|
||||||
|
@ -33,7 +37,7 @@ func TestTeamList(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dummyuser
|
// Dummyuser
|
||||||
u, err := GetUserByID(1)
|
u, err := user.GetUserByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Check normal creation
|
// Check normal creation
|
||||||
|
@ -164,6 +168,8 @@ func TestTeamList_Update(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
tl := &TeamList{
|
tl := &TeamList{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
TeamID: tt.fields.TeamID,
|
TeamID: tt.fields.TeamID,
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestList_CreateOrUpdate(t *testing.T) {
|
func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
user := &User{
|
usr := &user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Email: "user1@example.com",
|
Email: "user1@example.com",
|
||||||
|
@ -31,41 +33,41 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
|
|
||||||
t.Run("create", func(t *testing.T) {
|
t.Run("create", func(t *testing.T) {
|
||||||
t.Run("normal", func(t *testing.T) {
|
t.Run("normal", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
Title: "test",
|
Title: "test",
|
||||||
Description: "Lorem Ipsum",
|
Description: "Lorem Ipsum",
|
||||||
NamespaceID: 1,
|
NamespaceID: 1,
|
||||||
}
|
}
|
||||||
err := list.Create(user)
|
err := list.Create(usr)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("nonexistant namespace", func(t *testing.T) {
|
t.Run("nonexistant namespace", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
Title: "test",
|
Title: "test",
|
||||||
Description: "Lorem Ipsum",
|
Description: "Lorem Ipsum",
|
||||||
NamespaceID: 999999,
|
NamespaceID: 999999,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := list.Create(user)
|
err := list.Create(usr)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||||
})
|
})
|
||||||
t.Run("nonexistant owner", func(t *testing.T) {
|
t.Run("nonexistant owner", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
user := &User{ID: 9482385}
|
usr := &user.User{ID: 9482385}
|
||||||
list := List{
|
list := List{
|
||||||
Title: "test",
|
Title: "test",
|
||||||
Description: "Lorem Ipsum",
|
Description: "Lorem Ipsum",
|
||||||
NamespaceID: 1,
|
NamespaceID: 1,
|
||||||
}
|
}
|
||||||
err := list.Create(user)
|
err := list.Create(usr)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||||
})
|
})
|
||||||
t.Run("existing identifier", func(t *testing.T) {
|
t.Run("existing identifier", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
Title: "test",
|
Title: "test",
|
||||||
Description: "Lorem Ipsum",
|
Description: "Lorem Ipsum",
|
||||||
|
@ -73,7 +75,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
NamespaceID: 1,
|
NamespaceID: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := list.Create(user)
|
err := list.Create(usr)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
||||||
})
|
})
|
||||||
|
@ -81,7 +83,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
|
|
||||||
t.Run("update", func(t *testing.T) {
|
t.Run("update", func(t *testing.T) {
|
||||||
t.Run("normal", func(t *testing.T) {
|
t.Run("normal", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Title: "test",
|
Title: "test",
|
||||||
|
@ -94,7 +96,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
|
|
||||||
})
|
})
|
||||||
t.Run("nonexistant", func(t *testing.T) {
|
t.Run("nonexistant", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
ID: 99999999,
|
ID: 99999999,
|
||||||
Title: "test",
|
Title: "test",
|
||||||
|
@ -105,7 +107,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
|
|
||||||
})
|
})
|
||||||
t.Run("existing identifier", func(t *testing.T) {
|
t.Run("existing identifier", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
Title: "test",
|
Title: "test",
|
||||||
Description: "Lorem Ipsum",
|
Description: "Lorem Ipsum",
|
||||||
|
@ -113,7 +115,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
NamespaceID: 1,
|
NamespaceID: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := list.Create(user)
|
err := list.Create(usr)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
||||||
})
|
})
|
||||||
|
@ -121,7 +123,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestList_Delete(t *testing.T) {
|
func TestList_Delete(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
list := List{
|
list := List{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}
|
}
|
||||||
|
@ -131,14 +133,16 @@ func TestList_Delete(t *testing.T) {
|
||||||
|
|
||||||
func TestList_ReadAll(t *testing.T) {
|
func TestList_ReadAll(t *testing.T) {
|
||||||
t.Run("all in namespace", func(t *testing.T) {
|
t.Run("all in namespace", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
// Get all lists for our namespace
|
// Get all lists for our namespace
|
||||||
lists, err := GetListsByNamespaceID(1, &User{})
|
lists, err := GetListsByNamespaceID(1, &user.User{})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, len(lists), 2)
|
assert.Equal(t, len(lists), 2)
|
||||||
})
|
})
|
||||||
t.Run("all lists for user", func(t *testing.T) {
|
t.Run("all lists for user", func(t *testing.T) {
|
||||||
u := &User{ID: 1}
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
|
u := &user.User{ID: 1}
|
||||||
list := List{}
|
list := List{}
|
||||||
lists3, _, _, err := list.ReadAll(u, "", 1, 50)
|
lists3, _, _, err := list.ReadAll(u, "", 1, 50)
|
||||||
|
|
||||||
|
@ -148,10 +152,12 @@ func TestList_ReadAll(t *testing.T) {
|
||||||
assert.Equal(t, 16, s.Len())
|
assert.Equal(t, 16, s.Len())
|
||||||
})
|
})
|
||||||
t.Run("lists for nonexistant user", func(t *testing.T) {
|
t.Run("lists for nonexistant user", func(t *testing.T) {
|
||||||
user := &User{ID: 999999}
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
|
usr := &user.User{ID: 999999}
|
||||||
list := List{}
|
list := List{}
|
||||||
_, _, _, err := list.ReadAll(user, "", 1, 50)
|
_, _, _, err := list.ReadAll(usr, "", 1, 50)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import "code.vikunja.io/web"
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
|
"code.vikunja.io/web"
|
||||||
|
)
|
||||||
|
|
||||||
// ListUser represents a list <-> user relation
|
// ListUser represents a list <-> user relation
|
||||||
type ListUser struct {
|
type ListUser struct {
|
||||||
|
@ -47,8 +50,8 @@ func (ListUser) TableName() string {
|
||||||
|
|
||||||
// UserWithRight represents a user in combination with the right it can have on a list/namespace
|
// UserWithRight represents a user in combination with the right it can have on a list/namespace
|
||||||
type UserWithRight struct {
|
type UserWithRight struct {
|
||||||
User `xorm:"extends"`
|
user.User `xorm:"extends"`
|
||||||
Right Right `json:"right"`
|
Right Right `json:"right"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new list <-> user relation
|
// Create creates a new list <-> user relation
|
||||||
|
@ -80,7 +83,7 @@ func (lu *ListUser) Create(a web.Auth) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(lu.Username)
|
user, err := user.GetUserByUsername(lu.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -126,7 +129,7 @@ func (lu *ListUser) Create(a web.Auth) (err error) {
|
||||||
func (lu *ListUser) Delete() (err error) {
|
func (lu *ListUser) Delete() (err error) {
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(lu.Username)
|
user, err := user.GetUserByUsername(lu.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -227,7 +230,7 @@ func (lu *ListUser) Update() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(lu.Username)
|
user, err := user.GetUserByUsername(lu.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
|
@ -48,7 +50,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
||||||
ListID: 3,
|
ListID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||||
},
|
},
|
||||||
|
@ -58,7 +60,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
||||||
ListID: 300,
|
ListID: 300,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
|
@ -68,13 +70,15 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
||||||
ListID: 3,
|
ListID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 4},
|
a: &user.User{ID: 4},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
lu := &ListUser{
|
lu := &ListUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
UserID: tt.fields.UserID,
|
UserID: tt.fields.UserID,
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"gopkg.in/d4l3k/messagediff.v1"
|
"gopkg.in/d4l3k/messagediff.v1"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -58,7 +60,7 @@ func TestListUser_Create(t *testing.T) {
|
||||||
name: "ListUsers Create for duplicate",
|
name: "ListUsers Create for duplicate",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
ListID: 2,
|
ListID: 3,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrUserAlreadyHasAccess,
|
errType: IsErrUserAlreadyHasAccess,
|
||||||
|
@ -89,7 +91,7 @@ func TestListUser_Create(t *testing.T) {
|
||||||
ListID: 2,
|
ListID: 2,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrUserDoesNotExist,
|
errType: user.IsErrUserDoesNotExist,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "ListUsers Create with the owner as shared user",
|
name: "ListUsers Create with the owner as shared user",
|
||||||
|
@ -103,6 +105,8 @@ func TestListUser_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
ul := &ListUser{
|
ul := &ListUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
UserID: tt.fields.UserID,
|
UserID: tt.fields.UserID,
|
||||||
|
@ -155,11 +159,11 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||||
ListID: 3,
|
ListID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: []*UserWithRight{
|
want: []*UserWithRight{
|
||||||
{
|
{
|
||||||
User: User{
|
User: user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -169,7 +173,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||||
Right: RightRead,
|
Right: RightRead,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
User: User{
|
User: user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -185,7 +189,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||||
ListID: 3,
|
ListID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 4},
|
a: &user.User{ID: 4},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrNeedToHaveListReadAccess,
|
errType: IsErrNeedToHaveListReadAccess,
|
||||||
|
@ -193,6 +197,8 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
ul := &ListUser{
|
ul := &ListUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
UserID: tt.fields.UserID,
|
UserID: tt.fields.UserID,
|
||||||
|
@ -271,6 +277,8 @@ func TestListUser_Update(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
lu := &ListUser{
|
lu := &ListUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Username: tt.fields.Username,
|
Username: tt.fields.Username,
|
||||||
|
@ -316,7 +324,7 @@ func TestListUser_Delete(t *testing.T) {
|
||||||
ListID: 2,
|
ListID: 2,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrUserDoesNotExist,
|
errType: user.IsErrUserDoesNotExist,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Try deleting a user which does not has access but exists",
|
name: "Try deleting a user which does not has access but exists",
|
||||||
|
@ -337,6 +345,8 @@ func TestListUser_Delete(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
lu := &ListUser{
|
lu := &ListUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Username: tt.fields.Username,
|
Username: tt.fields.Username,
|
||||||
|
|
|
@ -19,6 +19,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
"code.vikunja.io/api/pkg/files"
|
"code.vikunja.io/api/pkg/files"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -33,7 +34,9 @@ func TestMain(m *testing.M) {
|
||||||
// Some tests use the file engine, so we'll need to initialize that
|
// Some tests use the file engine, so we'll need to initialize that
|
||||||
files.InitTests()
|
files.InitTests()
|
||||||
|
|
||||||
SetupTests(config.ServiceRootpath.GetString())
|
user.InitTests()
|
||||||
|
|
||||||
|
SetupTests()
|
||||||
|
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
"code.vikunja.io/api/pkg/db"
|
"code.vikunja.io/api/pkg/db"
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
_ "github.com/go-sql-driver/mysql" // Because.
|
_ "github.com/go-sql-driver/mysql" // Because.
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ var (
|
||||||
// GetTables returns all structs which are also a table.
|
// GetTables returns all structs which are also a table.
|
||||||
func GetTables() []interface{} {
|
func GetTables() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
&User{},
|
&user.User{},
|
||||||
&List{},
|
&List{},
|
||||||
&Task{},
|
&Task{},
|
||||||
&Team{},
|
&Team{},
|
||||||
|
|
|
@ -18,6 +18,7 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/metrics"
|
"code.vikunja.io/api/pkg/metrics"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
"time"
|
"time"
|
||||||
|
@ -34,7 +35,7 @@ type Namespace struct {
|
||||||
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||||
|
|
||||||
// The user who owns this namespace
|
// The user who owns this namespace
|
||||||
Owner *User `xorm:"-" json:"owner" valid:"-"`
|
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
|
||||||
|
|
||||||
// A unix timestamp when this namespace was created. You cannot change this value.
|
// A unix timestamp when this namespace was created. You cannot change this value.
|
||||||
Created int64 `xorm:"created not null" json:"created"`
|
Created int64 `xorm:"created not null" json:"created"`
|
||||||
|
@ -97,7 +98,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the namespace Owner
|
// Get the namespace Owner
|
||||||
namespace.Owner, err = GetUserByID(namespace.OwnerID)
|
namespace.Owner, err = user.GetUserByID(namespace.OwnerID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
|
||||||
// @Router /namespaces/{id} [get]
|
// @Router /namespaces/{id} [get]
|
||||||
func (n *Namespace) ReadOne() (err error) {
|
func (n *Namespace) ReadOne() (err error) {
|
||||||
// Get the namespace Owner
|
// Get the namespace Owner
|
||||||
n.Owner, err = GetUserByID(n.OwnerID)
|
n.Owner, err = user.GetUserByID(n.OwnerID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
|
||||||
return nil, 0, 0, ErrGenericForbidden{}
|
return nil, 0, 0, ErrGenericForbidden{}
|
||||||
}
|
}
|
||||||
|
|
||||||
doer, err := getUserWithError(a)
|
doer, err := user.GetFromAuth(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
@ -176,7 +177,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all users
|
// Get all users
|
||||||
users := []*User{}
|
users := []*user.User{}
|
||||||
err = x.Select("users.*").
|
err = x.Select("users.*").
|
||||||
Table("namespaces").
|
Table("namespaces").
|
||||||
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
|
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
|
||||||
|
@ -301,7 +302,7 @@ func (n *Namespace) Create(a web.Auth) (err error) {
|
||||||
n.ID = 0 // This would otherwise prevent the creation of new lists after one was created
|
n.ID = 0 // This would otherwise prevent the creation of new lists after one was created
|
||||||
|
|
||||||
// Check if the User exists
|
// Check if the User exists
|
||||||
n.Owner, err = GetUserByID(a.GetID())
|
n.Owner, err = user.GetUserByID(a.GetID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -343,7 +344,7 @@ func (n *Namespace) Delete() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete all lists with their tasks
|
// Delete all lists with their tasks
|
||||||
lists, err := GetListsByNamespaceID(n.ID, &User{})
|
lists, err := GetListsByNamespaceID(n.ID, &user.User{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -401,7 +402,7 @@ func (n *Namespace) Update() (err error) {
|
||||||
// Check if the (new) owner exists
|
// Check if the (new) owner exists
|
||||||
n.OwnerID = n.Owner.ID
|
n.OwnerID = n.Owner.ID
|
||||||
if currentNamespace.OwnerID != n.OwnerID {
|
if currentNamespace.OwnerID != n.OwnerID {
|
||||||
n.Owner, err = GetUserByID(n.OwnerID)
|
n.Owner, err = user.GetUserByID(n.OwnerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
|
@ -48,7 +50,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
||||||
NamespaceID: 3,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||||
},
|
},
|
||||||
|
@ -58,7 +60,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
||||||
NamespaceID: 300,
|
NamespaceID: 300,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
|
@ -68,13 +70,15 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
||||||
NamespaceID: 3,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 4},
|
a: &user.User{ID: 4},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
tn := &TeamNamespace{
|
tn := &TeamNamespace{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
TeamID: tt.fields.TeamID,
|
TeamID: tt.fields.TeamID,
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -25,6 +27,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTeamNamespace(t *testing.T) {
|
func TestTeamNamespace(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
// Dummy team <-> namespace relation
|
// Dummy team <-> namespace relation
|
||||||
tn := TeamNamespace{
|
tn := TeamNamespace{
|
||||||
TeamID: 1,
|
TeamID: 1,
|
||||||
|
@ -32,7 +36,7 @@ func TestTeamNamespace(t *testing.T) {
|
||||||
Right: RightAdmin,
|
Right: RightAdmin,
|
||||||
}
|
}
|
||||||
|
|
||||||
dummyuser, err := GetUserByID(1)
|
dummyuser, err := user.GetUserByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Test normal creation
|
// Test normal creation
|
||||||
|
@ -80,7 +84,7 @@ func TestTeamNamespace(t *testing.T) {
|
||||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||||
|
|
||||||
// Check with no right to read the namespace
|
// Check with no right to read the namespace
|
||||||
nouser := &User{ID: 393}
|
nouser := &user.User{ID: 393}
|
||||||
_, _, _, err = tn.ReadAll(nouser, "", 1, 50)
|
_, _, _, err = tn.ReadAll(nouser, "", 1, 50)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrNeedToHaveNamespaceReadAccess(err))
|
assert.True(t, IsErrNeedToHaveNamespaceReadAccess(err))
|
||||||
|
@ -156,6 +160,8 @@ func TestTeamNamespace_Update(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
tl := &TeamNamespace{
|
tl := &TeamNamespace{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
TeamID: tt.fields.TeamID,
|
TeamID: tt.fields.TeamID,
|
||||||
|
|
|
@ -17,12 +17,16 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNamespace_Create(t *testing.T) {
|
func TestNamespace_Create(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
// Create test database
|
// Create test database
|
||||||
//assert.NoError(t, LoadFixtures())
|
//assert.NoError(t, LoadFixtures())
|
||||||
|
|
||||||
|
@ -33,7 +37,7 @@ func TestNamespace_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doer
|
// Doer
|
||||||
doer, err := GetUserByID(1)
|
doer, err := user.GetUserByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Try creating it
|
// Try creating it
|
||||||
|
@ -57,11 +61,11 @@ func TestNamespace_Create(t *testing.T) {
|
||||||
assert.True(t, IsErrNamespaceNameCannotBeEmpty(err))
|
assert.True(t, IsErrNamespaceNameCannotBeEmpty(err))
|
||||||
|
|
||||||
// Try inserting one with a nonexistant user
|
// Try inserting one with a nonexistant user
|
||||||
nUser := &User{ID: 9482385}
|
nUser := &user.User{ID: 9482385}
|
||||||
dnsp2 := dummynamespace
|
dnsp2 := dummynamespace
|
||||||
err = dnsp2.Create(nUser)
|
err = dnsp2.Create(nUser)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||||
|
|
||||||
// Update it
|
// Update it
|
||||||
allowed, err = dummynamespace.CanUpdate(doer)
|
allowed, err = dummynamespace.CanUpdate(doer)
|
||||||
|
@ -85,7 +89,7 @@ func TestNamespace_Create(t *testing.T) {
|
||||||
dummynamespace.Owner.ID = 94829838572
|
dummynamespace.Owner.ID = 94829838572
|
||||||
err = dummynamespace.Update()
|
err = dummynamespace.Update()
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||||
|
|
||||||
// Try updating without a name
|
// Try updating without a name
|
||||||
dummynamespace.Name = ""
|
dummynamespace.Name = ""
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import "code.vikunja.io/web"
|
import (
|
||||||
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
|
"code.vikunja.io/web"
|
||||||
|
)
|
||||||
|
|
||||||
// NamespaceUser represents a namespace <-> user relation
|
// NamespaceUser represents a namespace <-> user relation
|
||||||
type NamespaceUser struct {
|
type NamespaceUser struct {
|
||||||
|
@ -75,7 +78,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(nu.Username)
|
user, err := user2.GetUserByUsername(nu.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -117,7 +120,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
||||||
func (nu *NamespaceUser) Delete() (err error) {
|
func (nu *NamespaceUser) Delete() (err error) {
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(nu.Username)
|
user, err := user2.GetUserByUsername(nu.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -213,7 +216,7 @@ func (nu *NamespaceUser) Update() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(nu.Username)
|
user, err := user2.GetUserByUsername(nu.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
|
@ -48,7 +50,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
||||||
NamespaceID: 3,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||||
},
|
},
|
||||||
|
@ -58,7 +60,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
||||||
NamespaceID: 300,
|
NamespaceID: 300,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
|
@ -68,13 +70,15 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
||||||
NamespaceID: 3,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 4},
|
a: &user.User{ID: 4},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
nu := &NamespaceUser{
|
nu := &NamespaceUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
UserID: tt.fields.UserID,
|
UserID: tt.fields.UserID,
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"gopkg.in/d4l3k/messagediff.v1"
|
"gopkg.in/d4l3k/messagediff.v1"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -56,7 +58,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||||
name: "NamespaceUsers Create for duplicate",
|
name: "NamespaceUsers Create for duplicate",
|
||||||
fields: fields{
|
fields: fields{
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
NamespaceID: 2,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrUserAlreadyHasNamespaceAccess,
|
errType: IsErrUserAlreadyHasNamespaceAccess,
|
||||||
|
@ -87,7 +89,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||||
NamespaceID: 2,
|
NamespaceID: 2,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrUserDoesNotExist,
|
errType: user.IsErrUserDoesNotExist,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "NamespaceUsers Create with the owner as shared user",
|
name: "NamespaceUsers Create with the owner as shared user",
|
||||||
|
@ -101,6 +103,8 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
un := &NamespaceUser{
|
un := &NamespaceUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Username: tt.fields.Username,
|
Username: tt.fields.Username,
|
||||||
|
@ -152,11 +156,11 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||||
NamespaceID: 3,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 3},
|
a: &user.User{ID: 3},
|
||||||
},
|
},
|
||||||
want: []*UserWithRight{
|
want: []*UserWithRight{
|
||||||
{
|
{
|
||||||
User: User{
|
User: user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -166,7 +170,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||||
Right: RightRead,
|
Right: RightRead,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
User: User{
|
User: user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -182,7 +186,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||||
NamespaceID: 3,
|
NamespaceID: 3,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 4},
|
a: &user.User{ID: 4},
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrNeedToHaveNamespaceReadAccess,
|
errType: IsErrNeedToHaveNamespaceReadAccess,
|
||||||
|
@ -190,6 +194,8 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
un := &NamespaceUser{
|
un := &NamespaceUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
UserID: tt.fields.UserID,
|
UserID: tt.fields.UserID,
|
||||||
|
@ -269,6 +275,8 @@ func TestNamespaceUser_Update(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
nu := &NamespaceUser{
|
nu := &NamespaceUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Username: tt.fields.Username,
|
Username: tt.fields.Username,
|
||||||
|
@ -314,7 +322,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||||
NamespaceID: 2,
|
NamespaceID: 2,
|
||||||
},
|
},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
errType: IsErrUserDoesNotExist,
|
errType: user.IsErrUserDoesNotExist,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Try deleting a user which does not has access but exists",
|
name: "Try deleting a user which does not has access but exists",
|
||||||
|
@ -335,6 +343,8 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
nu := &NamespaceUser{
|
nu := &NamespaceUser{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Username: tt.fields.Username,
|
Username: tt.fields.Username,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,8 +39,8 @@ func (TaskAssginee) TableName() string {
|
||||||
|
|
||||||
// TaskAssigneeWithUser is a helper type to deal with user joins
|
// TaskAssigneeWithUser is a helper type to deal with user joins
|
||||||
type TaskAssigneeWithUser struct {
|
type TaskAssigneeWithUser struct {
|
||||||
TaskID int64
|
TaskID int64
|
||||||
User `xorm:"extends"`
|
user.User `xorm:"extends"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRawTaskAssigneesForTasks(taskIDs []int64) (taskAssignees []*TaskAssigneeWithUser, err error) {
|
func getRawTaskAssigneesForTasks(taskIDs []int64) (taskAssignees []*TaskAssigneeWithUser, err error) {
|
||||||
|
@ -53,7 +54,7 @@ func getRawTaskAssigneesForTasks(taskIDs []int64) (taskAssignees []*TaskAssignee
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or update a bunch of task assignees
|
// Create or update a bunch of task assignees
|
||||||
func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
func (t *Task) updateTaskAssignees(assignees []*user.User) (err error) {
|
||||||
|
|
||||||
// Load the current assignees
|
// Load the current assignees
|
||||||
currentAssignees, err := getRawTaskAssigneesForTasks([]int64{t.ID})
|
currentAssignees, err := getRawTaskAssigneesForTasks([]int64{t.ID})
|
||||||
|
@ -61,7 +62,7 @@ func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Assignees = make([]*User, 0, len(currentAssignees))
|
t.Assignees = make([]*user.User, 0, len(currentAssignees))
|
||||||
for _, assignee := range currentAssignees {
|
for _, assignee := range currentAssignees {
|
||||||
t.Assignees = append(t.Assignees, &assignee.User)
|
t.Assignees = append(t.Assignees, &assignee.User)
|
||||||
}
|
}
|
||||||
|
@ -80,7 +81,7 @@ func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a hashmap of the new assignees for easier comparison
|
// Make a hashmap of the new assignees for easier comparison
|
||||||
newAssignees := make(map[int64]*User, len(assignees))
|
newAssignees := make(map[int64]*user.User, len(assignees))
|
||||||
for _, newAssignee := range assignees {
|
for _, newAssignee := range assignees {
|
||||||
newAssignees[newAssignee.ID] = newAssignee
|
newAssignees[newAssignee.ID] = newAssignee
|
||||||
}
|
}
|
||||||
|
@ -88,7 +89,7 @@ func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
||||||
// Get old assignees to delete
|
// Get old assignees to delete
|
||||||
var found bool
|
var found bool
|
||||||
var assigneesToDelete []int64
|
var assigneesToDelete []int64
|
||||||
oldAssignees := make(map[int64]*User, len(t.Assignees))
|
oldAssignees := make(map[int64]*user.User, len(t.Assignees))
|
||||||
for _, oldAssignee := range t.Assignees {
|
for _, oldAssignee := range t.Assignees {
|
||||||
found = false
|
found = false
|
||||||
if newAssignees[oldAssignee.ID] != nil {
|
if newAssignees[oldAssignee.ID] != nil {
|
||||||
|
@ -142,7 +143,7 @@ func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Small helper functions to set the new assignees in various places
|
// Small helper functions to set the new assignees in various places
|
||||||
func (t *Task) setTaskAssignees(assignees []*User) {
|
func (t *Task) setTaskAssignees(assignees []*user.User) {
|
||||||
if len(assignees) == 0 {
|
if len(assignees) == 0 {
|
||||||
t.Assignees = nil
|
t.Assignees = nil
|
||||||
return
|
return
|
||||||
|
@ -200,7 +201,7 @@ func (la *TaskAssginee) Create(a web.Auth) (err error) {
|
||||||
|
|
||||||
func (t *Task) addNewAssigneeByID(newAssigneeID int64, list *List) (err error) {
|
func (t *Task) addNewAssigneeByID(newAssigneeID int64, list *List) (err error) {
|
||||||
// Check if the user exists and has access to the list
|
// Check if the user exists and has access to the list
|
||||||
newAssignee, err := GetUserByID(newAssigneeID)
|
newAssignee, err := user.GetUserByID(newAssigneeID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -252,7 +253,7 @@ func (la *TaskAssginee) ReadAll(a web.Auth, search string, page int, perPage int
|
||||||
return nil, 0, 0, ErrGenericForbidden{}
|
return nil, 0, 0, ErrGenericForbidden{}
|
||||||
}
|
}
|
||||||
|
|
||||||
var taskAssignees []*User
|
var taskAssignees []*user.User
|
||||||
err = x.Table("task_assignees").
|
err = x.Table("task_assignees").
|
||||||
Select("users.*").
|
Select("users.*").
|
||||||
Join("INNER", "users", "task_assignees.user_id = users.id").
|
Join("INNER", "users", "task_assignees.user_id = users.id").
|
||||||
|
@ -267,15 +268,15 @@ func (la *TaskAssginee) ReadAll(a web.Auth, search string, page int, perPage int
|
||||||
Select("users.*").
|
Select("users.*").
|
||||||
Join("INNER", "users", "task_assignees.user_id = users.id").
|
Join("INNER", "users", "task_assignees.user_id = users.id").
|
||||||
Where("task_id = ? AND users.username LIKE ?", la.TaskID, "%"+search+"%").
|
Where("task_id = ? AND users.username LIKE ?", la.TaskID, "%"+search+"%").
|
||||||
Count(&User{})
|
Count(&user.User{})
|
||||||
return taskAssignees, len(taskAssignees), numberOfTotalItems, err
|
return taskAssignees, len(taskAssignees), numberOfTotalItems, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// BulkAssignees is a helper struct used to update multiple assignees at once.
|
// BulkAssignees is a helper struct used to update multiple assignees at once.
|
||||||
type BulkAssignees struct {
|
type BulkAssignees struct {
|
||||||
// A list with all assignees
|
// A list with all assignees
|
||||||
Assignees []*User `json:"assignees"`
|
Assignees []*user.User `json:"assignees"`
|
||||||
TaskID int64 `json:"-" param:"listtask"`
|
TaskID int64 `json:"-" param:"listtask"`
|
||||||
|
|
||||||
web.CRUDable `json:"-"`
|
web.CRUDable `json:"-"`
|
||||||
web.Rights `json:"-"`
|
web.Rights `json:"-"`
|
||||||
|
|
|
@ -18,6 +18,7 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/files"
|
"code.vikunja.io/api/pkg/files"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
@ -29,8 +30,8 @@ type TaskAttachment struct {
|
||||||
TaskID int64 `xorm:"int(11) not null" json:"task_id" param:"task"`
|
TaskID int64 `xorm:"int(11) not null" json:"task_id" param:"task"`
|
||||||
FileID int64 `xorm:"int(11) not null" json:"-"`
|
FileID int64 `xorm:"int(11) not null" json:"-"`
|
||||||
|
|
||||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||||
CreatedBy *User `xorm:"-" json:"created_by"`
|
CreatedBy *user.User `xorm:"-" json:"created_by"`
|
||||||
|
|
||||||
File *files.File `xorm:"-" json:"file"`
|
File *files.File `xorm:"-" json:"file"`
|
||||||
|
|
||||||
|
@ -132,7 +133,7 @@ func (ta *TaskAttachment) ReadAll(a web.Auth, search string, page int, perPage i
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
us := make(map[int64]*User)
|
us := make(map[int64]*user.User)
|
||||||
err = x.In("id", userIDs).Find(&us)
|
err = x.In("id", userIDs).Find(&us)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
|
|
|
@ -20,6 +20,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
"code.vikunja.io/api/pkg/files"
|
"code.vikunja.io/api/pkg/files"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
@ -95,7 +96,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
||||||
tf := &testfile{
|
tf := &testfile{
|
||||||
content: []byte("testingstuff"),
|
content: []byte("testingstuff"),
|
||||||
}
|
}
|
||||||
testuser := &User{ID: 1}
|
testuser := &user.User{ID: 1}
|
||||||
|
|
||||||
err := ta.NewAttachment(tf, "testfile", 100, testuser)
|
err := ta.NewAttachment(tf, "testfile", 100, testuser)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -119,7 +120,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
||||||
func TestTaskAttachment_ReadAll(t *testing.T) {
|
func TestTaskAttachment_ReadAll(t *testing.T) {
|
||||||
files.InitTestFileFixtures(t)
|
files.InitTestFileFixtures(t)
|
||||||
ta := &TaskAttachment{TaskID: 1}
|
ta := &TaskAttachment{TaskID: 1}
|
||||||
as, _, _, err := ta.ReadAll(&User{ID: 1}, "", 0, 50)
|
as, _, _, err := ta.ReadAll(&user.User{ID: 1}, "", 0, 50)
|
||||||
attachments, _ := as.([]*TaskAttachment)
|
attachments, _ := as.([]*TaskAttachment)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, attachments, 3)
|
assert.Len(t, attachments, 3)
|
||||||
|
@ -152,7 +153,7 @@ func TestTaskAttachment_Delete(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTaskAttachment_Rights(t *testing.T) {
|
func TestTaskAttachment_Rights(t *testing.T) {
|
||||||
u := &User{ID: 1}
|
u := &user.User{ID: 1}
|
||||||
t.Run("Can Read", func(t *testing.T) {
|
t.Run("Can Read", func(t *testing.T) {
|
||||||
t.Run("Allowed", func(t *testing.T) {
|
t.Run("Allowed", func(t *testing.T) {
|
||||||
ta := &TaskAttachment{TaskID: 1}
|
ta := &TaskAttachment{TaskID: 1}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -108,7 +109,7 @@ func (tf *TaskCollection) ReadAll(a web.Auth, search string, page int, perPage i
|
||||||
// If the list ID is not set, we get all tasks for the user.
|
// If the list ID is not set, we get all tasks for the user.
|
||||||
// This allows to use this function in Task.ReadAll with a possibility to deprecate the latter at some point.
|
// This allows to use this function in Task.ReadAll with a possibility to deprecate the latter at some point.
|
||||||
if tf.ListID == 0 {
|
if tf.ListID == 0 {
|
||||||
tf.Lists, _, _, err = getRawListsForUser("", &User{ID: a.GetID()}, -1, 0)
|
tf.Lists, _, _, err = getRawListsForUser("", &user.User{ID: a.GetID()}, -1, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,30 +19,28 @@ package models
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/db"
|
"code.vikunja.io/api/pkg/db"
|
||||||
"code.vikunja.io/api/pkg/files"
|
"code.vikunja.io/api/pkg/files"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"gopkg.in/d4l3k/messagediff.v1"
|
"gopkg.in/d4l3k/messagediff.v1"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTaskCollection_ReadAll(t *testing.T) {
|
func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
assert.NoError(t, db.LoadFixtures())
|
|
||||||
|
|
||||||
// Dummy users
|
// Dummy users
|
||||||
user1 := &User{
|
user1 := &user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
||||||
}
|
}
|
||||||
user2 := &User{
|
user2 := &user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
|
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
|
||||||
}
|
}
|
||||||
user6 := &User{
|
user6 := &user.User{
|
||||||
ID: 6,
|
ID: 6,
|
||||||
Username: "user6",
|
Username: "user6",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -463,7 +461,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedByID: 1,
|
CreatedByID: 1,
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
Assignees: []*User{
|
Assignees: []*user.User{
|
||||||
user1,
|
user1,
|
||||||
user2,
|
user2,
|
||||||
},
|
},
|
||||||
|
@ -538,7 +536,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
fields: fields{},
|
fields: fields{},
|
||||||
args: args{
|
args: args{
|
||||||
search: "",
|
search: "",
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
page: 0,
|
page: 0,
|
||||||
},
|
},
|
||||||
want: []*Task{
|
want: []*Task{
|
||||||
|
@ -585,7 +583,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
search: "",
|
search: "",
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
page: 0,
|
page: 0,
|
||||||
},
|
},
|
||||||
want: []*Task{
|
want: []*Task{
|
||||||
|
@ -631,7 +629,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
search: "",
|
search: "",
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
page: 0,
|
page: 0,
|
||||||
},
|
},
|
||||||
want: []*Task{
|
want: []*Task{
|
||||||
|
@ -648,7 +646,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
search: "",
|
search: "",
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
page: 0,
|
page: 0,
|
||||||
},
|
},
|
||||||
want: []*Task{
|
want: []*Task{
|
||||||
|
@ -664,7 +662,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
search: "",
|
search: "",
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
page: 0,
|
page: 0,
|
||||||
},
|
},
|
||||||
want: []*Task{
|
want: []*Task{
|
||||||
|
@ -677,6 +675,8 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
lt := &TaskCollection{
|
lt := &TaskCollection{
|
||||||
ListID: tt.fields.ListID,
|
ListID: tt.fields.ListID,
|
||||||
StartDateSortUnix: tt.fields.StartDateSortUnix,
|
StartDateSortUnix: tt.fields.StartDateSortUnix,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ type TaskRelation struct {
|
||||||
|
|
||||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||||
// The user who created this relation
|
// The user who created this relation
|
||||||
CreatedBy *User `xorm:"-" json:"created_by"`
|
CreatedBy *user.User `xorm:"-" json:"created_by"`
|
||||||
|
|
||||||
// A unix timestamp when this label was created. You cannot change this value.
|
// A unix timestamp when this label was created. You cannot change this value.
|
||||||
Created int64 `xorm:"created not null" json:"created"`
|
Created int64 `xorm:"created not null" json:"created"`
|
||||||
|
|
|
@ -18,45 +18,55 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTaskRelation_Create(t *testing.T) {
|
func TestTaskRelation_Create(t *testing.T) {
|
||||||
t.Run("Normal", func(t *testing.T) {
|
t.Run("Normal", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 2,
|
OtherTaskID: 2,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
err := rel.Create(&User{ID: 1})
|
err := rel.Create(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("Two Tasks In Different Lists", func(t *testing.T) {
|
t.Run("Two Tasks In Different Lists", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 13,
|
OtherTaskID: 13,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
err := rel.Create(&User{ID: 1})
|
err := rel.Create(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("Already Existing", func(t *testing.T) {
|
t.Run("Already Existing", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 29,
|
OtherTaskID: 29,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
err := rel.Create(&User{ID: 1})
|
err := rel.Create(&user.User{ID: 1})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrRelationAlreadyExists(err))
|
assert.True(t, IsErrRelationAlreadyExists(err))
|
||||||
})
|
})
|
||||||
t.Run("Same Task", func(t *testing.T) {
|
t.Run("Same Task", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 1,
|
OtherTaskID: 1,
|
||||||
}
|
}
|
||||||
err := rel.Create(&User{ID: 1})
|
err := rel.Create(&user.User{ID: 1})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrRelationTasksCannotBeTheSame(err))
|
assert.True(t, IsErrRelationTasksCannotBeTheSame(err))
|
||||||
})
|
})
|
||||||
|
@ -64,6 +74,8 @@ func TestTaskRelation_Create(t *testing.T) {
|
||||||
|
|
||||||
func TestTaskRelation_Delete(t *testing.T) {
|
func TestTaskRelation_Delete(t *testing.T) {
|
||||||
t.Run("Normal", func(t *testing.T) {
|
t.Run("Normal", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 29,
|
OtherTaskID: 29,
|
||||||
|
@ -73,6 +85,8 @@ func TestTaskRelation_Delete(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("Not existing", func(t *testing.T) {
|
t.Run("Not existing", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 9999,
|
TaskID: 9999,
|
||||||
OtherTaskID: 3,
|
OtherTaskID: 3,
|
||||||
|
@ -86,73 +100,87 @@ func TestTaskRelation_Delete(t *testing.T) {
|
||||||
|
|
||||||
func TestTaskRelation_CanCreate(t *testing.T) {
|
func TestTaskRelation_CanCreate(t *testing.T) {
|
||||||
t.Run("Normal", func(t *testing.T) {
|
t.Run("Normal", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 2,
|
OtherTaskID: 2,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, can)
|
assert.True(t, can)
|
||||||
})
|
})
|
||||||
t.Run("Two tasks on different lists", func(t *testing.T) {
|
t.Run("Two tasks on different lists", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 13,
|
OtherTaskID: 13,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, can)
|
assert.True(t, can)
|
||||||
})
|
})
|
||||||
t.Run("No update rights on base task", func(t *testing.T) {
|
t.Run("No update rights on base task", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 14,
|
TaskID: 14,
|
||||||
OtherTaskID: 1,
|
OtherTaskID: 1,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, can)
|
assert.False(t, can)
|
||||||
})
|
})
|
||||||
t.Run("No update rights on base task, but read rights", func(t *testing.T) {
|
t.Run("No update rights on base task, but read rights", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 15,
|
TaskID: 15,
|
||||||
OtherTaskID: 1,
|
OtherTaskID: 1,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, can)
|
assert.False(t, can)
|
||||||
})
|
})
|
||||||
t.Run("No read rights on other task", func(t *testing.T) {
|
t.Run("No read rights on other task", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 14,
|
OtherTaskID: 14,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.False(t, can)
|
assert.False(t, can)
|
||||||
})
|
})
|
||||||
t.Run("Nonexisting base task", func(t *testing.T) {
|
t.Run("Nonexisting base task", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 999999,
|
TaskID: 999999,
|
||||||
OtherTaskID: 1,
|
OtherTaskID: 1,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrTaskDoesNotExist(err))
|
assert.True(t, IsErrTaskDoesNotExist(err))
|
||||||
assert.False(t, can)
|
assert.False(t, can)
|
||||||
})
|
})
|
||||||
t.Run("Nonexisting other task", func(t *testing.T) {
|
t.Run("Nonexisting other task", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
rel := TaskRelation{
|
rel := TaskRelation{
|
||||||
TaskID: 1,
|
TaskID: 1,
|
||||||
OtherTaskID: 999999,
|
OtherTaskID: 999999,
|
||||||
RelationKind: RelationKindSubtask,
|
RelationKind: RelationKindSubtask,
|
||||||
}
|
}
|
||||||
can, err := rel.CanCreate(&User{ID: 1})
|
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrTaskDoesNotExist(err))
|
assert.True(t, IsErrTaskDoesNotExist(err))
|
||||||
assert.False(t, can)
|
assert.False(t, can)
|
||||||
|
|
|
@ -19,6 +19,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/files"
|
"code.vikunja.io/api/pkg/files"
|
||||||
"code.vikunja.io/api/pkg/metrics"
|
"code.vikunja.io/api/pkg/metrics"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/api/pkg/utils"
|
"code.vikunja.io/api/pkg/utils"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
|
@ -55,7 +56,7 @@ type Task struct {
|
||||||
// When this task ends.
|
// When this task ends.
|
||||||
EndDateUnix int64 `xorm:"int(11) INDEX null" json:"endDate" query:"-"`
|
EndDateUnix int64 `xorm:"int(11) INDEX null" json:"endDate" query:"-"`
|
||||||
// An array of users who are assigned to this task
|
// An array of users who are assigned to this task
|
||||||
Assignees []*User `xorm:"-" json:"assignees"`
|
Assignees []*user.User `xorm:"-" json:"assignees"`
|
||||||
// An array of labels which are associated with this task.
|
// An array of labels which are associated with this task.
|
||||||
Labels []*Label `xorm:"-" json:"labels"`
|
Labels []*Label `xorm:"-" json:"labels"`
|
||||||
// The task color in hex
|
// The task color in hex
|
||||||
|
@ -87,7 +88,7 @@ type Task struct {
|
||||||
Updated int64 `xorm:"updated not null" json:"updated"`
|
Updated int64 `xorm:"updated not null" json:"updated"`
|
||||||
|
|
||||||
// The user who initially created the task.
|
// The user who initially created the task.
|
||||||
CreatedBy *User `xorm:"-" json:"createdBy" valid:"-"`
|
CreatedBy *user.User `xorm:"-" json:"createdBy" valid:"-"`
|
||||||
|
|
||||||
web.CRUDable `xorm:"-" json:"-"`
|
web.CRUDable `xorm:"-" json:"-"`
|
||||||
web.Rights `xorm:"-" json:"-"`
|
web.Rights `xorm:"-" json:"-"`
|
||||||
|
@ -365,7 +366,7 @@ func addMoreInfoToTasks(taskMap map[int64]*Task) (tasks []*Task, err error) {
|
||||||
|
|
||||||
// Get all users of a task
|
// Get all users of a task
|
||||||
// aka the ones who created a task
|
// aka the ones who created a task
|
||||||
users := make(map[int64]*User)
|
users := make(map[int64]*user.User)
|
||||||
err = x.In("id", userIDs).Find(&users)
|
err = x.In("id", userIDs).Find(&users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -487,7 +488,7 @@ func (t *Task) Create(a web.Auth) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := GetUserByID(a.GetID())
|
u, err := user.GetUserByID(a.GetID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,14 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTask_Create(t *testing.T) {
|
func TestTask_Create(t *testing.T) {
|
||||||
user := &User{
|
usr := &user.User{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Email: "user1@example.com",
|
Email: "user1@example.com",
|
||||||
|
@ -31,13 +33,13 @@ func TestTask_Create(t *testing.T) {
|
||||||
// We only test creating a task here, the rights are all well tested in the integration tests.
|
// We only test creating a task here, the rights are all well tested in the integration tests.
|
||||||
|
|
||||||
t.Run("normal", func(t *testing.T) {
|
t.Run("normal", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{
|
task := &Task{
|
||||||
Text: "Lorem",
|
Text: "Lorem",
|
||||||
Description: "Lorem Ipsum Dolor",
|
Description: "Lorem Ipsum Dolor",
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
}
|
}
|
||||||
err := task.Create(user)
|
err := task.Create(usr)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// Assert getting a uid
|
// Assert getting a uid
|
||||||
assert.NotEmpty(t, task.UID)
|
assert.NotEmpty(t, task.UID)
|
||||||
|
@ -47,30 +49,30 @@ func TestTask_Create(t *testing.T) {
|
||||||
|
|
||||||
})
|
})
|
||||||
t.Run("empty text", func(t *testing.T) {
|
t.Run("empty text", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{
|
task := &Task{
|
||||||
Text: "",
|
Text: "",
|
||||||
Description: "Lorem Ipsum Dolor",
|
Description: "Lorem Ipsum Dolor",
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
}
|
}
|
||||||
err := task.Create(user)
|
err := task.Create(usr)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrTaskCannotBeEmpty(err))
|
assert.True(t, IsErrTaskCannotBeEmpty(err))
|
||||||
})
|
})
|
||||||
t.Run("nonexistant list", func(t *testing.T) {
|
t.Run("nonexistant list", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{
|
task := &Task{
|
||||||
Text: "Test",
|
Text: "Test",
|
||||||
Description: "Lorem Ipsum Dolor",
|
Description: "Lorem Ipsum Dolor",
|
||||||
ListID: 9999999,
|
ListID: 9999999,
|
||||||
}
|
}
|
||||||
err := task.Create(user)
|
err := task.Create(usr)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrListDoesNotExist(err))
|
assert.True(t, IsErrListDoesNotExist(err))
|
||||||
})
|
})
|
||||||
t.Run("noneixtant user", func(t *testing.T) {
|
t.Run("noneixtant user", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
nUser := &User{ID: 99999999}
|
nUser := &user.User{ID: 99999999}
|
||||||
task := &Task{
|
task := &Task{
|
||||||
Text: "Test",
|
Text: "Test",
|
||||||
Description: "Lorem Ipsum Dolor",
|
Description: "Lorem Ipsum Dolor",
|
||||||
|
@ -78,13 +80,13 @@ func TestTask_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
err := task.Create(nUser)
|
err := task.Create(nUser)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTask_Update(t *testing.T) {
|
func TestTask_Update(t *testing.T) {
|
||||||
t.Run("normal", func(t *testing.T) {
|
t.Run("normal", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{
|
task := &Task{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Text: "test10000",
|
Text: "test10000",
|
||||||
|
@ -95,7 +97,7 @@ func TestTask_Update(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("nonexistant task", func(t *testing.T) {
|
t.Run("nonexistant task", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{
|
task := &Task{
|
||||||
ID: 9999999,
|
ID: 9999999,
|
||||||
Text: "test10000",
|
Text: "test10000",
|
||||||
|
@ -110,7 +112,7 @@ func TestTask_Update(t *testing.T) {
|
||||||
|
|
||||||
func TestTask_Delete(t *testing.T) {
|
func TestTask_Delete(t *testing.T) {
|
||||||
t.Run("normal", func(t *testing.T) {
|
t.Run("normal", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{
|
task := &Task{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}
|
}
|
||||||
|
@ -121,12 +123,14 @@ func TestTask_Delete(t *testing.T) {
|
||||||
|
|
||||||
func TestUpdateDone(t *testing.T) {
|
func TestUpdateDone(t *testing.T) {
|
||||||
t.Run("marking a task as done", func(t *testing.T) {
|
t.Run("marking a task as done", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
oldTask := &Task{Done: false}
|
oldTask := &Task{Done: false}
|
||||||
newTask := &Task{Done: true}
|
newTask := &Task{Done: true}
|
||||||
updateDone(oldTask, newTask)
|
updateDone(oldTask, newTask)
|
||||||
assert.NotEqual(t, int64(0), oldTask.DoneAtUnix)
|
assert.NotEqual(t, int64(0), oldTask.DoneAtUnix)
|
||||||
})
|
})
|
||||||
t.Run("unmarking a task as done", func(t *testing.T) {
|
t.Run("unmarking a task as done", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
oldTask := &Task{Done: true}
|
oldTask := &Task{Done: true}
|
||||||
newTask := &Task{Done: false}
|
newTask := &Task{Done: false}
|
||||||
updateDone(oldTask, newTask)
|
updateDone(oldTask, newTask)
|
||||||
|
@ -136,14 +140,14 @@ func TestUpdateDone(t *testing.T) {
|
||||||
|
|
||||||
func TestTask_ReadOne(t *testing.T) {
|
func TestTask_ReadOne(t *testing.T) {
|
||||||
t.Run("default", func(t *testing.T) {
|
t.Run("default", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{ID: 1}
|
task := &Task{ID: 1}
|
||||||
err := task.ReadOne()
|
err := task.ReadOne()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "task #1", task.Text)
|
assert.Equal(t, "task #1", task.Text)
|
||||||
})
|
})
|
||||||
t.Run("nonexisting", func(t *testing.T) {
|
t.Run("nonexisting", func(t *testing.T) {
|
||||||
initFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
task := &Task{ID: 99999}
|
task := &Task{ID: 99999}
|
||||||
err := task.ReadOne()
|
err := task.ReadOne()
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
|
@ -16,7 +16,10 @@
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import "code.vikunja.io/web"
|
import (
|
||||||
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
|
"code.vikunja.io/web"
|
||||||
|
)
|
||||||
|
|
||||||
// Create implements the create method to assign a user to a team
|
// Create implements the create method to assign a user to a team
|
||||||
// @Summary Add a user to a team
|
// @Summary Add a user to a team
|
||||||
|
@ -41,7 +44,7 @@ func (tm *TeamMember) Create(a web.Auth) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user exists
|
// Check if the user exists
|
||||||
user, err := GetUserByUsername(tm.Username)
|
user, err := user2.GetUserByUsername(tm.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -84,7 +87,7 @@ func (tm *TeamMember) Delete() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the numeric user id
|
// Find the numeric user id
|
||||||
user, err := GetUserByUsername(tm.Username)
|
user, err := user2.GetUserByUsername(tm.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,14 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTeamMember_Create(t *testing.T) {
|
func TestTeamMember_Create(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
// Dummy team member
|
// Dummy team member
|
||||||
dummyteammember := TeamMember{
|
dummyteammember := TeamMember{
|
||||||
|
@ -30,7 +33,7 @@ func TestTeamMember_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doer
|
// Doer
|
||||||
doer, err := GetUserByID(1)
|
doer, err := user.GetUserByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Insert a new team member
|
// Insert a new team member
|
||||||
|
@ -71,7 +74,7 @@ func TestTeamMember_Create(t *testing.T) {
|
||||||
dummyteammember.Username = "user9484"
|
dummyteammember.Username = "user9484"
|
||||||
err = dummyteammember.Create(doer)
|
err = dummyteammember.Create(doer)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||||
|
|
||||||
// Try adding a user to a team which does not exist
|
// Try adding a user to a team which does not exist
|
||||||
tm = TeamMember{TeamID: 94824, Username: "user1"}
|
tm = TeamMember{TeamID: 94824, Username: "user1"}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/metrics"
|
"code.vikunja.io/api/pkg/metrics"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ type Team struct {
|
||||||
CreatedByID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
CreatedByID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||||
|
|
||||||
// The user who created this team.
|
// The user who created this team.
|
||||||
CreatedBy *User `xorm:"-" json:"createdBy"`
|
CreatedBy *user.User `xorm:"-" json:"createdBy"`
|
||||||
// An array of all members in this team.
|
// An array of all members in this team.
|
||||||
Members []*TeamUser `xorm:"-" json:"members"`
|
Members []*TeamUser `xorm:"-" json:"members"`
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ func (Team) TableName() string {
|
||||||
// AfterLoad gets the created by user object
|
// AfterLoad gets the created by user object
|
||||||
func (t *Team) AfterLoad() {
|
func (t *Team) AfterLoad() {
|
||||||
// Get the owner
|
// Get the owner
|
||||||
t.CreatedBy, _ = GetUserByID(t.CreatedByID)
|
t.CreatedBy, _ = user.GetUserByID(t.CreatedByID)
|
||||||
|
|
||||||
// Get all members
|
// Get all members
|
||||||
x.Select("*").
|
x.Select("*").
|
||||||
|
@ -90,7 +91,7 @@ func (TeamMember) TableName() string {
|
||||||
|
|
||||||
// TeamUser is the team member type
|
// TeamUser is the team member type
|
||||||
type TeamUser struct {
|
type TeamUser struct {
|
||||||
User `xorm:"extends"`
|
user.User `xorm:"extends"`
|
||||||
// Whether or not the member is an admin of the team. See the docs for more about what a team admin can do
|
// Whether or not the member is an admin of the team. See the docs for more about what a team admin can do
|
||||||
Admin bool `json:"admin"`
|
Admin bool `json:"admin"`
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ func (t *Team) ReadAll(a web.Auth, search string, page int, perPage int) (result
|
||||||
// @Failure 500 {object} models.Message "Internal error"
|
// @Failure 500 {object} models.Message "Internal error"
|
||||||
// @Router /teams [put]
|
// @Router /teams [put]
|
||||||
func (t *Team) Create(a web.Auth) (err error) {
|
func (t *Team) Create(a web.Auth) (err error) {
|
||||||
doer, err := getUserWithError(a)
|
doer, err := user.GetFromAuth(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
|
@ -28,7 +30,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
CreatedByID int64
|
CreatedByID int64
|
||||||
CreatedBy *User
|
CreatedBy *user.User
|
||||||
Members []*TeamUser
|
Members []*TeamUser
|
||||||
Created int64
|
Created int64
|
||||||
Updated int64
|
Updated int64
|
||||||
|
@ -50,7 +52,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": true, "IsAdmin": true, "CanRead": true, "CanDelete": true, "CanUpdate": true},
|
want: map[string]bool{"CanCreate": true, "IsAdmin": true, "CanRead": true, "CanDelete": true, "CanUpdate": true},
|
||||||
},
|
},
|
||||||
|
@ -60,7 +62,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||||
ID: 300,
|
ID: 300,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 1},
|
a: &user.User{ID: 1},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
|
@ -70,13 +72,15 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||||
ID: 1,
|
ID: 1,
|
||||||
},
|
},
|
||||||
args: args{
|
args: args{
|
||||||
a: &User{ID: 4},
|
a: &user.User{ID: 4},
|
||||||
},
|
},
|
||||||
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
|
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
tm := &Team{
|
tm := &Team{
|
||||||
ID: tt.fields.ID,
|
ID: tt.fields.ID,
|
||||||
Name: tt.fields.Name,
|
Name: tt.fields.Name,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -30,7 +31,7 @@ func TestTeam_Create(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Doer
|
// Doer
|
||||||
doer, err := GetUserByID(1)
|
doer, err := user.GetUserByID(1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Insert it
|
// Insert it
|
||||||
|
|
|
@ -17,78 +17,49 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
|
||||||
_ "code.vikunja.io/api/pkg/config" // To trigger its init() which initializes the config
|
_ "code.vikunja.io/api/pkg/config" // To trigger its init() which initializes the config
|
||||||
"code.vikunja.io/api/pkg/db"
|
"code.vikunja.io/api/pkg/db"
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/mail"
|
"code.vikunja.io/api/pkg/mail"
|
||||||
"fmt"
|
|
||||||
"github.com/go-xorm/xorm"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"gopkg.in/testfixtures.v2"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetupTests takes care of seting up the db, fixtures etc.
|
// SetupTests takes care of seting up the db, fixtures etc.
|
||||||
// This is an extra function to be able to call the fixtures setup from the integration tests.
|
// This is an extra function to be able to call the fixtures setup from the integration tests.
|
||||||
func SetupTests(pathToRoot string) {
|
func SetupTests() {
|
||||||
var err error
|
var err error
|
||||||
fixturesDir := filepath.Join(pathToRoot, "pkg", "models", "fixtures")
|
x, err = db.CreateTestEngine()
|
||||||
if err = createTestEngine(fixturesDir); err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error creating test engine: %v\n", err)
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = x.Sync2(GetTables()...)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = db.InitTestFixtures(
|
||||||
|
"files",
|
||||||
|
"label_task",
|
||||||
|
"labels",
|
||||||
|
"link_sharing",
|
||||||
|
"list",
|
||||||
|
"namespaces",
|
||||||
|
"task_assignees",
|
||||||
|
"task_attachments",
|
||||||
|
"task_relations",
|
||||||
|
"task_reminders",
|
||||||
|
"tasks",
|
||||||
|
"team_list",
|
||||||
|
"team_members",
|
||||||
|
"team_namespaces",
|
||||||
|
"teams",
|
||||||
|
"users",
|
||||||
|
"users_list",
|
||||||
|
"users_namespace")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the pseudo mail queue
|
// Start the pseudo mail queue
|
||||||
mail.StartMailDaemon()
|
mail.StartMailDaemon()
|
||||||
|
|
||||||
// Create test database
|
|
||||||
if err = db.LoadFixtures(); err != nil {
|
|
||||||
log.Fatalf("Error preparing test database: %v", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTestEngine(fixturesDir string) error {
|
|
||||||
var err error
|
|
||||||
var fixturesHelper testfixtures.Helper = &testfixtures.SQLite{}
|
|
||||||
// If set, use the config we provided instead of normal
|
|
||||||
if os.Getenv("VIKUNJA_TESTS_USE_CONFIG") == "1" {
|
|
||||||
x, err = db.CreateTestEngine()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error getting test engine: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = initSchema(x)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.DatabaseType.GetString() == "mysql" {
|
|
||||||
fixturesHelper = &testfixtures.MySQL{}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
x, err = db.CreateTestEngine()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error getting test engine: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync dat shit
|
|
||||||
err = initSchema(x)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("sync database struct error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return db.InitFixtures(fixturesHelper, fixturesDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initSchema(tx *xorm.Engine) error {
|
|
||||||
return tx.Sync2(GetTables()...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initFixtures(t *testing.T) {
|
|
||||||
// Init db fixtures
|
|
||||||
err := db.LoadFixtures()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,26 @@
|
||||||
// Vikunja is a todo-list application to facilitate your life.
|
// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// This file is part of Vikunja.
|
||||||
|
//
|
||||||
|
// Vikunja is free software: you can redistribute it and/or modify
|
||||||
// it under the terms of the GNU General Public License as published by
|
// it under the terms of the GNU General Public License as published by
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
// (at your option) any later version.
|
// (at your option) any later version.
|
||||||
//
|
//
|
||||||
// This program is distributed in the hope that it will be useful,
|
// Vikunja is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import "github.com/go-xorm/builder"
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
// ListUsers returns a list with all users, filtered by an optional searchstring
|
"github.com/go-xorm/builder"
|
||||||
func ListUsers(searchterm string) (users []User, err error) {
|
)
|
||||||
|
|
||||||
if searchterm == "" {
|
|
||||||
err = x.Find(&users)
|
|
||||||
} else {
|
|
||||||
err = x.
|
|
||||||
Where("username LIKE ?", "%"+searchterm+"%").
|
|
||||||
Find(&users)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return []User{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return users, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListUIDs hold all kinds of user IDs from accounts who have somehow access to a list
|
// ListUIDs hold all kinds of user IDs from accounts who have somehow access to a list
|
||||||
type ListUIDs struct {
|
type ListUIDs struct {
|
||||||
|
@ -47,7 +33,7 @@ type ListUIDs struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListUsersFromList returns a list with all users who have access to a list, regardless of the method which gave them access
|
// ListUsersFromList returns a list with all users who have access to a list, regardless of the method which gave them access
|
||||||
func ListUsersFromList(l *List, search string) (users []*User, err error) {
|
func ListUsersFromList(l *List, search string) (users []*user.User, err error) {
|
||||||
|
|
||||||
userids := []*ListUIDs{}
|
userids := []*ListUIDs{}
|
||||||
|
|
|
@ -1,178 +0,0 @@
|
||||||
// Vikunja is a todo-list application to facilitate your life.
|
|
||||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"code.vikunja.io/api/pkg/utils"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCreateUser(t *testing.T) {
|
|
||||||
// Create test database
|
|
||||||
//assert.NoError(t, LoadFixtures())
|
|
||||||
|
|
||||||
// Get our doer
|
|
||||||
doer, err := GetUserByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Our dummy user for testing
|
|
||||||
dummyuser := &User{
|
|
||||||
Username: "testuu",
|
|
||||||
Password: "1234",
|
|
||||||
Email: "noone@example.com",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new user
|
|
||||||
createdUser, err := CreateUser(dummyuser)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Create a second new user
|
|
||||||
_, err = CreateUser(&User{Username: dummyuser.Username + "2", Email: dummyuser.Email + "m", Password: dummyuser.Password})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Check if it fails to create the same user again
|
|
||||||
_, err = CreateUser(dummyuser)
|
|
||||||
assert.Error(t, err)
|
|
||||||
|
|
||||||
// Check if it fails to create a user with just the same username
|
|
||||||
_, err = CreateUser(&User{Username: dummyuser.Username, Password: "12345", Email: "email@example.com"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrUsernameExists(err))
|
|
||||||
|
|
||||||
// Check if it fails to create one with the same email
|
|
||||||
_, err = CreateUser(&User{Username: "noone", Password: "1234", Email: dummyuser.Email})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrUserEmailExists(err))
|
|
||||||
|
|
||||||
// Check if it fails to create a user without password and username
|
|
||||||
_, err = CreateUser(&User{})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrNoUsernamePassword(err))
|
|
||||||
|
|
||||||
// Check if he exists
|
|
||||||
theuser, err := GetUser(createdUser)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Get by his ID
|
|
||||||
_, err = GetUserByID(theuser.ID)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Passing 0 as ID should return an error
|
|
||||||
_, err = GetUserByID(0)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
|
||||||
|
|
||||||
// Check the user credentials with an unverified email
|
|
||||||
_, err = CheckUserCredentials(&UserLogin{"user5", "1234"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrEmailNotConfirmed(err))
|
|
||||||
|
|
||||||
// Update everything and check again
|
|
||||||
_, err = x.Cols("is_active").Where("true").Update(User{IsActive: true})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
user, err := CheckUserCredentials(&UserLogin{"testuu", "1234"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, "testuu", user.Username)
|
|
||||||
|
|
||||||
// Check wrong password (should also fail)
|
|
||||||
_, err = CheckUserCredentials(&UserLogin{"testuu", "12345"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrWrongUsernameOrPassword(err))
|
|
||||||
|
|
||||||
// Check usercredentials for a nonexistent user (should fail)
|
|
||||||
_, err = CheckUserCredentials(&UserLogin{"dfstestuu", "1234"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrWrongUsernameOrPassword(err))
|
|
||||||
|
|
||||||
// Update the user
|
|
||||||
uuser, err := UpdateUser(&User{ID: theuser.ID, Password: "444444"})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, theuser.Password, uuser.Password) // Password should not change
|
|
||||||
assert.Equal(t, theuser.Username, uuser.Username) // Username should not change either
|
|
||||||
|
|
||||||
// Try updating one which does not exist
|
|
||||||
_, err = UpdateUser(&User{ID: 99999, Username: "dg"})
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
|
||||||
|
|
||||||
// Update a users password
|
|
||||||
newpassword := "55555"
|
|
||||||
err = UpdateUserPassword(theuser, newpassword)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Check if it was changed
|
|
||||||
_, err = CheckUserCredentials(&UserLogin{theuser.Username, newpassword})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Check if the searchterm works
|
|
||||||
all, err := ListUsers("test")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, len(all) > 0)
|
|
||||||
|
|
||||||
all, err = ListUsers("")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, len(all) > 0)
|
|
||||||
|
|
||||||
// Try updating the password of a nonexistent user (should fail)
|
|
||||||
err = UpdateUserPassword(&User{ID: 9999}, newpassword)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrUserDoesNotExist(err))
|
|
||||||
|
|
||||||
// Delete it
|
|
||||||
err = DeleteUserByID(theuser.ID, doer)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Try deleting one with ID = 0
|
|
||||||
err = DeleteUserByID(0, doer)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrIDCannotBeZero(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUserPasswordReset(t *testing.T) {
|
|
||||||
// Request a new token
|
|
||||||
tr := &PasswordTokenRequest{
|
|
||||||
Email: "user1@example.com",
|
|
||||||
}
|
|
||||||
err := RequestUserPasswordResetToken(tr)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Get the token / inside the user object
|
|
||||||
userWithToken, err := GetUserByID(1)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Try resetting it
|
|
||||||
reset := &PasswordReset{
|
|
||||||
Token: userWithToken.PasswordResetToken,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try resetting it without a password
|
|
||||||
reset.NewPassword = ""
|
|
||||||
err = UserPasswordReset(reset)
|
|
||||||
assert.True(t, IsErrNoUsernamePassword(err))
|
|
||||||
|
|
||||||
// Reset it
|
|
||||||
reset.NewPassword = "1234"
|
|
||||||
err = UserPasswordReset(reset)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// Try resetting it with a wrong token
|
|
||||||
reset.Token = utils.MakeRandomString(400)
|
|
||||||
err = UserPasswordReset(reset)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.True(t, IsErrInvalidPasswordResetToken(err))
|
|
||||||
}
|
|
|
@ -1,38 +1,51 @@
|
||||||
|
// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is part of Vikunja.
|
||||||
|
//
|
||||||
|
// Vikunja is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Vikunja is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/db"
|
"code.vikunja.io/api/pkg/db"
|
||||||
"github.com/stretchr/testify/assert"
|
"code.vikunja.io/api/pkg/user"
|
||||||
"gopkg.in/d4l3k/messagediff.v1"
|
"gopkg.in/d4l3k/messagediff.v1"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestListUsersFromList(t *testing.T) {
|
func TestListUsersFromList(t *testing.T) {
|
||||||
|
testuser1 := &user.User{
|
||||||
err := db.LoadFixtures()
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
testuser1 := &User{
|
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808",
|
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808",
|
||||||
}
|
}
|
||||||
testuser2 := &User{
|
testuser2 := &user.User{
|
||||||
ID: 2,
|
ID: 2,
|
||||||
Username: "user2",
|
Username: "user2",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||||
}
|
}
|
||||||
testuser3 := &User{
|
testuser3 := &user.User{
|
||||||
ID: 3,
|
ID: 3,
|
||||||
Username: "user3",
|
Username: "user3",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
AvatarURL: "97d6d9441ff85fdc730e02a6068d267b",
|
AvatarURL: "97d6d9441ff85fdc730e02a6068d267b",
|
||||||
PasswordResetToken: "passwordresettesttoken",
|
PasswordResetToken: "passwordresettesttoken",
|
||||||
}
|
}
|
||||||
testuser4 := &User{
|
testuser4 := &user.User{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Username: "user4",
|
Username: "user4",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -40,7 +53,7 @@ func TestListUsersFromList(t *testing.T) {
|
||||||
AvatarURL: "7e65550957227bd38fe2d7fbc6fd2f7b",
|
AvatarURL: "7e65550957227bd38fe2d7fbc6fd2f7b",
|
||||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||||
}
|
}
|
||||||
testuser5 := &User{
|
testuser5 := &user.User{
|
||||||
ID: 5,
|
ID: 5,
|
||||||
Username: "user5",
|
Username: "user5",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -48,56 +61,56 @@ func TestListUsersFromList(t *testing.T) {
|
||||||
AvatarURL: "cfa35b8cd2ec278026357769582fa563",
|
AvatarURL: "cfa35b8cd2ec278026357769582fa563",
|
||||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||||
}
|
}
|
||||||
testuser6 := &User{
|
testuser6 := &user.User{
|
||||||
ID: 6,
|
ID: 6,
|
||||||
Username: "user6",
|
Username: "user6",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed",
|
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed",
|
||||||
}
|
}
|
||||||
testuser7 := &User{
|
testuser7 := &user.User{
|
||||||
ID: 7,
|
ID: 7,
|
||||||
Username: "user7",
|
Username: "user7",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "e80a711d4de44c30054806ebbd488464",
|
AvatarURL: "e80a711d4de44c30054806ebbd488464",
|
||||||
}
|
}
|
||||||
testuser8 := &User{
|
testuser8 := &user.User{
|
||||||
ID: 8,
|
ID: 8,
|
||||||
Username: "user8",
|
Username: "user8",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "2b9b320416cd31020bb6844c3fadefd1",
|
AvatarURL: "2b9b320416cd31020bb6844c3fadefd1",
|
||||||
}
|
}
|
||||||
testuser9 := &User{
|
testuser9 := &user.User{
|
||||||
ID: 9,
|
ID: 9,
|
||||||
Username: "user9",
|
Username: "user9",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "f784fdb21d26dd2c64f5135f35ec401f",
|
AvatarURL: "f784fdb21d26dd2c64f5135f35ec401f",
|
||||||
}
|
}
|
||||||
testuser10 := &User{
|
testuser10 := &user.User{
|
||||||
ID: 10,
|
ID: 10,
|
||||||
Username: "user10",
|
Username: "user10",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "fce8ff4ff56d75ad587d1bbaa5ef0563",
|
AvatarURL: "fce8ff4ff56d75ad587d1bbaa5ef0563",
|
||||||
}
|
}
|
||||||
testuser11 := &User{
|
testuser11 := &user.User{
|
||||||
ID: 11,
|
ID: 11,
|
||||||
Username: "user11",
|
Username: "user11",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "ad6d67d0c4495e186010732a7d360028",
|
AvatarURL: "ad6d67d0c4495e186010732a7d360028",
|
||||||
}
|
}
|
||||||
testuser12 := &User{
|
testuser12 := &user.User{
|
||||||
ID: 12,
|
ID: 12,
|
||||||
Username: "user12",
|
Username: "user12",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
AvatarURL: "ef1debc1364806281c42eeedfdeb943b",
|
AvatarURL: "ef1debc1364806281c42eeedfdeb943b",
|
||||||
}
|
}
|
||||||
testuser13 := &User{
|
testuser13 := &user.User{
|
||||||
ID: 13,
|
ID: 13,
|
||||||
Username: "user13",
|
Username: "user13",
|
||||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||||
|
@ -112,19 +125,19 @@ func TestListUsersFromList(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
wantUsers []*User
|
wantUsers []*user.User
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Check owner only",
|
name: "Check owner only",
|
||||||
args: args{l: &List{ID: 18, OwnerID: 7}},
|
args: args{l: &List{ID: 18, OwnerID: 7}},
|
||||||
wantUsers: []*User{testuser7},
|
wantUsers: []*user.User{testuser7},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// This list has another different user shared for each possible method
|
// This list has another different user shared for each possible method
|
||||||
name: "Check with owner and other users",
|
name: "Check with owner and other users",
|
||||||
args: args{l: &List{ID: 19, OwnerID: 7}},
|
args: args{l: &List{ID: 19, OwnerID: 7}},
|
||||||
wantUsers: []*User{
|
wantUsers: []*user.User{
|
||||||
testuser1, // Shared Via Team readonly
|
testuser1, // Shared Via Team readonly
|
||||||
testuser2, // Shared Via Team write
|
testuser2, // Shared Via Team write
|
||||||
testuser3, // Shared Via Team admin
|
testuser3, // Shared Via Team admin
|
||||||
|
@ -147,6 +160,8 @@ func TestListUsersFromList(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
gotUsers, err := ListUsersFromList(tt.args.l, tt.args.search)
|
gotUsers, err := ListUsersFromList(tt.args.l, tt.args.search)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("ListUsersFromList() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("ListUsersFromList() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
|
|
@ -19,12 +19,13 @@ package migration
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InsertFromStructure takes a fully nested Vikunja data structure and a user and then creates everything for this user
|
// InsertFromStructure takes a fully nested Vikunja data structure and a user and then creates everything for this user
|
||||||
// (Namespaces, tasks, etc. Even attachments and relations.)
|
// (Namespaces, tasks, etc. Even attachments and relations.)
|
||||||
func InsertFromStructure(str []*models.NamespaceWithLists, user *models.User) (err error) {
|
func InsertFromStructure(str []*models.NamespaceWithLists, user *user.User) (err error) {
|
||||||
|
|
||||||
// Create all namespaces
|
// Create all namespaces
|
||||||
for _, n := range str {
|
for _, n := range str {
|
||||||
|
|
|
@ -19,6 +19,7 @@ package handler
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
"code.vikunja.io/api/pkg/modules/migration"
|
"code.vikunja.io/api/pkg/modules/migration"
|
||||||
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -53,7 +54,7 @@ func (mw *MigrationWeb) Migrate(c echo.Context) error {
|
||||||
ms := mw.MigrationStruct()
|
ms := mw.MigrationStruct()
|
||||||
|
|
||||||
// Get the user from context
|
// Get the user from context
|
||||||
user, err := models.GetCurrentUser(c)
|
user, err := user2.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
@ -82,7 +83,7 @@ func (mw *MigrationWeb) Migrate(c echo.Context) error {
|
||||||
func (mw *MigrationWeb) Status(c echo.Context) error {
|
func (mw *MigrationWeb) Status(c echo.Context) error {
|
||||||
ms := mw.MigrationStruct()
|
ms := mw.MigrationStruct()
|
||||||
|
|
||||||
user, err := models.GetCurrentUser(c)
|
user, err := user2.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package migration
|
package migration
|
||||||
|
|
||||||
import "code.vikunja.io/api/pkg/models"
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
|
)
|
||||||
|
|
||||||
// Status represents this migration status
|
// Status represents this migration status
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
@ -32,7 +34,7 @@ func (s *Status) TableName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMigrationStatus sets the migration status for a user
|
// SetMigrationStatus sets the migration status for a user
|
||||||
func SetMigrationStatus(m Migrator, u *models.User) (err error) {
|
func SetMigrationStatus(m Migrator, u *user.User) (err error) {
|
||||||
status := &Status{
|
status := &Status{
|
||||||
UserID: u.ID,
|
UserID: u.ID,
|
||||||
MigratorName: m.Name(),
|
MigratorName: m.Name(),
|
||||||
|
@ -42,7 +44,7 @@ func SetMigrationStatus(m Migrator, u *models.User) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMigrationStatus returns the migration status for a migration and a user
|
// GetMigrationStatus returns the migration status for a migration and a user
|
||||||
func GetMigrationStatus(m Migrator, u *models.User) (status *Status, err error) {
|
func GetMigrationStatus(m Migrator, u *user.User) (status *Status, err error) {
|
||||||
status = &Status{}
|
status = &Status{}
|
||||||
_, err = x.Where("user_id = ? and migrator_name = ?", u.ID, m.Name()).Desc("id").Get(status)
|
_, err = x.Where("user_id = ? and migrator_name = ?", u.ID, m.Name()).Desc("id").Get(status)
|
||||||
return
|
return
|
||||||
|
|
|
@ -17,13 +17,15 @@
|
||||||
|
|
||||||
package migration
|
package migration
|
||||||
|
|
||||||
import "code.vikunja.io/api/pkg/models"
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
|
)
|
||||||
|
|
||||||
// Migrator is the basic migrator interface which is shared among all migrators
|
// Migrator is the basic migrator interface which is shared among all migrators
|
||||||
type Migrator interface {
|
type Migrator interface {
|
||||||
// Migrate is the interface used to migrate a user's tasks from another platform to vikunja.
|
// Migrate is the interface used to migrate a user's tasks from another platform to vikunja.
|
||||||
// The user object is the user who's tasks will be migrated.
|
// The user object is the user who's tasks will be migrated.
|
||||||
Migrate(user *models.User) error
|
Migrate(user *user.User) error
|
||||||
// AuthURL returns a url for clients to authenticate against.
|
// AuthURL returns a url for clients to authenticate against.
|
||||||
// The use case for this are Oauth flows, where the server token should remain hidden and not
|
// The use case for this are Oauth flows, where the server token should remain hidden and not
|
||||||
// known to the frontend.
|
// known to the frontend.
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
"code.vikunja.io/api/pkg/modules/migration"
|
"code.vikunja.io/api/pkg/modules/migration"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/api/pkg/utils"
|
"code.vikunja.io/api/pkg/utils"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -341,7 +342,7 @@ func makeAuthGetRequest(token *wunderlistAuthToken, urlPart string, v interface{
|
||||||
// @Success 200 {object} models.Message "A message telling you everything was migrated successfully."
|
// @Success 200 {object} models.Message "A message telling you everything was migrated successfully."
|
||||||
// @Failure 500 {object} models.Message "Internal server error"
|
// @Failure 500 {object} models.Message "Internal server error"
|
||||||
// @Router /migration/wunderlist/migrate [post]
|
// @Router /migration/wunderlist/migrate [post]
|
||||||
func (w *Migration) Migrate(user *models.User) (err error) {
|
func (w *Migration) Migrate(user *user.User) (err error) {
|
||||||
|
|
||||||
log.Debugf("[Wunderlist migration] Starting wunderlist migration for user %d", user.ID)
|
log.Debugf("[Wunderlist migration] Starting wunderlist migration for user %d", user.ID)
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package v1
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
@ -34,7 +35,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewUserJWTAuthtoken generates and signes a new jwt token for a user. This is a global function to be able to call it from integration tests.
|
// NewUserJWTAuthtoken generates and signes a new jwt token for a user. This is a global function to be able to call it from integration tests.
|
||||||
func NewUserJWTAuthtoken(user *models.User) (token string, err error) {
|
func NewUserJWTAuthtoken(user *user.User) (token string, err error) {
|
||||||
t := jwt.New(jwt.SigningMethodHS256)
|
t := jwt.New(jwt.SigningMethodHS256)
|
||||||
|
|
||||||
// Set claims
|
// Set claims
|
||||||
|
@ -78,7 +79,7 @@ func GetAuthFromClaims(c echo.Context) (a web.Auth, err error) {
|
||||||
return models.GetLinkShareFromClaims(claims)
|
return models.GetLinkShareFromClaims(claims)
|
||||||
}
|
}
|
||||||
if typ == AuthTypeUser {
|
if typ == AuthTypeUser {
|
||||||
return models.GetUserFromClaims(claims)
|
return user.GetUserFromClaims(claims)
|
||||||
}
|
}
|
||||||
return nil, echo.NewHTTPError(http.StatusBadRequest, models.Message{Message: "Invalid JWT token."})
|
return nil, echo.NewHTTPError(http.StatusBadRequest, models.Message{Message: "Invalid JWT token."})
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -46,7 +47,7 @@ func GetListsByNamespaceID(c echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the lists
|
// Get the lists
|
||||||
doer, err := models.GetCurrentUser(c)
|
doer, err := user.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
@ -73,7 +74,7 @@ func getNamespace(c echo.Context) (namespace *models.Namespace, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user has acces to that namespace
|
// Check if the user has acces to that namespace
|
||||||
user, err := models.GetCurrentUser(c)
|
user, err := user.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
@ -41,13 +42,13 @@ type Token struct {
|
||||||
// @Failure 403 {object} models.Message "Invalid username or password."
|
// @Failure 403 {object} models.Message "Invalid username or password."
|
||||||
// @Router /login [post]
|
// @Router /login [post]
|
||||||
func Login(c echo.Context) error {
|
func Login(c echo.Context) error {
|
||||||
u := models.UserLogin{}
|
u := user2.Login{}
|
||||||
if err := c.Bind(&u); err != nil {
|
if err := c.Bind(&u); err != nil {
|
||||||
return c.JSON(http.StatusBadRequest, models.Message{"Please provide a username and password."})
|
return c.JSON(http.StatusBadRequest, models.Message{"Please provide a username and password."})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check user
|
// Check user
|
||||||
user, err := models.CheckUserCredentials(&u)
|
user, err := user2.CheckUserCredentials(&u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
@ -80,7 +81,7 @@ func RenewToken(c echo.Context) error {
|
||||||
return echo.ErrBadRequest
|
return echo.ErrBadRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := models.GetUserFromClaims(claims)
|
user, err := user2.GetUserFromClaims(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -45,7 +46,7 @@ func UploadTaskAttachment(c echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rights check
|
// Rights check
|
||||||
user, err := models.GetCurrentUser(c)
|
user, err := user2.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
@ -114,7 +115,7 @@ func GetTaskAttachment(c echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rights check
|
// Rights check
|
||||||
user, err := models.GetCurrentUser(c)
|
user, err := user2.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package v1
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -40,13 +41,20 @@ func RegisterUser(c echo.Context) error {
|
||||||
return echo.ErrNotFound
|
return echo.ErrNotFound
|
||||||
}
|
}
|
||||||
// Check for Request Content
|
// Check for Request Content
|
||||||
var datUser *models.APIUserPassword
|
var datUser *user.APIUserPassword
|
||||||
if err := c.Bind(&datUser); err != nil {
|
if err := c.Bind(&datUser); err != nil {
|
||||||
return c.JSON(http.StatusBadRequest, models.Message{"No or invalid user model provided."})
|
return c.JSON(http.StatusBadRequest, models.Message{"No or invalid user model provided."})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the user
|
// Insert the user
|
||||||
newUser, err := models.CreateUser(datUser.APIFormat())
|
newUser, err := user.CreateUser(datUser.APIFormat())
|
||||||
|
if err != nil {
|
||||||
|
return handler.HandleHTTPError(err, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add its namespace
|
||||||
|
newN := &models.Namespace{Name: newUser.Username, Description: newUser.Username + "'s namespace.", Owner: newUser}
|
||||||
|
err = newN.Create(newUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -36,12 +37,12 @@ import (
|
||||||
// @Router /user/confirm [post]
|
// @Router /user/confirm [post]
|
||||||
func UserConfirmEmail(c echo.Context) error {
|
func UserConfirmEmail(c echo.Context) error {
|
||||||
// Check for Request Content
|
// Check for Request Content
|
||||||
var emailConfirm models.EmailConfirm
|
var emailConfirm user.EmailConfirm
|
||||||
if err := c.Bind(&emailConfirm); err != nil {
|
if err := c.Bind(&emailConfirm); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "No token provided.")
|
return echo.NewHTTPError(http.StatusBadRequest, "No token provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.UserEmailConfirm(&emailConfirm)
|
err := user.ConfirmEmail(&emailConfirm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
// Vikunja is a todo-list application to facilitate your life.
|
|
||||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package v1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"code.vikunja.io/api/pkg/models"
|
|
||||||
"code.vikunja.io/web/handler"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// UserDelete is the handler to delete a user
|
|
||||||
func UserDelete(c echo.Context) error {
|
|
||||||
|
|
||||||
// TODO: only allow users to allow itself
|
|
||||||
|
|
||||||
id := c.Param("id")
|
|
||||||
|
|
||||||
// Make int
|
|
||||||
userID, err := strconv.ParseInt(id, 10, 64)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return c.JSON(http.StatusBadRequest, models.Message{"User ID is invalid."})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the user exists
|
|
||||||
_, err = models.GetUserByID(userID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if models.IsErrUserDoesNotExist(err) {
|
|
||||||
return c.JSON(http.StatusNotFound, models.Message{"The user does not exist."})
|
|
||||||
}
|
|
||||||
return c.JSON(http.StatusInternalServerError, models.Message{"Could not get user."})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the doer options
|
|
||||||
doer, err := models.GetCurrentUser(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete it
|
|
||||||
err = models.DeleteUserByID(userID, doer)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return handler.HandleHTTPError(err, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, models.Message{"success"})
|
|
||||||
}
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -38,7 +39,7 @@ import (
|
||||||
// @Router /users [get]
|
// @Router /users [get]
|
||||||
func UserList(c echo.Context) error {
|
func UserList(c echo.Context) error {
|
||||||
s := c.QueryParam("s")
|
s := c.QueryParam("s")
|
||||||
users, err := models.ListUsers(s)
|
users, err := user.ListUsers(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +73,7 @@ func ListUsersForList(c echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
list := models.List{ID: listID}
|
list := models.List{ID: listID}
|
||||||
currentUser, err := models.GetCurrentUser(c)
|
currentUser, err := user.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -36,12 +37,12 @@ import (
|
||||||
// @Router /user/password/reset [post]
|
// @Router /user/password/reset [post]
|
||||||
func UserResetPassword(c echo.Context) error {
|
func UserResetPassword(c echo.Context) error {
|
||||||
// Check for Request Content
|
// Check for Request Content
|
||||||
var pwReset models.PasswordReset
|
var pwReset user.PasswordReset
|
||||||
if err := c.Bind(&pwReset); err != nil {
|
if err := c.Bind(&pwReset); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "No password provided.")
|
return echo.NewHTTPError(http.StatusBadRequest, "No password provided.")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.UserPasswordReset(&pwReset)
|
err := user.ResetPassword(&pwReset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ func UserResetPassword(c echo.Context) error {
|
||||||
// @Router /user/password/token [post]
|
// @Router /user/password/token [post]
|
||||||
func UserRequestResetPasswordToken(c echo.Context) error {
|
func UserRequestResetPasswordToken(c echo.Context) error {
|
||||||
// Check for Request Content
|
// Check for Request Content
|
||||||
var pwTokenReset models.PasswordTokenRequest
|
var pwTokenReset user.PasswordTokenRequest
|
||||||
if err := c.Bind(&pwTokenReset); err != nil {
|
if err := c.Bind(&pwTokenReset); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "No username provided.")
|
return echo.NewHTTPError(http.StatusBadRequest, "No username provided.")
|
||||||
}
|
}
|
||||||
|
@ -71,7 +72,7 @@ func UserRequestResetPasswordToken(c echo.Context) error {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, err)
|
return echo.NewHTTPError(http.StatusBadRequest, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := models.RequestUserPasswordResetToken(&pwTokenReset)
|
err := user.RequestUserPasswordResetToken(&pwTokenReset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -35,12 +35,12 @@ import (
|
||||||
// @Failure 500 {object} models.Message "Internal server error."
|
// @Failure 500 {object} models.Message "Internal server error."
|
||||||
// @Router /user [get]
|
// @Router /user [get]
|
||||||
func UserShow(c echo.Context) error {
|
func UserShow(c echo.Context) error {
|
||||||
userInfos, err := models.GetCurrentUser(c)
|
userInfos, err := user2.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
|
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := models.GetUserByID(userInfos.ID)
|
user, err := user2.GetUserByID(userInfos.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -44,7 +45,7 @@ type UserPassword struct {
|
||||||
// @Router /user/password [post]
|
// @Router /user/password [post]
|
||||||
func UserChangePassword(c echo.Context) error {
|
func UserChangePassword(c echo.Context) error {
|
||||||
// Check if the user is itself
|
// Check if the user is itself
|
||||||
doer, err := models.GetCurrentUser(c)
|
doer, err := user.GetCurrentUser(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
|
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
|
||||||
}
|
}
|
||||||
|
@ -56,16 +57,16 @@ func UserChangePassword(c echo.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if newPW.OldPassword == "" {
|
if newPW.OldPassword == "" {
|
||||||
return handler.HandleHTTPError(models.ErrEmptyOldPassword{}, c)
|
return handler.HandleHTTPError(user.ErrEmptyOldPassword{}, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the current password
|
// Check the current password
|
||||||
if _, err = models.CheckUserCredentials(&models.UserLogin{Username: doer.Username, Password: newPW.OldPassword}); err != nil {
|
if _, err = user.CheckUserCredentials(&user.Login{Username: doer.Username, Password: newPW.OldPassword}); err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the password
|
// Update the password
|
||||||
if err = models.UpdateUserPassword(doer, newPW.NewPassword); err != nil {
|
if err = user.UpdateUserPassword(doer, newPW.NewPassword); err != nil {
|
||||||
return handler.HandleHTTPError(err, c)
|
return handler.HandleHTTPError(err, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
@ -31,10 +32,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getBasicAuthUserFromContext(c echo.Context) (user models.User, err error) {
|
func getBasicAuthUserFromContext(c echo.Context) (user.User, error) {
|
||||||
u, is := c.Get("userBasicAuth").(models.User)
|
u, is := c.Get("userBasicAuth").(user.User)
|
||||||
if !is {
|
if !is {
|
||||||
return models.User{}, fmt.Errorf("user is not user element, is %s", reflect.TypeOf(c.Get("userBasicAuth")))
|
return user.User{}, fmt.Errorf("user is not user element, is %s", reflect.TypeOf(c.Get("userBasicAuth")))
|
||||||
}
|
}
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package caldav
|
||||||
import (
|
import (
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
user2 "code.vikunja.io/api/pkg/user"
|
||||||
"github.com/samedi/caldav-go/data"
|
"github.com/samedi/caldav-go/data"
|
||||||
"github.com/samedi/caldav-go/errs"
|
"github.com/samedi/caldav-go/errs"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -39,7 +40,7 @@ type VikunjaCaldavListStorage struct {
|
||||||
// Used when handling a single task, like updating
|
// Used when handling a single task, like updating
|
||||||
task *models.Task
|
task *models.Task
|
||||||
// The current user
|
// The current user
|
||||||
user *models.User
|
user *user2.User
|
||||||
isPrincipal bool
|
isPrincipal bool
|
||||||
isEntry bool // Entry level handling should only return a link to the principal url
|
isEntry bool // Entry level handling should only return a link to the principal url
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/metrics"
|
"code.vikunja.io/api/pkg/metrics"
|
||||||
"code.vikunja.io/api/pkg/models"
|
"code.vikunja.io/api/pkg/models"
|
||||||
v1 "code.vikunja.io/api/pkg/routes/api/v1"
|
v1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"time"
|
"time"
|
||||||
|
@ -51,7 +52,7 @@ func setupMetrics(a *echo.Group) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
metrics.UserCountKey,
|
metrics.UserCountKey,
|
||||||
models.User{},
|
user.User{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
metrics.NamespaceCountKey,
|
metrics.NamespaceCountKey,
|
||||||
|
|
|
@ -53,6 +53,7 @@ import (
|
||||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||||
"code.vikunja.io/api/pkg/routes/caldav"
|
"code.vikunja.io/api/pkg/routes/caldav"
|
||||||
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
|
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
|
||||||
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"code.vikunja.io/web/handler"
|
"code.vikunja.io/web/handler"
|
||||||
"github.com/asaskevich/govalidator"
|
"github.com/asaskevich/govalidator"
|
||||||
|
@ -407,11 +408,11 @@ func registerCalDavRoutes(c *echo.Group) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func caldavBasicAuth(username, password string, c echo.Context) (bool, error) {
|
func caldavBasicAuth(username, password string, c echo.Context) (bool, error) {
|
||||||
creds := &models.UserLogin{
|
creds := &user.Login{
|
||||||
Username: username,
|
Username: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
}
|
}
|
||||||
u, err := models.CheckUserCredentials(creds)
|
u, err := user.CheckUserCredentials(creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error during basic auth for caldav: %v", err)
|
log.Errorf("Error during basic auth for caldav: %v", err)
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is part of Vikunja.
|
||||||
|
//
|
||||||
|
// Vikunja is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Vikunja is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/config"
|
||||||
|
"code.vikunja.io/api/pkg/db"
|
||||||
|
"code.vikunja.io/api/pkg/log"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var x *xorm.Engine
|
||||||
|
|
||||||
|
// InitDB sets up the database connection to use in this module
|
||||||
|
func InitDB() (err error) {
|
||||||
|
x, err = db.CreateDBEngine()
|
||||||
|
if err != nil {
|
||||||
|
log.Criticalf("Could not connect to db: %v", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
if config.CacheEnabled.GetBool() && config.CacheType.GetString() == "redis" {
|
||||||
|
db.RegisterTableStructsForCache(GetTables())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTables returns all structs which are also a table.
|
||||||
|
func GetTables() []interface{} {
|
||||||
|
return []interface{}{
|
||||||
|
&User{},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,291 @@
|
||||||
|
// Copyright2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This file is part of Vikunja.
|
||||||
|
//
|
||||||
|
// Vikunja is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// Vikunja is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.vikunja.io/web"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// =====================
|
||||||
|
// User Operation Errors
|
||||||
|
// =====================
|
||||||
|
|
||||||
|
// ErrUsernameExists represents a "UsernameAlreadyExists" kind of error.
|
||||||
|
type ErrUsernameExists struct {
|
||||||
|
UserID int64
|
||||||
|
Username string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUsernameExists checks if an error is a ErrUsernameExists.
|
||||||
|
func IsErrUsernameExists(err error) bool {
|
||||||
|
_, ok := err.(ErrUsernameExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUsernameExists) Error() string {
|
||||||
|
return fmt.Sprintf("User with that username already exists [user id: %d, username: %s]", err.UserID, err.Username)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorCodeUsernameExists holds the unique world-error code of this error
|
||||||
|
const ErrorCodeUsernameExists = 1001
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrUsernameExists) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUsernameExists, Message: "A user with this username already exists."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUserEmailExists represents a "UserEmailExists" kind of error.
|
||||||
|
type ErrUserEmailExists struct {
|
||||||
|
UserID int64
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUserEmailExists checks if an error is a ErrUserEmailExists.
|
||||||
|
func IsErrUserEmailExists(err error) bool {
|
||||||
|
_, ok := err.(ErrUserEmailExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUserEmailExists) Error() string {
|
||||||
|
return fmt.Sprintf("User with that email already exists [user id: %d, email: %s]", err.UserID, err.Email)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorCodeUserEmailExists holds the unique world-error code of this error
|
||||||
|
const ErrorCodeUserEmailExists = 1002
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrUserEmailExists) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUserEmailExists, Message: "A user with this email address already exists."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNoUsernamePassword represents a "NoUsernamePassword" kind of error.
|
||||||
|
type ErrNoUsernamePassword struct{}
|
||||||
|
|
||||||
|
// IsErrNoUsernamePassword checks if an error is a ErrNoUsernamePassword.
|
||||||
|
func IsErrNoUsernamePassword(err error) bool {
|
||||||
|
_, ok := err.(ErrNoUsernamePassword)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrNoUsernamePassword) Error() string {
|
||||||
|
return fmt.Sprintf("No username and password provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeNoUsernamePassword holds the unique world-error code of this error
|
||||||
|
const ErrCodeNoUsernamePassword = 1004
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrNoUsernamePassword) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeNoUsernamePassword, Message: "Please specify a username and a password."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUserDoesNotExist represents a "UserDoesNotExist" kind of error.
|
||||||
|
type ErrUserDoesNotExist struct {
|
||||||
|
UserID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrUserDoesNotExist checks if an error is a ErrUserDoesNotExist.
|
||||||
|
func IsErrUserDoesNotExist(err error) bool {
|
||||||
|
_, ok := err.(ErrUserDoesNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUserDoesNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("User does not exist [user id: %d]", err.UserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeUserDoesNotExist holds the unique world-error code of this error
|
||||||
|
const ErrCodeUserDoesNotExist = 1005
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrUserDoesNotExist) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeUserDoesNotExist, Message: "The user does not exist."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCouldNotGetUserID represents a "ErrCouldNotGetUserID" kind of error.
|
||||||
|
type ErrCouldNotGetUserID struct{}
|
||||||
|
|
||||||
|
// IsErrCouldNotGetUserID checks if an error is a ErrCouldNotGetUserID.
|
||||||
|
func IsErrCouldNotGetUserID(err error) bool {
|
||||||
|
_, ok := err.(ErrCouldNotGetUserID)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrCouldNotGetUserID) Error() string {
|
||||||
|
return fmt.Sprintf("Could not get user ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeCouldNotGetUserID holds the unique world-error code of this error
|
||||||
|
const ErrCodeCouldNotGetUserID = 1006
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrCouldNotGetUserID) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeCouldNotGetUserID, Message: "Could not get user id."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNoPasswordResetToken represents an error where no password reset token exists for that user
|
||||||
|
type ErrNoPasswordResetToken struct {
|
||||||
|
UserID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrNoPasswordResetToken) Error() string {
|
||||||
|
return fmt.Sprintf("No token to reset a password [UserID: %d]", err.UserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeNoPasswordResetToken holds the unique world-error code of this error
|
||||||
|
const ErrCodeNoPasswordResetToken = 1008
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrNoPasswordResetToken) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeNoPasswordResetToken, Message: "No token to reset a user's password provided."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidPasswordResetToken is an error where the password reset token is invalid
|
||||||
|
type ErrInvalidPasswordResetToken struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrInvalidPasswordResetToken) Error() string {
|
||||||
|
return fmt.Sprintf("Invalid token to reset a password [Token: %s]", err.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeInvalidPasswordResetToken holds the unique world-error code of this error
|
||||||
|
const ErrCodeInvalidPasswordResetToken = 1009
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrInvalidPasswordResetToken) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidPasswordResetToken, Message: "Invalid token to reset a user's password."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrInvalidPasswordResetToken checks if an error is a ErrInvalidPasswordResetToken.
|
||||||
|
func IsErrInvalidPasswordResetToken(err error) bool {
|
||||||
|
_, ok := err.(ErrInvalidPasswordResetToken)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidEmailConfirmToken is an error where the email confirm token is invalid
|
||||||
|
type ErrInvalidEmailConfirmToken struct {
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrInvalidEmailConfirmToken) Error() string {
|
||||||
|
return fmt.Sprintf("Invalid email confirm token [Token: %s]", err.Token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeInvalidEmailConfirmToken holds the unique world-error code of this error
|
||||||
|
const ErrCodeInvalidEmailConfirmToken = 1010
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrInvalidEmailConfirmToken) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidEmailConfirmToken, Message: "Invalid email confirm token."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrInvalidEmailConfirmToken checks if an error is a ErrInvalidEmailConfirmToken.
|
||||||
|
func IsErrInvalidEmailConfirmToken(err error) bool {
|
||||||
|
_, ok := err.(ErrInvalidEmailConfirmToken)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrWrongUsernameOrPassword is an error where the email was not confirmed
|
||||||
|
type ErrWrongUsernameOrPassword struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrWrongUsernameOrPassword) Error() string {
|
||||||
|
return fmt.Sprintf("Wrong username or password")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeWrongUsernameOrPassword holds the unique world-error code of this error
|
||||||
|
const ErrCodeWrongUsernameOrPassword = 1011
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrWrongUsernameOrPassword) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeWrongUsernameOrPassword, Message: "Wrong username or password."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrWrongUsernameOrPassword checks if an error is a IsErrEmailNotConfirmed.
|
||||||
|
func IsErrWrongUsernameOrPassword(err error) bool {
|
||||||
|
_, ok := err.(ErrWrongUsernameOrPassword)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrEmailNotConfirmed is an error where the email was not confirmed
|
||||||
|
type ErrEmailNotConfirmed struct {
|
||||||
|
UserID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrEmailNotConfirmed) Error() string {
|
||||||
|
return fmt.Sprintf("Email is not confirmed [UserID: %d]", err.UserID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeEmailNotConfirmed holds the unique world-error code of this error
|
||||||
|
const ErrCodeEmailNotConfirmed = 1012
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrEmailNotConfirmed) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmailNotConfirmed, Message: "Please confirm your email address."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrEmailNotConfirmed checks if an error is a IsErrEmailNotConfirmed.
|
||||||
|
func IsErrEmailNotConfirmed(err error) bool {
|
||||||
|
_, ok := err.(ErrEmailNotConfirmed)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrEmptyNewPassword represents a "EmptyNewPassword" kind of error.
|
||||||
|
type ErrEmptyNewPassword struct{}
|
||||||
|
|
||||||
|
// IsErrEmptyNewPassword checks if an error is a ErrEmptyNewPassword.
|
||||||
|
func IsErrEmptyNewPassword(err error) bool {
|
||||||
|
_, ok := err.(ErrEmptyNewPassword)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrEmptyNewPassword) Error() string {
|
||||||
|
return fmt.Sprintf("New password is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeEmptyNewPassword holds the unique world-error code of this error
|
||||||
|
const ErrCodeEmptyNewPassword = 1013
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrEmptyNewPassword) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyNewPassword, Message: "Please specify new password."}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrEmptyOldPassword represents a "EmptyOldPassword" kind of error.
|
||||||
|
type ErrEmptyOldPassword struct{}
|
||||||
|
|
||||||
|
// IsErrEmptyOldPassword checks if an error is a ErrEmptyOldPassword.
|
||||||
|
func IsErrEmptyOldPassword(err error) bool {
|
||||||
|
_, ok := err.(ErrEmptyOldPassword)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrEmptyOldPassword) Error() string {
|
||||||
|
return fmt.Sprintf("Old password is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeEmptyOldPassword holds the unique world-error code of this error
|
||||||
|
const ErrCodeEmptyOldPassword = 1014
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrEmptyOldPassword) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyOldPassword, Message: "Please specify old password."}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue