Refactor User and DB handling (#123)
fix copyright date Add more user tests More user tests More user tests Start refactoring user tests Docs Fix lint Fix db fixtures init in tests Fix models test Fix loading fixtures Fix ineffasign Fix lint Fix integration tests Fix init of test engine creation Fix user related tests Better handling of creating test enging Moved all fixtures to db package Moved all fixtures to db package Moved user related stuff to seperate package Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/123
This commit is contained in:
parent
8c33e24e92
commit
7e9446ea07
108 changed files with 1506 additions and 1024 deletions
|
@ -16,7 +16,12 @@ In general, this api repo has the following structure:
|
|||
* `docs`
|
||||
* `pkg`
|
||||
* `caldav`
|
||||
* `cmd`
|
||||
* `config`
|
||||
* `db`
|
||||
* `fixtures`
|
||||
* `files`
|
||||
* `integration`
|
||||
* `log`
|
||||
* `mail`
|
||||
* `metrics`
|
||||
|
@ -29,8 +34,11 @@ In general, this api repo has the following structure:
|
|||
* `red`
|
||||
* `routes`
|
||||
* `api/v1`
|
||||
* `static`
|
||||
* `swagger`
|
||||
* `user`
|
||||
* `utils`
|
||||
* `version`
|
||||
* `REST-Tests`
|
||||
* `templates`
|
||||
* `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.
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
### user
|
||||
|
||||
All user-related things like registration etc. live in this package.
|
||||
|
||||
### utils
|
||||
|
||||
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.
|
||||
|
||||
### 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
|
||||
|
||||
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.
|
||||
|
||||
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/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
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/samedi/caldav-go v3.0.0+incompatible
|
||||
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package caldav
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
@ -49,7 +49,7 @@ type Todo struct {
|
|||
Summary string
|
||||
Description string
|
||||
CompletedUnix int64
|
||||
Organizer *models.User
|
||||
Organizer *user.User
|
||||
Priority int64 // 0-9, 1 is highest
|
||||
RelatedToUID string
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"code.vikunja.io/api/pkg/models"
|
||||
migrator "code.vikunja.io/api/pkg/modules/migration"
|
||||
"code.vikunja.io/api/pkg/red"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
|
@ -76,6 +77,10 @@ func initialize() {
|
|||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = user.InitDB()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = files.SetEngine()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
|
|
28
pkg/db/db.go
28
pkg/db/db.go
|
@ -23,7 +23,6 @@ import (
|
|||
"fmt"
|
||||
"github.com/go-xorm/core"
|
||||
"github.com/go-xorm/xorm"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -85,33 +84,6 @@ func CreateDBEngine() (engine *xorm.Engine, err error) {
|
|||
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
|
||||
func RegisterTableStructsForCache(val interface{}) {
|
||||
gob.Register(val)
|
||||
|
|
69
pkg/db/test.go
Normal file
69
pkg/db/test.go
Normal file
|
@ -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
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/testfixtures.v2"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var fixtures *testfixtures.Context
|
||||
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@ -34,3 +55,9 @@ func InitFixtures(helper testfixtures.Helper, dir string) (err error) {
|
|||
func LoadFixtures() error {
|
||||
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"
|
||||
"github.com/spf13/afero"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/testfixtures.v2"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -45,10 +43,9 @@ func InitTestFileHandler() {
|
|||
}
|
||||
|
||||
func initFixtures(t *testing.T) {
|
||||
// Init db fixtures
|
||||
err := db.LoadFixtures()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// DB fixtures
|
||||
db.LoadAndAssertFixtures(t)
|
||||
// File fixtures
|
||||
InitTestFileFixtures(t)
|
||||
}
|
||||
|
||||
|
@ -73,17 +70,7 @@ func InitTests() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
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
|
||||
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)
|
||||
err = db.InitTestFixtures("files")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/routes"
|
||||
v1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
|
@ -38,34 +39,34 @@ import (
|
|||
|
||||
// These are the test users, the same way they are in the test database
|
||||
var (
|
||||
testuser1 = models.User{
|
||||
testuser1 = user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
Email: "user1@example.com",
|
||||
IsActive: true,
|
||||
}
|
||||
testuser2 = models.User{
|
||||
testuser2 = user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
Email: "user2@example.com",
|
||||
}
|
||||
testuser3 = models.User{
|
||||
testuser3 = user.User{
|
||||
ID: 3,
|
||||
Username: "user3",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
Email: "user3@example.com",
|
||||
PasswordResetToken: "passwordresettesttoken",
|
||||
}
|
||||
testuser4 = models.User{
|
||||
testuser4 = user.User{
|
||||
ID: 4,
|
||||
Username: "user4",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
Email: "user4@example.com",
|
||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||
}
|
||||
testuser5 = models.User{
|
||||
testuser5 = user.User{
|
||||
ID: 4,
|
||||
Username: "user5",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -81,7 +82,8 @@ func setupTestEnv() (e *echo.Echo, err error) {
|
|||
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
||||
// Some tests use the file engine, so we'll need to initialize that
|
||||
files.InitTests()
|
||||
models.SetupTests(config.ServiceRootpath.GetString())
|
||||
user.InitTests()
|
||||
models.SetupTests()
|
||||
|
||||
err = db.LoadFixtures()
|
||||
if err != nil {
|
||||
|
@ -114,7 +116,7 @@ func newTestRequest(t *testing.T, method string, handler func(ctx echo.Context)
|
|||
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
|
||||
token, err := v1.NewUserJWTAuthtoken(user)
|
||||
assert.NoError(t, err)
|
||||
|
@ -152,7 +154,7 @@ func testRequestSetup(t *testing.T, method string, payload string, queryParams u
|
|||
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)
|
||||
addUserTokenToContext(t, user, c)
|
||||
err = handler(c)
|
||||
|
@ -185,7 +187,7 @@ func assertHandlerErrorCode(t *testing.T, err error, expectedErrorCode int) {
|
|||
}
|
||||
|
||||
type webHandlerTest struct {
|
||||
user *models.User
|
||||
user *user.User
|
||||
linkShare *models.LinkSharing
|
||||
strFunc func() handler.CObject
|
||||
t *testing.T
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
@ -36,7 +36,7 @@ func TestLogin(t *testing.T) {
|
|||
t.Run("Empty payload", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Not existing user", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
||||
|
@ -44,7 +44,7 @@ func TestLogin(t *testing.T) {
|
|||
"password": "1234"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeWrongUsernameOrPassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeWrongUsernameOrPassword)
|
||||
})
|
||||
t.Run("Wrong password", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
||||
|
@ -52,7 +52,7 @@ func TestLogin(t *testing.T) {
|
|||
"password": "wrong"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeWrongUsernameOrPassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeWrongUsernameOrPassword)
|
||||
})
|
||||
t.Run("user with unconfirmed email", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.Login, `{
|
||||
|
@ -60,6 +60,6 @@ func TestLogin(t *testing.T) {
|
|||
"password": "1234"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeEmailNotConfirmed)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeEmailNotConfirmed)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
@ -37,7 +37,7 @@ func TestRegister(t *testing.T) {
|
|||
t.Run("Empty payload", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Empty username", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||
|
@ -46,7 +46,7 @@ func TestRegister(t *testing.T) {
|
|||
"email": "email@example.com"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Empty password", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||
|
@ -55,7 +55,7 @@ func TestRegister(t *testing.T) {
|
|||
"email": "email@example.com"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Empty email", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||
|
@ -64,7 +64,7 @@ func TestRegister(t *testing.T) {
|
|||
"email": ""
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Already existing username", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||
|
@ -73,7 +73,7 @@ func TestRegister(t *testing.T) {
|
|||
"email": "email@example.com"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrorCodeUsernameExists)
|
||||
assertHandlerErrorCode(t, err, user.ErrorCodeUsernameExists)
|
||||
})
|
||||
t.Run("Already existing email", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.RegisterUser, `{
|
||||
|
@ -82,6 +82,6 @@ func TestRegister(t *testing.T) {
|
|||
"email": "user1@example.com"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrorCodeUserEmailExists)
|
||||
assertHandlerErrorCode(t, err, user.ErrorCodeUserEmailExists)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
@ -39,7 +39,7 @@ func TestUserChangePassword(t *testing.T) {
|
|||
"old_password": "invalid"
|
||||
}`, nil, nil)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeWrongUsernameOrPassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeWrongUsernameOrPassword)
|
||||
})
|
||||
t.Run("Empty old password", func(t *testing.T) {
|
||||
_, err := newTestRequestWithUser(t, http.MethodPost, apiv1.UserChangePassword, &testuser1, `{
|
||||
|
@ -47,7 +47,7 @@ func TestUserChangePassword(t *testing.T) {
|
|||
"old_password": ""
|
||||
}`, nil, nil)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeEmptyOldPassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeEmptyOldPassword)
|
||||
})
|
||||
t.Run("Empty new password", func(t *testing.T) {
|
||||
_, err := newTestRequestWithUser(t, http.MethodPost, apiv1.UserChangePassword, &testuser1, `{
|
||||
|
@ -55,6 +55,6 @@ func TestUserChangePassword(t *testing.T) {
|
|||
"old_password": "1234"
|
||||
}`, nil, nil)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeEmptyNewPassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeEmptyNewPassword)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
|
@ -35,16 +35,16 @@ func TestUserConfirmEmail(t *testing.T) {
|
|||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{}`)
|
||||
assert.Error(t, err)
|
||||
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) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{"token": ""}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidEmailConfirmToken)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeInvalidEmailConfirmToken)
|
||||
})
|
||||
t.Run("Invalid token", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserConfirmEmail, `{"token": "invalidToken"}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeInvalidEmailConfirmToken)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeInvalidEmailConfirmToken)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
|
@ -34,7 +34,7 @@ func TestUserRequestResetPasswordToken(t *testing.T) {
|
|||
t.Run("Empty payload", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Invalid email address", func(t *testing.T) {
|
||||
_, 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) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserRequestResetPasswordToken, `{"email": "user1000@example.com"}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeUserDoesNotExist)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeUserDoesNotExist)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
|
@ -45,7 +45,7 @@ func TestUserPasswordReset(t *testing.T) {
|
|||
"token": "passwordresettesttoken"
|
||||
}`)
|
||||
assert.Error(t, err)
|
||||
assertHandlerErrorCode(t, err, models.ErrCodeNoUsernamePassword)
|
||||
assertHandlerErrorCode(t, err, user.ErrCodeNoUsernamePassword)
|
||||
})
|
||||
t.Run("Invalid password reset token", func(t *testing.T) {
|
||||
_, err := newTestRequest(t, http.MethodPost, apiv1.UserResetPassword, `{
|
||||
|
@ -53,6 +53,6 @@ func TestUserPasswordReset(t *testing.T) {
|
|||
"token": "invalidtoken"
|
||||
}`)
|
||||
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/log"
|
||||
"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/olekukonko/tablewriter"
|
||||
"os"
|
||||
|
@ -138,5 +140,7 @@ func initSchema(tx *xorm.Engine) error {
|
|||
schemeBeans := []interface{}{}
|
||||
schemeBeans = append(schemeBeans, models.GetTables()...)
|
||||
schemeBeans = append(schemeBeans, files.GetTables()...)
|
||||
schemeBeans = append(schemeBeans, migration.GetTables()...)
|
||||
schemeBeans = append(schemeBeans, user.GetTables()...)
|
||||
return tx.Sync2(schemeBeans...)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -9,7 +11,7 @@ func TestBulkTask_Update(t *testing.T) {
|
|||
IDs []int64
|
||||
Tasks []*Task
|
||||
Task Task
|
||||
User *User
|
||||
User *user.User
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -24,7 +26,7 @@ func TestBulkTask_Update(t *testing.T) {
|
|||
Task: Task{
|
||||
Text: "bulkupdated",
|
||||
},
|
||||
User: &User{ID: 1},
|
||||
User: &user.User{ID: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -34,7 +36,7 @@ func TestBulkTask_Update(t *testing.T) {
|
|||
Task: Task{
|
||||
Text: "bulkupdated",
|
||||
},
|
||||
User: &User{ID: 1},
|
||||
User: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
},
|
||||
|
@ -45,13 +47,15 @@ func TestBulkTask_Update(t *testing.T) {
|
|||
Task: Task{
|
||||
Text: "bulkupdated",
|
||||
},
|
||||
User: &User{ID: 1},
|
||||
User: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
bt := &BulkTask{
|
||||
IDs: tt.fields.IDs,
|
||||
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."}
|
||||
}
|
||||
|
||||
// =====================
|
||||
// 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
|
||||
// ===================
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../files/fixtures/files.yml
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"time"
|
||||
)
|
||||
|
@ -34,7 +35,7 @@ type Label struct {
|
|||
|
||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||
// 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.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
|
@ -63,7 +64,7 @@ func (Label) TableName() string {
|
|||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels [put]
|
||||
func (l *Label) Create(a web.Auth) (err error) {
|
||||
u, err := getUserWithError(a)
|
||||
u, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
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{}
|
||||
}
|
||||
|
||||
u := &User{ID: a.GetID()}
|
||||
u := &user.User{ID: a.GetID()}
|
||||
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(u)
|
||||
|
@ -175,7 +176,7 @@ func (l *Label) ReadOne() (err error) {
|
|||
}
|
||||
*l = *label
|
||||
|
||||
user, err := GetUserByID(l.CreatedByID)
|
||||
user, err := user.GetUserByID(l.CreatedByID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -198,7 +199,7 @@ func getLabelByIDSimple(labelID int64) (*Label, error) {
|
|||
}
|
||||
|
||||
// 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
|
||||
lists, _, _, err := getRawListsForUser("", u, -1, 0)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"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
|
||||
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(&User{ID: a.GetID()})
|
||||
taskIDs, err := getUserTaskIDs(&user.User{ID: a.GetID()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"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{
|
||||
User: &User{ID: a.GetID()},
|
||||
User: &user.User{ID: a.GetID()},
|
||||
Search: search,
|
||||
Page: page,
|
||||
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.
|
||||
type LabelByTaskIDsOptions struct {
|
||||
User *User
|
||||
User *user.User
|
||||
Search string
|
||||
Page int
|
||||
PerPage int
|
||||
|
@ -185,7 +186,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
|||
for _, l := range labels {
|
||||
userids = append(userids, l.CreatedByID)
|
||||
}
|
||||
users := make(map[int64]*User)
|
||||
users := make(map[int64]*user.User)
|
||||
err = x.In("id", userids).Find(&users)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
|
@ -290,7 +291,7 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
|||
return err
|
||||
}
|
||||
if !hasAccessToLabel {
|
||||
user, _ := creator.(*User)
|
||||
user, _ := creator.(*user.User)
|
||||
return ErrUserHasNoAccessToLabel{LabelID: l.ID, UserID: user.ID}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
@ -37,7 +39,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
|||
TaskID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantLabels: []*labelWithTaskID{
|
||||
{
|
||||
|
@ -46,7 +48,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
|||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: &User{
|
||||
CreatedBy: &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -62,7 +64,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
|||
TaskID: 14,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrNoRightToSeeTask,
|
||||
|
@ -73,7 +75,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
|||
TaskID: 9999,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrTaskDoesNotExist,
|
||||
|
@ -81,6 +83,8 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
l := &LabelTask{
|
||||
ID: tt.fields.ID,
|
||||
TaskID: tt.fields.TaskID,
|
||||
|
@ -131,17 +135,17 @@ func TestLabelTask_Create(t *testing.T) {
|
|||
LabelID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "already existing",
|
||||
fields: fields{
|
||||
TaskID: 1,
|
||||
LabelID: 1,
|
||||
LabelID: 4,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrLabelIsAlreadyOnTask,
|
||||
|
@ -153,7 +157,7 @@ func TestLabelTask_Create(t *testing.T) {
|
|||
LabelID: 9999,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
},
|
||||
|
@ -164,7 +168,7 @@ func TestLabelTask_Create(t *testing.T) {
|
|||
LabelID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
wantErr: true,
|
||||
|
@ -173,6 +177,8 @@ func TestLabelTask_Create(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
l := &LabelTask{
|
||||
ID: tt.fields.ID,
|
||||
TaskID: tt.fields.TaskID,
|
||||
|
@ -217,9 +223,9 @@ func TestLabelTask_Delete(t *testing.T) {
|
|||
name: "normal",
|
||||
fields: fields{
|
||||
TaskID: 1,
|
||||
LabelID: 1,
|
||||
LabelID: 4,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "delete nonexistant",
|
||||
|
@ -227,7 +233,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
|||
TaskID: 1,
|
||||
LabelID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
|
@ -236,7 +242,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
|||
TaskID: 1,
|
||||
LabelID: 9999,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
|
@ -245,7 +251,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
|||
TaskID: 9999,
|
||||
LabelID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
|
@ -254,12 +260,14 @@ func TestLabelTask_Delete(t *testing.T) {
|
|||
TaskID: 14,
|
||||
LabelID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
l := &LabelTask{
|
||||
ID: tt.fields.ID,
|
||||
TaskID: tt.fields.TaskID,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
@ -32,7 +33,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
|||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
|
@ -43,7 +44,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
|||
a web.Auth
|
||||
page int
|
||||
}
|
||||
user1 := &User{
|
||||
user1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -60,7 +61,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
|||
{
|
||||
name: "normal",
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantLs: []*labelWithTaskID{
|
||||
{
|
||||
|
@ -85,7 +86,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
|||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: &User{
|
||||
CreatedBy: &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -98,7 +99,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
|||
{
|
||||
name: "invalid user",
|
||||
args: args{
|
||||
a: &User{ID: -1},
|
||||
a: &user.User{ID: -1},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
|
@ -136,13 +137,13 @@ func TestLabel_ReadOne(t *testing.T) {
|
|||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
Rights web.Rights
|
||||
}
|
||||
user1 := &User{
|
||||
user1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -169,7 +170,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
|||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "Get nonexistant label",
|
||||
|
@ -179,7 +180,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
|||
wantErr: true,
|
||||
errType: IsErrLabelDoesNotExist,
|
||||
wantForbidden: true,
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "no rights",
|
||||
|
@ -187,7 +188,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
|||
ID: 3,
|
||||
},
|
||||
wantForbidden: true,
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "Get label #4 - other user",
|
||||
|
@ -198,14 +199,14 @@ func TestLabel_ReadOne(t *testing.T) {
|
|||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: &User{
|
||||
CreatedBy: &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
},
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
@ -248,7 +249,7 @@ func TestLabel_Create(t *testing.T) {
|
|||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
|
@ -272,7 +273,7 @@ func TestLabel_Create(t *testing.T) {
|
|||
HexColor: "ffccff",
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -308,7 +309,7 @@ func TestLabel_Update(t *testing.T) {
|
|||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
|
@ -327,7 +328,7 @@ func TestLabel_Update(t *testing.T) {
|
|||
ID: 1,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "nonexisting",
|
||||
|
@ -335,7 +336,7 @@ func TestLabel_Update(t *testing.T) {
|
|||
ID: 99999,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
wantErr: true,
|
||||
},
|
||||
|
@ -345,7 +346,7 @@ func TestLabel_Update(t *testing.T) {
|
|||
ID: 3,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
|
@ -354,7 +355,7 @@ func TestLabel_Update(t *testing.T) {
|
|||
ID: 4,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
|
@ -390,7 +391,7 @@ func TestLabel_Delete(t *testing.T) {
|
|||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
|
@ -409,14 +410,14 @@ func TestLabel_Delete(t *testing.T) {
|
|||
fields: fields{
|
||||
ID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "nonexisting",
|
||||
fields: fields{
|
||||
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.
|
||||
},
|
||||
{
|
||||
|
@ -424,7 +425,7 @@ func TestLabel_Delete(t *testing.T) {
|
|||
fields: fields{
|
||||
ID: 3,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
|
@ -432,7 +433,7 @@ func TestLabel_Delete(t *testing.T) {
|
|||
fields: fields{
|
||||
ID: 4,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
|
@ -48,7 +49,7 @@ type LinkSharing struct {
|
|||
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
|
||||
SharedBy *User `xorm:"-" json:"shared_by"`
|
||||
SharedBy *user.User `xorm:"-" json:"shared_by"`
|
||||
SharedByID int64 `xorm:"int(11) INDEX not null" json:"-"`
|
||||
|
||||
// A unix timestamp when this list was shared. You cannot change this value.
|
||||
|
@ -100,7 +101,7 @@ func (share *LinkSharing) Create(a web.Auth) (err error) {
|
|||
share.SharedByID = a.GetID()
|
||||
share.Hash = utils.MakeRandomString(40)
|
||||
_, err = x.Insert(share)
|
||||
share.SharedBy, _ = a.(*User)
|
||||
share.SharedBy, _ = a.(*user.User)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -168,7 +169,7 @@ func (share *LinkSharing) ReadAll(a web.Auth, search string, page int, perPage i
|
|||
userIDs = append(userIDs, s.SharedByID)
|
||||
}
|
||||
|
||||
users := make(map[int64]*User)
|
||||
users := make(map[int64]*user.User)
|
||||
err = x.In("id", userIDs).Find(&users)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
|
|
|
@ -18,6 +18,7 @@ package models
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
|
@ -36,7 +37,7 @@ type List struct {
|
|||
NamespaceID int64 `xorm:"int(11) INDEX not null" json:"-" param:"namespace"`
|
||||
|
||||
// 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.
|
||||
// Deprecated: you should use the dedicated task list endpoint because it has support for pagination and filtering
|
||||
Tasks []*Task `xorm:"-" json:"-"`
|
||||
|
@ -51,7 +52,7 @@ type List struct {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
err = x.Select("l.*").
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
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]
|
||||
func (l *List) ReadOne() (err error) {
|
||||
// Get list owner
|
||||
l.Owner, err = GetUserByID(l.OwnerID)
|
||||
l.Owner, err = user.GetUserByID(l.OwnerID)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -176,8 +177,8 @@ func GetListSimplByTaskID(taskID int64) (l *List, err error) {
|
|||
}
|
||||
|
||||
// Gets the lists only, without any tasks or so
|
||||
func getRawListsForUser(search string, u *User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
||||
fullUser, err := GetUserByID(u.ID)
|
||||
func getRawListsForUser(search string, u *user.User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
||||
fullUser, err := user.GetUserByID(u.ID)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
@ -237,7 +238,7 @@ func AddListDetails(lists []*List) (err error) {
|
|||
}
|
||||
|
||||
// Get all list owners
|
||||
owners := []*User{}
|
||||
owners := []*user.User{}
|
||||
err = x.In("id", ownerIDs).Find(&owners)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -348,7 +349,7 @@ func updateListByTaskID(taskID int64) (err error) {
|
|||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /namespaces/{namespaceID}/lists [put]
|
||||
func (l *List) Create(a web.Auth) (err error) {
|
||||
doer, err := getUserWithError(a)
|
||||
doer, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"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
|
||||
if originalList.isOwner(&User{ID: a.GetID()}) {
|
||||
if originalList.isOwner(&user.User{ID: a.GetID()}) {
|
||||
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
|
||||
}
|
||||
|
||||
if l.isOwner(&User{ID: a.GetID()}) {
|
||||
if l.isOwner(&user.User{ID: a.GetID()}) {
|
||||
return true, nil
|
||||
}
|
||||
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 if the user is either owner or can write to the list
|
||||
// Owners are always admins
|
||||
if originalList.isOwner(&User{ID: a.GetID()}) {
|
||||
if originalList.isOwner(&user.User{ID: a.GetID()}) {
|
||||
return true, nil
|
||||
}
|
||||
return originalList.checkRight(a, RightAdmin)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
|
@ -25,6 +27,8 @@ import (
|
|||
)
|
||||
|
||||
func TestTeamList(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Dummy relation
|
||||
tl := TeamList{
|
||||
TeamID: 1,
|
||||
|
@ -33,7 +37,7 @@ func TestTeamList(t *testing.T) {
|
|||
}
|
||||
|
||||
// Dummyuser
|
||||
u, err := GetUserByID(1)
|
||||
u, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check normal creation
|
||||
|
@ -164,6 +168,8 @@ func TestTeamList_Update(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tl := &TeamList{
|
||||
ID: tt.fields.ID,
|
||||
TeamID: tt.fields.TeamID,
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestList_CreateOrUpdate(t *testing.T) {
|
||||
user := &User{
|
||||
usr := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Email: "user1@example.com",
|
||||
|
@ -31,41 +33,41 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
|||
|
||||
t.Run("create", func(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
NamespaceID: 1,
|
||||
}
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("nonexistant namespace", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
NamespaceID: 999999,
|
||||
}
|
||||
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
})
|
||||
t.Run("nonexistant owner", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
user := &User{ID: 9482385}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
usr := &user.User{ID: 9482385}
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
NamespaceID: 1,
|
||||
}
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
})
|
||||
t.Run("existing identifier", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
|
@ -73,7 +75,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
|||
NamespaceID: 1,
|
||||
}
|
||||
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, 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("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
ID: 1,
|
||||
Title: "test",
|
||||
|
@ -94,7 +96,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
|||
|
||||
})
|
||||
t.Run("nonexistant", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
ID: 99999999,
|
||||
Title: "test",
|
||||
|
@ -105,7 +107,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
|||
|
||||
})
|
||||
t.Run("existing identifier", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
|
@ -113,7 +115,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
|||
NamespaceID: 1,
|
||||
}
|
||||
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
||||
})
|
||||
|
@ -121,7 +123,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestList_Delete(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
ID: 1,
|
||||
}
|
||||
|
@ -131,14 +133,16 @@ func TestList_Delete(t *testing.T) {
|
|||
|
||||
func TestList_ReadAll(t *testing.T) {
|
||||
t.Run("all in namespace", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
// Get all lists for our namespace
|
||||
lists, err := GetListsByNamespaceID(1, &User{})
|
||||
lists, err := GetListsByNamespaceID(1, &user.User{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(lists), 2)
|
||||
})
|
||||
t.Run("all lists for user", func(t *testing.T) {
|
||||
u := &User{ID: 1}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
u := &user.User{ID: 1}
|
||||
list := List{}
|
||||
lists3, _, _, err := list.ReadAll(u, "", 1, 50)
|
||||
|
||||
|
@ -148,10 +152,12 @@ func TestList_ReadAll(t *testing.T) {
|
|||
assert.Equal(t, 16, s.Len())
|
||||
})
|
||||
t.Run("lists for nonexistant user", func(t *testing.T) {
|
||||
user := &User{ID: 999999}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
usr := &user.User{ID: 999999}
|
||||
list := List{}
|
||||
_, _, _, err := list.ReadAll(user, "", 1, 50)
|
||||
_, _, _, err := list.ReadAll(usr, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
package models
|
||||
|
||||
import "code.vikunja.io/web"
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
// ListUser represents a list <-> user relation
|
||||
type ListUser struct {
|
||||
|
@ -47,7 +50,7 @@ func (ListUser) TableName() string {
|
|||
|
||||
// UserWithRight represents a user in combination with the right it can have on a list/namespace
|
||||
type UserWithRight struct {
|
||||
User `xorm:"extends"`
|
||||
user.User `xorm:"extends"`
|
||||
Right Right `json:"right"`
|
||||
}
|
||||
|
||||
|
@ -80,7 +83,7 @@ func (lu *ListUser) Create(a web.Auth) (err error) {
|
|||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(lu.Username)
|
||||
user, err := user.GetUserByUsername(lu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -126,7 +129,7 @@ func (lu *ListUser) Create(a web.Auth) (err error) {
|
|||
func (lu *ListUser) Delete() (err error) {
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(lu.Username)
|
||||
user, err := user.GetUserByUsername(lu.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -227,7 +230,7 @@ func (lu *ListUser) Update() (err error) {
|
|||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(lu.Username)
|
||||
user, err := user.GetUserByUsername(lu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
|
@ -48,7 +50,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
|||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
|
@ -58,7 +60,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
|||
ListID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
|
@ -68,13 +70,15 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
|||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
"runtime"
|
||||
|
@ -58,7 +60,7 @@ func TestListUser_Create(t *testing.T) {
|
|||
name: "ListUsers Create for duplicate",
|
||||
fields: fields{
|
||||
Username: "user1",
|
||||
ListID: 2,
|
||||
ListID: 3,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserAlreadyHasAccess,
|
||||
|
@ -89,7 +91,7 @@ func TestListUser_Create(t *testing.T) {
|
|||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
name: "ListUsers Create with the owner as shared user",
|
||||
|
@ -103,6 +105,8 @@ func TestListUser_Create(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
ul := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
@ -155,11 +159,11 @@ func TestListUser_ReadAll(t *testing.T) {
|
|||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: []*UserWithRight{
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -169,7 +173,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
|||
Right: RightRead,
|
||||
},
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -185,7 +189,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
|||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrNeedToHaveListReadAccess,
|
||||
|
@ -193,6 +197,8 @@ func TestListUser_ReadAll(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
ul := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
@ -271,6 +277,8 @@ func TestListUser_Update(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
@ -316,7 +324,7 @@ func TestListUser_Delete(t *testing.T) {
|
|||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
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 {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
|
|
@ -19,6 +19,7 @@ package models
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
@ -33,7 +34,9 @@ func TestMain(m *testing.M) {
|
|||
// Some tests use the file engine, so we'll need to initialize that
|
||||
files.InitTests()
|
||||
|
||||
SetupTests(config.ServiceRootpath.GetString())
|
||||
user.InitTests()
|
||||
|
||||
SetupTests()
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
_ "github.com/go-sql-driver/mysql" // Because.
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
|
@ -33,7 +34,7 @@ var (
|
|||
// GetTables returns all structs which are also a table.
|
||||
func GetTables() []interface{} {
|
||||
return []interface{}{
|
||||
&User{},
|
||||
&user.User{},
|
||||
&List{},
|
||||
&Task{},
|
||||
&Team{},
|
||||
|
|
|
@ -18,6 +18,7 @@ package models
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/imdario/mergo"
|
||||
"time"
|
||||
|
@ -34,7 +35,7 @@ type Namespace struct {
|
|||
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
|
||||
// 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.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
|
@ -97,7 +98,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
|
|||
}
|
||||
|
||||
// Get the namespace Owner
|
||||
namespace.Owner, err = GetUserByID(namespace.OwnerID)
|
||||
namespace.Owner, err = user.GetUserByID(namespace.OwnerID)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -115,7 +116,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
|
|||
// @Router /namespaces/{id} [get]
|
||||
func (n *Namespace) ReadOne() (err error) {
|
||||
// Get the namespace Owner
|
||||
n.Owner, err = GetUserByID(n.OwnerID)
|
||||
n.Owner, err = user.GetUserByID(n.OwnerID)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
|
|||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
doer, err := getUserWithError(a)
|
||||
doer, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
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
|
||||
users := []*User{}
|
||||
users := []*user.User{}
|
||||
err = x.Select("users.*").
|
||||
Table("namespaces").
|
||||
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
|
||||
|
||||
// Check if the User exists
|
||||
n.Owner, err = GetUserByID(a.GetID())
|
||||
n.Owner, err = user.GetUserByID(a.GetID())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -343,7 +344,7 @@ func (n *Namespace) Delete() (err error) {
|
|||
}
|
||||
|
||||
// Delete all lists with their tasks
|
||||
lists, err := GetListsByNamespaceID(n.ID, &User{})
|
||||
lists, err := GetListsByNamespaceID(n.ID, &user.User{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -401,7 +402,7 @@ func (n *Namespace) Update() (err error) {
|
|||
// Check if the (new) owner exists
|
||||
n.OwnerID = n.Owner.ID
|
||||
if currentNamespace.OwnerID != n.OwnerID {
|
||||
n.Owner, err = GetUserByID(n.OwnerID)
|
||||
n.Owner, err = user.GetUserByID(n.OwnerID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
|
@ -48,7 +50,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
|||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
|
@ -58,7 +60,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
|||
NamespaceID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
|
@ -68,13 +70,15 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
|||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tn := &TeamNamespace{
|
||||
ID: tt.fields.ID,
|
||||
TeamID: tt.fields.TeamID,
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
|
@ -25,6 +27,8 @@ import (
|
|||
)
|
||||
|
||||
func TestTeamNamespace(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Dummy team <-> namespace relation
|
||||
tn := TeamNamespace{
|
||||
TeamID: 1,
|
||||
|
@ -32,7 +36,7 @@ func TestTeamNamespace(t *testing.T) {
|
|||
Right: RightAdmin,
|
||||
}
|
||||
|
||||
dummyuser, err := GetUserByID(1)
|
||||
dummyuser, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test normal creation
|
||||
|
@ -80,7 +84,7 @@ func TestTeamNamespace(t *testing.T) {
|
|||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
|
||||
// Check with no right to read the namespace
|
||||
nouser := &User{ID: 393}
|
||||
nouser := &user.User{ID: 393}
|
||||
_, _, _, err = tn.ReadAll(nouser, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNeedToHaveNamespaceReadAccess(err))
|
||||
|
@ -156,6 +160,8 @@ func TestTeamNamespace_Update(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tl := &TeamNamespace{
|
||||
ID: tt.fields.ID,
|
||||
TeamID: tt.fields.TeamID,
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNamespace_Create(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Create test database
|
||||
//assert.NoError(t, LoadFixtures())
|
||||
|
||||
|
@ -33,7 +37,7 @@ func TestNamespace_Create(t *testing.T) {
|
|||
}
|
||||
|
||||
// Doer
|
||||
doer, err := GetUserByID(1)
|
||||
doer, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try creating it
|
||||
|
@ -57,11 +61,11 @@ func TestNamespace_Create(t *testing.T) {
|
|||
assert.True(t, IsErrNamespaceNameCannotBeEmpty(err))
|
||||
|
||||
// Try inserting one with a nonexistant user
|
||||
nUser := &User{ID: 9482385}
|
||||
nUser := &user.User{ID: 9482385}
|
||||
dnsp2 := dummynamespace
|
||||
err = dnsp2.Create(nUser)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
|
||||
// Update it
|
||||
allowed, err = dummynamespace.CanUpdate(doer)
|
||||
|
@ -85,7 +89,7 @@ func TestNamespace_Create(t *testing.T) {
|
|||
dummynamespace.Owner.ID = 94829838572
|
||||
err = dummynamespace.Update()
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
|
||||
// Try updating without a name
|
||||
dummynamespace.Name = ""
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
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
|
||||
type NamespaceUser struct {
|
||||
|
@ -75,7 +78,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
|||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
user, err := user2.GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -117,7 +120,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
|||
func (nu *NamespaceUser) Delete() (err error) {
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
user, err := user2.GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -213,7 +216,7 @@ func (nu *NamespaceUser) Update() (err error) {
|
|||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
user, err := user2.GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
|
@ -48,7 +50,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
|||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
|
@ -58,7 +60,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
|||
NamespaceID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
|
@ -68,13 +70,15 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
|||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
|
@ -56,7 +58,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
|||
name: "NamespaceUsers Create for duplicate",
|
||||
fields: fields{
|
||||
Username: "user1",
|
||||
NamespaceID: 2,
|
||||
NamespaceID: 3,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserAlreadyHasNamespaceAccess,
|
||||
|
@ -87,7 +89,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
|||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
name: "NamespaceUsers Create with the owner as shared user",
|
||||
|
@ -101,6 +103,8 @@ func TestNamespaceUser_Create(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
un := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
@ -152,11 +156,11 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
|||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: []*UserWithRight{
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -166,7 +170,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
|||
Right: RightRead,
|
||||
},
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -182,7 +186,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
|||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrNeedToHaveNamespaceReadAccess,
|
||||
|
@ -190,6 +194,8 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
un := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
@ -269,6 +275,8 @@ func TestNamespaceUser_Update(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
@ -314,7 +322,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
|||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
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 {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
|
@ -39,7 +40,7 @@ func (TaskAssginee) TableName() string {
|
|||
// TaskAssigneeWithUser is a helper type to deal with user joins
|
||||
type TaskAssigneeWithUser struct {
|
||||
TaskID int64
|
||||
User `xorm:"extends"`
|
||||
user.User `xorm:"extends"`
|
||||
}
|
||||
|
||||
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
|
||||
func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
||||
func (t *Task) updateTaskAssignees(assignees []*user.User) (err error) {
|
||||
|
||||
// Load the current assignees
|
||||
currentAssignees, err := getRawTaskAssigneesForTasks([]int64{t.ID})
|
||||
|
@ -61,7 +62,7 @@ func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
t.Assignees = make([]*User, 0, len(currentAssignees))
|
||||
t.Assignees = make([]*user.User, 0, len(currentAssignees))
|
||||
for _, assignee := range currentAssignees {
|
||||
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
|
||||
newAssignees := make(map[int64]*User, len(assignees))
|
||||
newAssignees := make(map[int64]*user.User, len(assignees))
|
||||
for _, newAssignee := range assignees {
|
||||
newAssignees[newAssignee.ID] = newAssignee
|
||||
}
|
||||
|
@ -88,7 +89,7 @@ func (t *Task) updateTaskAssignees(assignees []*User) (err error) {
|
|||
// Get old assignees to delete
|
||||
var found bool
|
||||
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 {
|
||||
found = false
|
||||
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
|
||||
func (t *Task) setTaskAssignees(assignees []*User) {
|
||||
func (t *Task) setTaskAssignees(assignees []*user.User) {
|
||||
if len(assignees) == 0 {
|
||||
t.Assignees = nil
|
||||
return
|
||||
|
@ -200,7 +201,7 @@ func (la *TaskAssginee) Create(a web.Auth) (err error) {
|
|||
|
||||
func (t *Task) addNewAssigneeByID(newAssigneeID int64, list *List) (err error) {
|
||||
// Check if the user exists and has access to the list
|
||||
newAssignee, err := GetUserByID(newAssigneeID)
|
||||
newAssignee, err := user.GetUserByID(newAssigneeID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -252,7 +253,7 @@ func (la *TaskAssginee) ReadAll(a web.Auth, search string, page int, perPage int
|
|||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
var taskAssignees []*User
|
||||
var taskAssignees []*user.User
|
||||
err = x.Table("task_assignees").
|
||||
Select("users.*").
|
||||
Join("INNER", "users", "task_assignees.user_id = users.id").
|
||||
|
@ -267,14 +268,14 @@ func (la *TaskAssginee) ReadAll(a web.Auth, search string, page int, perPage int
|
|||
Select("users.*").
|
||||
Join("INNER", "users", "task_assignees.user_id = users.id").
|
||||
Where("task_id = ? AND users.username LIKE ?", la.TaskID, "%"+search+"%").
|
||||
Count(&User{})
|
||||
Count(&user.User{})
|
||||
return taskAssignees, len(taskAssignees), numberOfTotalItems, err
|
||||
}
|
||||
|
||||
// BulkAssignees is a helper struct used to update multiple assignees at once.
|
||||
type BulkAssignees struct {
|
||||
// A list with all assignees
|
||||
Assignees []*User `json:"assignees"`
|
||||
Assignees []*user.User `json:"assignees"`
|
||||
TaskID int64 `json:"-" param:"listtask"`
|
||||
|
||||
web.CRUDable `json:"-"`
|
||||
|
|
|
@ -18,6 +18,7 @@ package models
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"io"
|
||||
"time"
|
||||
|
@ -30,7 +31,7 @@ type TaskAttachment struct {
|
|||
FileID 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"`
|
||||
|
||||
|
@ -132,7 +133,7 @@ func (ta *TaskAttachment) ReadAll(a web.Auth, search string, page int, perPage i
|
|||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
us := make(map[int64]*User)
|
||||
us := make(map[int64]*user.User)
|
||||
err = x.In("id", userIDs).Find(&us)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
|
|
|
@ -20,6 +20,7 @@ package models
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io"
|
||||
"os"
|
||||
|
@ -95,7 +96,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
|||
tf := &testfile{
|
||||
content: []byte("testingstuff"),
|
||||
}
|
||||
testuser := &User{ID: 1}
|
||||
testuser := &user.User{ID: 1}
|
||||
|
||||
err := ta.NewAttachment(tf, "testfile", 100, testuser)
|
||||
assert.NoError(t, err)
|
||||
|
@ -119,7 +120,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
|||
func TestTaskAttachment_ReadAll(t *testing.T) {
|
||||
files.InitTestFileFixtures(t)
|
||||
ta := &TaskAttachment{TaskID: 1}
|
||||
as, _, _, err := ta.ReadAll(&User{ID: 1}, "", 0, 50)
|
||||
as, _, _, err := ta.ReadAll(&user.User{ID: 1}, "", 0, 50)
|
||||
attachments, _ := as.([]*TaskAttachment)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, attachments, 3)
|
||||
|
@ -152,7 +153,7 @@ func TestTaskAttachment_Delete(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("Allowed", func(t *testing.T) {
|
||||
ta := &TaskAttachment{TaskID: 1}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"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.
|
||||
// This allows to use this function in Task.ReadAll with a possibility to deprecate the latter at some point.
|
||||
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 {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
|
|
@ -19,30 +19,28 @@ package models
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
assert.NoError(t, db.LoadFixtures())
|
||||
|
||||
// Dummy users
|
||||
user1 := &User{
|
||||
user1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
||||
}
|
||||
user2 := &User{
|
||||
user2 := &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
|
||||
}
|
||||
user6 := &User{
|
||||
user6 := &user.User{
|
||||
ID: 6,
|
||||
Username: "user6",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -463,7 +461,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Assignees: []*User{
|
||||
Assignees: []*user.User{
|
||||
user1,
|
||||
user2,
|
||||
},
|
||||
|
@ -538,7 +536,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
fields: fields{},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
|
@ -585,7 +583,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
|
@ -631,7 +629,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
|
@ -648,7 +646,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
|
@ -664,7 +662,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
|
@ -677,6 +675,8 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
|||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lt := &TaskCollection{
|
||||
ListID: tt.fields.ListID,
|
||||
StartDateSortUnix: tt.fields.StartDateSortUnix,
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
|
@ -83,7 +84,7 @@ type TaskRelation struct {
|
|||
|
||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||
// 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.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
|
|
|
@ -18,45 +18,55 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTaskRelation_Create(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 2,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Two Tasks In Different Lists", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 13,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Already Existing", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 29,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrRelationAlreadyExists(err))
|
||||
})
|
||||
t.Run("Same Task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 1,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrRelationTasksCannotBeTheSame(err))
|
||||
})
|
||||
|
@ -64,6 +74,8 @@ func TestTaskRelation_Create(t *testing.T) {
|
|||
|
||||
func TestTaskRelation_Delete(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 29,
|
||||
|
@ -73,6 +85,8 @@ func TestTaskRelation_Delete(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Not existing", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 9999,
|
||||
OtherTaskID: 3,
|
||||
|
@ -86,73 +100,87 @@ func TestTaskRelation_Delete(t *testing.T) {
|
|||
|
||||
func TestTaskRelation_CanCreate(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 2,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, can)
|
||||
})
|
||||
t.Run("Two tasks on different lists", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 13,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, can)
|
||||
})
|
||||
t.Run("No update rights on base task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 14,
|
||||
OtherTaskID: 1,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("No update rights on base task, but read rights", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 15,
|
||||
OtherTaskID: 1,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("No read rights on other task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 14,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("Nonexisting base task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 999999,
|
||||
OtherTaskID: 1,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTaskDoesNotExist(err))
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("Nonexisting other task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 999999,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTaskDoesNotExist(err))
|
||||
assert.False(t, can)
|
||||
|
|
|
@ -19,6 +19,7 @@ package models
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/imdario/mergo"
|
||||
|
@ -55,7 +56,7 @@ type Task struct {
|
|||
// When this task ends.
|
||||
EndDateUnix int64 `xorm:"int(11) INDEX null" json:"endDate" query:"-"`
|
||||
// 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.
|
||||
Labels []*Label `xorm:"-" json:"labels"`
|
||||
// The task color in hex
|
||||
|
@ -87,7 +88,7 @@ type Task struct {
|
|||
Updated int64 `xorm:"updated not null" json:"updated"`
|
||||
|
||||
// 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.Rights `xorm:"-" json:"-"`
|
||||
|
@ -365,7 +366,7 @@ func addMoreInfoToTasks(taskMap map[int64]*Task) (tasks []*Task, err error) {
|
|||
|
||||
// Get all users of 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)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -487,7 +488,7 @@ func (t *Task) Create(a web.Auth) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
u, err := GetUserByID(a.GetID())
|
||||
u, err := user.GetUserByID(a.GetID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTask_Create(t *testing.T) {
|
||||
user := &User{
|
||||
usr := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
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.
|
||||
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
Text: "Lorem",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
ListID: 1,
|
||||
}
|
||||
err := task.Create(user)
|
||||
err := task.Create(usr)
|
||||
assert.NoError(t, err)
|
||||
// Assert getting a uid
|
||||
assert.NotEmpty(t, task.UID)
|
||||
|
@ -47,30 +49,30 @@ func TestTask_Create(t *testing.T) {
|
|||
|
||||
})
|
||||
t.Run("empty text", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
Text: "",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
ListID: 1,
|
||||
}
|
||||
err := task.Create(user)
|
||||
err := task.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTaskCannotBeEmpty(err))
|
||||
})
|
||||
t.Run("nonexistant list", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
Text: "Test",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
ListID: 9999999,
|
||||
}
|
||||
err := task.Create(user)
|
||||
err := task.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrListDoesNotExist(err))
|
||||
})
|
||||
t.Run("noneixtant user", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
nUser := &User{ID: 99999999}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
nUser := &user.User{ID: 99999999}
|
||||
task := &Task{
|
||||
Text: "Test",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
|
@ -78,13 +80,13 @@ func TestTask_Create(t *testing.T) {
|
|||
}
|
||||
err := task.Create(nUser)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTask_Update(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
ID: 1,
|
||||
Text: "test10000",
|
||||
|
@ -95,7 +97,7 @@ func TestTask_Update(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("nonexistant task", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
ID: 9999999,
|
||||
Text: "test10000",
|
||||
|
@ -110,7 +112,7 @@ func TestTask_Update(t *testing.T) {
|
|||
|
||||
func TestTask_Delete(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
ID: 1,
|
||||
}
|
||||
|
@ -121,12 +123,14 @@ func TestTask_Delete(t *testing.T) {
|
|||
|
||||
func TestUpdateDone(t *testing.T) {
|
||||
t.Run("marking a task as done", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
oldTask := &Task{Done: false}
|
||||
newTask := &Task{Done: true}
|
||||
updateDone(oldTask, newTask)
|
||||
assert.NotEqual(t, int64(0), oldTask.DoneAtUnix)
|
||||
})
|
||||
t.Run("unmarking a task as done", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
oldTask := &Task{Done: true}
|
||||
newTask := &Task{Done: false}
|
||||
updateDone(oldTask, newTask)
|
||||
|
@ -136,14 +140,14 @@ func TestUpdateDone(t *testing.T) {
|
|||
|
||||
func TestTask_ReadOne(t *testing.T) {
|
||||
t.Run("default", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{ID: 1}
|
||||
err := task.ReadOne()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "task #1", task.Text)
|
||||
})
|
||||
t.Run("nonexisting", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{ID: 99999}
|
||||
err := task.ReadOne()
|
||||
assert.Error(t, err)
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
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
|
||||
// @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
|
||||
user, err := GetUserByUsername(tm.Username)
|
||||
user, err := user2.GetUserByUsername(tm.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -84,7 +87,7 @@ func (tm *TeamMember) Delete() (err error) {
|
|||
}
|
||||
|
||||
// Find the numeric user id
|
||||
user, err := GetUserByUsername(tm.Username)
|
||||
user, err := user2.GetUserByUsername(tm.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -17,11 +17,14 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTeamMember_Create(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Dummy team member
|
||||
dummyteammember := TeamMember{
|
||||
|
@ -30,7 +33,7 @@ func TestTeamMember_Create(t *testing.T) {
|
|||
}
|
||||
|
||||
// Doer
|
||||
doer, err := GetUserByID(1)
|
||||
doer, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Insert a new team member
|
||||
|
@ -71,7 +74,7 @@ func TestTeamMember_Create(t *testing.T) {
|
|||
dummyteammember.Username = "user9484"
|
||||
err = dummyteammember.Create(doer)
|
||||
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
|
||||
tm = TeamMember{TeamID: 94824, Username: "user1"}
|
||||
|
|
|
@ -18,6 +18,7 @@ package models
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
|
@ -32,7 +33,7 @@ type Team struct {
|
|||
CreatedByID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
|
||||
// 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.
|
||||
Members []*TeamUser `xorm:"-" json:"members"`
|
||||
|
||||
|
@ -53,7 +54,7 @@ func (Team) TableName() string {
|
|||
// AfterLoad gets the created by user object
|
||||
func (t *Team) AfterLoad() {
|
||||
// Get the owner
|
||||
t.CreatedBy, _ = GetUserByID(t.CreatedByID)
|
||||
t.CreatedBy, _ = user.GetUserByID(t.CreatedByID)
|
||||
|
||||
// Get all members
|
||||
x.Select("*").
|
||||
|
@ -90,7 +91,7 @@ func (TeamMember) TableName() string {
|
|||
|
||||
// TeamUser is the team member type
|
||||
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
|
||||
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"
|
||||
// @Router /teams [put]
|
||||
func (t *Team) Create(a web.Auth) (err error) {
|
||||
doer, err := getUserWithError(a)
|
||||
doer, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
|
@ -28,7 +30,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
|||
Name string
|
||||
Description string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Members []*TeamUser
|
||||
Created int64
|
||||
Updated int64
|
||||
|
@ -50,7 +52,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
|||
ID: 1,
|
||||
},
|
||||
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},
|
||||
},
|
||||
|
@ -60,7 +62,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
|||
ID: 300,
|
||||
},
|
||||
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},
|
||||
},
|
||||
|
@ -70,13 +72,15 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
|||
ID: 1,
|
||||
},
|
||||
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},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tm := &Team{
|
||||
ID: tt.fields.ID,
|
||||
Name: tt.fields.Name,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
@ -30,7 +31,7 @@ func TestTeam_Create(t *testing.T) {
|
|||
}
|
||||
|
||||
// Doer
|
||||
doer, err := GetUserByID(1)
|
||||
doer, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Insert it
|
||||
|
|
|
@ -17,78 +17,49 @@
|
|||
package models
|
||||
|
||||
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/db"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"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.
|
||||
// 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
|
||||
fixturesDir := filepath.Join(pathToRoot, "pkg", "models", "fixtures")
|
||||
if err = createTestEngine(fixturesDir); err != nil {
|
||||
log.Fatalf("Error creating test engine: %v\n", err)
|
||||
x, err = db.CreateTestEngine()
|
||||
if err != nil {
|
||||
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
|
||||
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 contributors. All rights reserved.
|
||||
// Copyright 2018-2020 Vikunja and contriubtors. 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
|
||||
// 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,
|
||||
// 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 this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import "github.com/go-xorm/builder"
|
||||
|
||||
// ListUsers returns a list with all users, filtered by an optional searchstring
|
||||
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
|
||||
}
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/go-xorm/builder"
|
||||
)
|
||||
|
||||
// ListUIDs hold all kinds of user IDs from accounts who have somehow access to a list
|
||||
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
|
||||
func ListUsersFromList(l *List, search string) (users []*User, err error) {
|
||||
func ListUsersFromList(l *List, search string) (users []*user.User, err error) {
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListUsersFromList(t *testing.T) {
|
||||
|
||||
err := db.LoadFixtures()
|
||||
assert.NoError(t, err)
|
||||
|
||||
testuser1 := &User{
|
||||
testuser1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808",
|
||||
}
|
||||
testuser2 := &User{
|
||||
testuser2 := &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
}
|
||||
testuser3 := &User{
|
||||
testuser3 := &user.User{
|
||||
ID: 3,
|
||||
Username: "user3",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "97d6d9441ff85fdc730e02a6068d267b",
|
||||
PasswordResetToken: "passwordresettesttoken",
|
||||
}
|
||||
testuser4 := &User{
|
||||
testuser4 := &user.User{
|
||||
ID: 4,
|
||||
Username: "user4",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -40,7 +53,7 @@ func TestListUsersFromList(t *testing.T) {
|
|||
AvatarURL: "7e65550957227bd38fe2d7fbc6fd2f7b",
|
||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||
}
|
||||
testuser5 := &User{
|
||||
testuser5 := &user.User{
|
||||
ID: 5,
|
||||
Username: "user5",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -48,56 +61,56 @@ func TestListUsersFromList(t *testing.T) {
|
|||
AvatarURL: "cfa35b8cd2ec278026357769582fa563",
|
||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||
}
|
||||
testuser6 := &User{
|
||||
testuser6 := &user.User{
|
||||
ID: 6,
|
||||
Username: "user6",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed",
|
||||
}
|
||||
testuser7 := &User{
|
||||
testuser7 := &user.User{
|
||||
ID: 7,
|
||||
Username: "user7",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "e80a711d4de44c30054806ebbd488464",
|
||||
}
|
||||
testuser8 := &User{
|
||||
testuser8 := &user.User{
|
||||
ID: 8,
|
||||
Username: "user8",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "2b9b320416cd31020bb6844c3fadefd1",
|
||||
}
|
||||
testuser9 := &User{
|
||||
testuser9 := &user.User{
|
||||
ID: 9,
|
||||
Username: "user9",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "f784fdb21d26dd2c64f5135f35ec401f",
|
||||
}
|
||||
testuser10 := &User{
|
||||
testuser10 := &user.User{
|
||||
ID: 10,
|
||||
Username: "user10",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "fce8ff4ff56d75ad587d1bbaa5ef0563",
|
||||
}
|
||||
testuser11 := &User{
|
||||
testuser11 := &user.User{
|
||||
ID: 11,
|
||||
Username: "user11",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "ad6d67d0c4495e186010732a7d360028",
|
||||
}
|
||||
testuser12 := &User{
|
||||
testuser12 := &user.User{
|
||||
ID: 12,
|
||||
Username: "user12",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "ef1debc1364806281c42eeedfdeb943b",
|
||||
}
|
||||
testuser13 := &User{
|
||||
testuser13 := &user.User{
|
||||
ID: 13,
|
||||
Username: "user13",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
|
@ -112,19 +125,19 @@ func TestListUsersFromList(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantUsers []*User
|
||||
wantUsers []*user.User
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Check owner only",
|
||||
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
|
||||
name: "Check with owner and other users",
|
||||
args: args{l: &List{ID: 19, OwnerID: 7}},
|
||||
wantUsers: []*User{
|
||||
wantUsers: []*user.User{
|
||||
testuser1, // Shared Via Team readonly
|
||||
testuser2, // Shared Via Team write
|
||||
testuser3, // Shared Via Team admin
|
||||
|
@ -147,6 +160,8 @@ func TestListUsersFromList(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
gotUsers, err := ListUsersFromList(tt.args.l, tt.args.search)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ListUsersFromList() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
|
|
@ -19,12 +19,13 @@ package migration
|
|||
import (
|
||||
"bytes"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// 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.)
|
||||
func InsertFromStructure(str []*models.NamespaceWithLists, user *models.User) (err error) {
|
||||
func InsertFromStructure(str []*models.NamespaceWithLists, user *user.User) (err error) {
|
||||
|
||||
// Create all namespaces
|
||||
for _, n := range str {
|
||||
|
|
|
@ -19,6 +19,7 @@ package handler
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/modules/migration"
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -53,7 +54,7 @@ func (mw *MigrationWeb) Migrate(c echo.Context) error {
|
|||
ms := mw.MigrationStruct()
|
||||
|
||||
// Get the user from context
|
||||
user, err := models.GetCurrentUser(c)
|
||||
user, err := user2.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
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 {
|
||||
ms := mw.MigrationStruct()
|
||||
|
||||
user, err := models.GetCurrentUser(c)
|
||||
user, err := user2.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
|
||||
package migration
|
||||
|
||||
import "code.vikunja.io/api/pkg/models"
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
)
|
||||
|
||||
// Status represents this migration status
|
||||
type Status struct {
|
||||
|
@ -32,7 +34,7 @@ func (s *Status) TableName() string {
|
|||
}
|
||||
|
||||
// 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{
|
||||
UserID: u.ID,
|
||||
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
|
||||
func GetMigrationStatus(m Migrator, u *models.User) (status *Status, err error) {
|
||||
func GetMigrationStatus(m Migrator, u *user.User) (status *Status, err error) {
|
||||
status = &Status{}
|
||||
_, err = x.Where("user_id = ? and migrator_name = ?", u.ID, m.Name()).Desc("id").Get(status)
|
||||
return
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
|
||||
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
|
||||
type Migrator interface {
|
||||
// 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.
|
||||
Migrate(user *models.User) error
|
||||
Migrate(user *user.User) error
|
||||
// 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
|
||||
// known to the frontend.
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/modules/migration"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"encoding/json"
|
||||
"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."
|
||||
// @Failure 500 {object} models.Message "Internal server error"
|
||||
// @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)
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package v1
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"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.
|
||||
func NewUserJWTAuthtoken(user *models.User) (token string, err error) {
|
||||
func NewUserJWTAuthtoken(user *user.User) (token string, err error) {
|
||||
t := jwt.New(jwt.SigningMethodHS256)
|
||||
|
||||
// Set claims
|
||||
|
@ -78,7 +79,7 @@ func GetAuthFromClaims(c echo.Context) (a web.Auth, err error) {
|
|||
return models.GetLinkShareFromClaims(claims)
|
||||
}
|
||||
if typ == AuthTypeUser {
|
||||
return models.GetUserFromClaims(claims)
|
||||
return user.GetUserFromClaims(claims)
|
||||
}
|
||||
return nil, echo.NewHTTPError(http.StatusBadRequest, models.Message{Message: "Invalid JWT token."})
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -46,7 +47,7 @@ func GetListsByNamespaceID(c echo.Context) error {
|
|||
}
|
||||
|
||||
// Get the lists
|
||||
doer, err := models.GetCurrentUser(c)
|
||||
doer, err := user.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
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
|
||||
user, err := models.GetCurrentUser(c)
|
||||
user, err := user.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/labstack/echo/v4"
|
||||
|
@ -41,13 +42,13 @@ type Token struct {
|
|||
// @Failure 403 {object} models.Message "Invalid username or password."
|
||||
// @Router /login [post]
|
||||
func Login(c echo.Context) error {
|
||||
u := models.UserLogin{}
|
||||
u := user2.Login{}
|
||||
if err := c.Bind(&u); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, models.Message{"Please provide a username and password."})
|
||||
}
|
||||
|
||||
// Check user
|
||||
user, err := models.CheckUserCredentials(&u)
|
||||
user, err := user2.CheckUserCredentials(&u)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
@ -80,7 +81,7 @@ func RenewToken(c echo.Context) error {
|
|||
return echo.ErrBadRequest
|
||||
}
|
||||
|
||||
user, err := models.GetUserFromClaims(claims)
|
||||
user, err := user2.GetUserFromClaims(claims)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -45,7 +46,7 @@ func UploadTaskAttachment(c echo.Context) error {
|
|||
}
|
||||
|
||||
// Rights check
|
||||
user, err := models.GetCurrentUser(c)
|
||||
user, err := user2.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
@ -114,7 +115,7 @@ func GetTaskAttachment(c echo.Context) error {
|
|||
}
|
||||
|
||||
// Rights check
|
||||
user, err := models.GetCurrentUser(c)
|
||||
user, err := user2.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package v1
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -40,13 +41,20 @@ func RegisterUser(c echo.Context) error {
|
|||
return echo.ErrNotFound
|
||||
}
|
||||
// Check for Request Content
|
||||
var datUser *models.APIUserPassword
|
||||
var datUser *user.APIUserPassword
|
||||
if err := c.Bind(&datUser); err != nil {
|
||||
return c.JSON(http.StatusBadRequest, models.Message{"No or invalid user model provided."})
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -36,12 +37,12 @@ import (
|
|||
// @Router /user/confirm [post]
|
||||
func UserConfirmEmail(c echo.Context) error {
|
||||
// Check for Request Content
|
||||
var emailConfirm models.EmailConfirm
|
||||
var emailConfirm user.EmailConfirm
|
||||
if err := c.Bind(&emailConfirm); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "No token provided.")
|
||||
}
|
||||
|
||||
err := models.UserEmailConfirm(&emailConfirm)
|
||||
err := user.ConfirmEmail(&emailConfirm)
|
||||
if err != nil {
|
||||
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 (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -38,7 +39,7 @@ import (
|
|||
// @Router /users [get]
|
||||
func UserList(c echo.Context) error {
|
||||
s := c.QueryParam("s")
|
||||
users, err := models.ListUsers(s)
|
||||
users, err := user.ListUsers(s)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
@ -72,7 +73,7 @@ func ListUsersForList(c echo.Context) error {
|
|||
}
|
||||
|
||||
list := models.List{ID: listID}
|
||||
currentUser, err := models.GetCurrentUser(c)
|
||||
currentUser, err := user.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -36,12 +37,12 @@ import (
|
|||
// @Router /user/password/reset [post]
|
||||
func UserResetPassword(c echo.Context) error {
|
||||
// Check for Request Content
|
||||
var pwReset models.PasswordReset
|
||||
var pwReset user.PasswordReset
|
||||
if err := c.Bind(&pwReset); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "No password provided.")
|
||||
}
|
||||
|
||||
err := models.UserPasswordReset(&pwReset)
|
||||
err := user.ResetPassword(&pwReset)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
@ -62,7 +63,7 @@ func UserResetPassword(c echo.Context) error {
|
|||
// @Router /user/password/token [post]
|
||||
func UserRequestResetPasswordToken(c echo.Context) error {
|
||||
// Check for Request Content
|
||||
var pwTokenReset models.PasswordTokenRequest
|
||||
var pwTokenReset user.PasswordTokenRequest
|
||||
if err := c.Bind(&pwTokenReset); err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "No username provided.")
|
||||
}
|
||||
|
@ -71,7 +72,7 @@ func UserRequestResetPasswordToken(c echo.Context) error {
|
|||
return echo.NewHTTPError(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
err := models.RequestUserPasswordResetToken(&pwTokenReset)
|
||||
err := user.RequestUserPasswordResetToken(&pwTokenReset)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -35,12 +35,12 @@ import (
|
|||
// @Failure 500 {object} models.Message "Internal server error."
|
||||
// @Router /user [get]
|
||||
func UserShow(c echo.Context) error {
|
||||
userInfos, err := models.GetCurrentUser(c)
|
||||
userInfos, err := user2.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
|
||||
}
|
||||
|
||||
user, err := models.GetUserByID(userInfos.ID)
|
||||
user, err := user2.GetUserByID(userInfos.ID)
|
||||
if err != nil {
|
||||
return handler.HandleHTTPError(err, c)
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package v1
|
|||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
|
@ -44,7 +45,7 @@ type UserPassword struct {
|
|||
// @Router /user/password [post]
|
||||
func UserChangePassword(c echo.Context) error {
|
||||
// Check if the user is itself
|
||||
doer, err := models.GetCurrentUser(c)
|
||||
doer, err := user.GetCurrentUser(c)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
|
||||
}
|
||||
|
@ -56,16 +57,16 @@ func UserChangePassword(c echo.Context) error {
|
|||
}
|
||||
|
||||
if newPW.OldPassword == "" {
|
||||
return handler.HandleHTTPError(models.ErrEmptyOldPassword{}, c)
|
||||
return handler.HandleHTTPError(user.ErrEmptyOldPassword{}, c)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"bytes"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web/handler"
|
||||
"fmt"
|
||||
"github.com/labstack/echo/v4"
|
||||
|
@ -31,10 +32,10 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func getBasicAuthUserFromContext(c echo.Context) (user models.User, err error) {
|
||||
u, is := c.Get("userBasicAuth").(models.User)
|
||||
func getBasicAuthUserFromContext(c echo.Context) (user.User, error) {
|
||||
u, is := c.Get("userBasicAuth").(user.User)
|
||||
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
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package caldav
|
|||
import (
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/models"
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"github.com/samedi/caldav-go/data"
|
||||
"github.com/samedi/caldav-go/errs"
|
||||
"strconv"
|
||||
|
@ -39,7 +40,7 @@ type VikunjaCaldavListStorage struct {
|
|||
// Used when handling a single task, like updating
|
||||
task *models.Task
|
||||
// The current user
|
||||
user *models.User
|
||||
user *user2.User
|
||||
isPrincipal bool
|
||||
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/models"
|
||||
v1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"time"
|
||||
|
@ -51,7 +52,7 @@ func setupMetrics(a *echo.Group) {
|
|||
},
|
||||
{
|
||||
metrics.UserCountKey,
|
||||
models.User{},
|
||||
user.User{},
|
||||
},
|
||||
{
|
||||
metrics.NamespaceCountKey,
|
||||
|
|
|
@ -53,6 +53,7 @@ import (
|
|||
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
|
||||
"code.vikunja.io/api/pkg/routes/caldav"
|
||||
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"code.vikunja.io/web/handler"
|
||||
"github.com/asaskevich/govalidator"
|
||||
|
@ -407,11 +408,11 @@ func registerCalDavRoutes(c *echo.Group) {
|
|||
}
|
||||
|
||||
func caldavBasicAuth(username, password string, c echo.Context) (bool, error) {
|
||||
creds := &models.UserLogin{
|
||||
creds := &user.Login{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
u, err := models.CheckUserCredentials(creds)
|
||||
u, err := user.CheckUserCredentials(creds)
|
||||
if err != nil {
|
||||
log.Errorf("Error during basic auth for caldav: %v", err)
|
||||
return false, nil
|
||||
|
|
50
pkg/user/db.go
Normal file
50
pkg/user/db.go
Normal file
|
@ -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{},
|
||||
}
|
||||
}
|
291
pkg/user/error.go
Normal file
291
pkg/user/error.go
Normal file
|
@ -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 a new issue