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:
konrad 2020-01-26 17:08:06 +00:00
parent 8c33e24e92
commit 7e9446ea07
108 changed files with 1506 additions and 1024 deletions

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1 +0,0 @@
../../files/fixtures/files.yml

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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:"-"`

View file

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

View file

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

View file

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

View file

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

View file

@ -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"`

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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