diff --git a/docs/content/doc/development/structure.md b/docs/content/doc/development/structure.md
index 8e819b6c..29dc1eba 100644
--- a/docs/content/doc/development/structure.md
+++ b/docs/content/doc/development/structure.md
@@ -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).
diff --git a/docs/content/doc/development/test.md b/docs/content/doc/development/test.md
index 1fdcfe89..55ddc883 100644
--- a/docs/content/doc/development/test.md
+++ b/docs/content/doc/development/test.md
@@ -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).
diff --git a/go.mod b/go.mod
index 2b304391..b1a8ffc5 100644
--- a/go.mod
+++ b/go.mod
@@ -59,7 +59,6 @@ require (
github.com/onsi/gomega v1.4.3 // indirect
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/pelletier/go-toml v1.4.0 // indirect
- github.com/pkg/errors v0.8.1 // indirect
github.com/prometheus/client_golang v0.9.2
github.com/samedi/caldav-go v3.0.0+incompatible
github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b
diff --git a/pkg/caldav/caldav.go b/pkg/caldav/caldav.go
index d988407e..c6cc1f2f 100644
--- a/pkg/caldav/caldav.go
+++ b/pkg/caldav/caldav.go
@@ -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
diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go
index 62d70f8a..d2c1b385 100644
--- a/pkg/cmd/cmd.go
+++ b/pkg/cmd/cmd.go
@@ -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())
diff --git a/pkg/db/db.go b/pkg/db/db.go
index b65dc680..4d9a46ef 100644
--- a/pkg/db/db.go
+++ b/pkg/db/db.go
@@ -23,7 +23,6 @@ import (
"fmt"
"github.com/go-xorm/core"
"github.com/go-xorm/xorm"
- "os"
"strconv"
"time"
@@ -85,33 +84,6 @@ func CreateDBEngine() (engine *xorm.Engine, err error) {
return
}
-// CreateTestEngine creates an instance of the db engine which lives in memory
-func CreateTestEngine() (engine *xorm.Engine, err error) {
-
- if x != nil {
- return x, nil
- }
-
- if os.Getenv("VIKUNJA_TESTS_USE_CONFIG") == "1" {
- config.InitConfig()
- engine, err = CreateDBEngine()
- if err != nil {
- return nil, err
- }
- } else {
- engine, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared")
- if err != nil {
- return nil, err
- }
- }
-
- engine.SetMapper(core.GonicMapper{})
- engine.ShowSQL(os.Getenv("UNIT_TESTS_VERBOSE") == "1")
- engine.SetLogger(xorm.NewSimpleLogger(log.GetLogWriter("database")))
- x = engine
- return
-}
-
// RegisterTableStructsForCache registers tables in gob encoding for redis cache
func RegisterTableStructsForCache(val interface{}) {
gob.Register(val)
diff --git a/pkg/files/fixtures/files.yml b/pkg/db/fixtures/files.yml
similarity index 100%
rename from pkg/files/fixtures/files.yml
rename to pkg/db/fixtures/files.yml
diff --git a/pkg/models/fixtures/label_task.yml b/pkg/db/fixtures/label_task.yml
similarity index 100%
rename from pkg/models/fixtures/label_task.yml
rename to pkg/db/fixtures/label_task.yml
diff --git a/pkg/models/fixtures/labels.yml b/pkg/db/fixtures/labels.yml
similarity index 100%
rename from pkg/models/fixtures/labels.yml
rename to pkg/db/fixtures/labels.yml
diff --git a/pkg/models/fixtures/link_sharing.yml b/pkg/db/fixtures/link_sharing.yml
similarity index 100%
rename from pkg/models/fixtures/link_sharing.yml
rename to pkg/db/fixtures/link_sharing.yml
diff --git a/pkg/models/fixtures/list.yml b/pkg/db/fixtures/list.yml
similarity index 100%
rename from pkg/models/fixtures/list.yml
rename to pkg/db/fixtures/list.yml
diff --git a/pkg/models/fixtures/namespaces.yml b/pkg/db/fixtures/namespaces.yml
similarity index 100%
rename from pkg/models/fixtures/namespaces.yml
rename to pkg/db/fixtures/namespaces.yml
diff --git a/pkg/models/fixtures/task_assignees.yml b/pkg/db/fixtures/task_assignees.yml
similarity index 100%
rename from pkg/models/fixtures/task_assignees.yml
rename to pkg/db/fixtures/task_assignees.yml
diff --git a/pkg/models/fixtures/task_attachments.yml b/pkg/db/fixtures/task_attachments.yml
similarity index 100%
rename from pkg/models/fixtures/task_attachments.yml
rename to pkg/db/fixtures/task_attachments.yml
diff --git a/pkg/models/fixtures/task_relations.yml b/pkg/db/fixtures/task_relations.yml
similarity index 100%
rename from pkg/models/fixtures/task_relations.yml
rename to pkg/db/fixtures/task_relations.yml
diff --git a/pkg/models/fixtures/task_reminders.yml b/pkg/db/fixtures/task_reminders.yml
similarity index 100%
rename from pkg/models/fixtures/task_reminders.yml
rename to pkg/db/fixtures/task_reminders.yml
diff --git a/pkg/models/fixtures/tasks.yml b/pkg/db/fixtures/tasks.yml
similarity index 100%
rename from pkg/models/fixtures/tasks.yml
rename to pkg/db/fixtures/tasks.yml
diff --git a/pkg/models/fixtures/team_list.yml b/pkg/db/fixtures/team_list.yml
similarity index 100%
rename from pkg/models/fixtures/team_list.yml
rename to pkg/db/fixtures/team_list.yml
diff --git a/pkg/models/fixtures/team_members.yml b/pkg/db/fixtures/team_members.yml
similarity index 100%
rename from pkg/models/fixtures/team_members.yml
rename to pkg/db/fixtures/team_members.yml
diff --git a/pkg/models/fixtures/team_namespaces.yml b/pkg/db/fixtures/team_namespaces.yml
similarity index 100%
rename from pkg/models/fixtures/team_namespaces.yml
rename to pkg/db/fixtures/team_namespaces.yml
diff --git a/pkg/models/fixtures/teams.yml b/pkg/db/fixtures/teams.yml
similarity index 100%
rename from pkg/models/fixtures/teams.yml
rename to pkg/db/fixtures/teams.yml
diff --git a/pkg/models/fixtures/users.yml b/pkg/db/fixtures/users.yml
similarity index 100%
rename from pkg/models/fixtures/users.yml
rename to pkg/db/fixtures/users.yml
diff --git a/pkg/models/fixtures/users_list.yml b/pkg/db/fixtures/users_list.yml
similarity index 100%
rename from pkg/models/fixtures/users_list.yml
rename to pkg/db/fixtures/users_list.yml
diff --git a/pkg/models/fixtures/users_namespace.yml b/pkg/db/fixtures/users_namespace.yml
similarity index 100%
rename from pkg/models/fixtures/users_namespace.yml
rename to pkg/db/fixtures/users_namespace.yml
diff --git a/pkg/db/test.go b/pkg/db/test.go
new file mode 100644
index 00000000..a7131084
--- /dev/null
+++ b/pkg/db/test.go
@@ -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 .
+
+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
+}
diff --git a/pkg/db/test_fixtures.go b/pkg/db/test_fixtures.go
index 3ad9708b..16d75a2b 100644
--- a/pkg/db/test_fixtures.go
+++ b/pkg/db/test_fixtures.go
@@ -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)
- fixtures, err = testfixtures.NewFolder(x.DB().DB, helper, dir)
+
+ // If fixture table names are specified, load them
+ // Otherwise, load all fixtures
+ if len(tablenames) > 0 {
+ for i, name := range tablenames {
+ tablenames[i] = filepath.Join(dir, name+".yml")
+ }
+ fixtures, err = testfixtures.NewFiles(x.DB().DB, helper, tablenames...)
+ } else {
+ fixtures, err = testfixtures.NewFolder(x.DB().DB, helper, dir)
+ }
return err
}
@@ -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)
+}
diff --git a/pkg/files/filehandling.go b/pkg/files/filehandling.go
index 53c12e9e..3540b26e 100644
--- a/pkg/files/filehandling.go
+++ b/pkg/files/filehandling.go
@@ -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)
}
diff --git a/pkg/integrations/integrations.go b/pkg/integrations/integrations.go
index 40bf5027..008271e3 100644
--- a/pkg/integrations/integrations.go
+++ b/pkg/integrations/integrations.go
@@ -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
diff --git a/pkg/integrations/login_test.go b/pkg/integrations/login_test.go
index 546e0270..e6ad2181 100644
--- a/pkg/integrations/login_test.go
+++ b/pkg/integrations/login_test.go
@@ -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)
})
}
diff --git a/pkg/integrations/register_test.go b/pkg/integrations/register_test.go
index 34b28de0..3ce59a08 100644
--- a/pkg/integrations/register_test.go
+++ b/pkg/integrations/register_test.go
@@ -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)
})
}
diff --git a/pkg/integrations/user_change_password_test.go b/pkg/integrations/user_change_password_test.go
index 5d639e29..e9afdc5e 100644
--- a/pkg/integrations/user_change_password_test.go
+++ b/pkg/integrations/user_change_password_test.go
@@ -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)
})
}
diff --git a/pkg/integrations/user_confirm_email_test.go b/pkg/integrations/user_confirm_email_test.go
index 9e439af2..35bd769f 100644
--- a/pkg/integrations/user_confirm_email_test.go
+++ b/pkg/integrations/user_confirm_email_test.go
@@ -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)
})
}
diff --git a/pkg/integrations/user_password_request_token_test.go b/pkg/integrations/user_password_request_token_test.go
index e171d7b8..12f1f72c 100644
--- a/pkg/integrations/user_password_request_token_test.go
+++ b/pkg/integrations/user_password_request_token_test.go
@@ -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)
})
}
diff --git a/pkg/integrations/user_password_reset_test.go b/pkg/integrations/user_password_reset_test.go
index 50e09c89..28867b21 100644
--- a/pkg/integrations/user_password_reset_test.go
+++ b/pkg/integrations/user_password_reset_test.go
@@ -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)
})
}
diff --git a/pkg/migration/migration.go b/pkg/migration/migration.go
index 0d7bbfeb..b55390a8 100644
--- a/pkg/migration/migration.go
+++ b/pkg/migration/migration.go
@@ -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...)
}
diff --git a/pkg/models/bulk_task_test.go b/pkg/models/bulk_task_test.go
index 289ba09c..39aa9f84 100644
--- a/pkg/models/bulk_task_test.go
+++ b/pkg/models/bulk_task_test.go
@@ -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,
diff --git a/pkg/models/error.go b/pkg/models/error.go
index 0aa69d39..110a1198 100644
--- a/pkg/models/error.go
+++ b/pkg/models/error.go
@@ -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
// ===================
diff --git a/pkg/models/fixtures/files.yml b/pkg/models/fixtures/files.yml
deleted file mode 120000
index aa889441..00000000
--- a/pkg/models/fixtures/files.yml
+++ /dev/null
@@ -1 +0,0 @@
-../../files/fixtures/files.yml
\ No newline at end of file
diff --git a/pkg/models/label.go b/pkg/models/label.go
index 9f226baf..8e525cbc 100644
--- a/pkg/models/label.go
+++ b/pkg/models/label.go
@@ -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)
diff --git a/pkg/models/label_rights.go b/pkg/models/label_rights.go
index c7c6fe6f..9c884def 100644
--- a/pkg/models/label_rights.go
+++ b/pkg/models/label_rights.go
@@ -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
}
diff --git a/pkg/models/label_task.go b/pkg/models/label_task.go
index bb2f57f2..6c7faa47 100644
--- a/pkg/models/label_task.go
+++ b/pkg/models/label_task.go
@@ -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}
}
diff --git a/pkg/models/label_task_test.go b/pkg/models/label_task_test.go
index 5d619857..cd497e85 100644
--- a/pkg/models/label_task_test.go
+++ b/pkg/models/label_task_test.go
@@ -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,
diff --git a/pkg/models/label_test.go b/pkg/models/label_test.go
index 96c2b61e..92b7537f 100644
--- a/pkg/models/label_test.go
+++ b/pkg/models/label_test.go
@@ -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,
},
}
diff --git a/pkg/models/link_sharing.go b/pkg/models/link_sharing.go
index 9012eee8..115e3405 100644
--- a/pkg/models/link_sharing.go
+++ b/pkg/models/link_sharing.go
@@ -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,8 +49,8 @@ type LinkSharing struct {
SharingType SharingType `xorm:"int(11) INDEX not null default 0" json:"sharing_type" valid:"length(0|2)" maximum:"2" default:"0"`
// The user who shared this list
- SharedBy *User `xorm:"-" json:"shared_by"`
- SharedByID int64 `xorm:"int(11) INDEX not null" json:"-"`
+ 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.
Created int64 `xorm:"created not null" json:"created"`
@@ -100,7 +101,7 @@ func (share *LinkSharing) Create(a web.Auth) (err error) {
share.SharedByID = a.GetID()
share.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
diff --git a/pkg/models/list.go b/pkg/models/list.go
index 0f3a4726..b18da771 100644
--- a/pkg/models/list.go
+++ b/pkg/models/list.go
@@ -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
}
diff --git a/pkg/models/list_rights.go b/pkg/models/list_rights.go
index 0a5eef8d..d3f96c8c 100644
--- a/pkg/models/list_rights.go
+++ b/pkg/models/list_rights.go
@@ -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
}
diff --git a/pkg/models/list_team_test.go b/pkg/models/list_team_test.go
index b6e9c68b..984c7069 100644
--- a/pkg/models/list_team_test.go
+++ b/pkg/models/list_team_test.go
@@ -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,
diff --git a/pkg/models/list_test.go b/pkg/models/list_test.go
index 7431b5ed..0c88428f 100644
--- a/pkg/models/list_test.go
+++ b/pkg/models/list_test.go
@@ -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))
})
}
diff --git a/pkg/models/list_users.go b/pkg/models/list_users.go
index f2b5a747..20564ef9 100644
--- a/pkg/models/list_users.go
+++ b/pkg/models/list_users.go
@@ -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,8 +50,8 @@ 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"`
- Right Right `json:"right"`
+ user.User `xorm:"extends"`
+ Right Right `json:"right"`
}
// Create creates a new list <-> user relation
@@ -80,7 +83,7 @@ func (lu *ListUser) Create(a web.Auth) (err error) {
}
// Check if the user exists
- 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
}
diff --git a/pkg/models/list_users_rights_test.go b/pkg/models/list_users_rights_test.go
index 1fac2635..1ba105fe 100644
--- a/pkg/models/list_users_rights_test.go
+++ b/pkg/models/list_users_rights_test.go
@@ -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,
diff --git a/pkg/models/list_users_test.go b/pkg/models/list_users_test.go
index 07daafaf..ab3c61db 100644
--- a/pkg/models/list_users_test.go
+++ b/pkg/models/list_users_test.go
@@ -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,
diff --git a/pkg/models/main_test.go b/pkg/models/main_test.go
index 7c1911aa..c3c912f6 100644
--- a/pkg/models/main_test.go
+++ b/pkg/models/main_test.go
@@ -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())
}
diff --git a/pkg/models/models.go b/pkg/models/models.go
index 33275901..4248f6a4 100644
--- a/pkg/models/models.go
+++ b/pkg/models/models.go
@@ -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{},
diff --git a/pkg/models/namespace.go b/pkg/models/namespace.go
index 932d0a70..7b68de05 100644
--- a/pkg/models/namespace.go
+++ b/pkg/models/namespace.go
@@ -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
}
diff --git a/pkg/models/namespace_team_rights_test.go b/pkg/models/namespace_team_rights_test.go
index 09b3d783..1634445a 100644
--- a/pkg/models/namespace_team_rights_test.go
+++ b/pkg/models/namespace_team_rights_test.go
@@ -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,
diff --git a/pkg/models/namespace_team_test.go b/pkg/models/namespace_team_test.go
index ef07cafc..a97ab9f1 100644
--- a/pkg/models/namespace_team_test.go
+++ b/pkg/models/namespace_team_test.go
@@ -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,
diff --git a/pkg/models/namespace_test.go b/pkg/models/namespace_test.go
index 81b4ef99..d510a768 100644
--- a/pkg/models/namespace_test.go
+++ b/pkg/models/namespace_test.go
@@ -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 = ""
diff --git a/pkg/models/namespace_users.go b/pkg/models/namespace_users.go
index b311b51f..b6256316 100644
--- a/pkg/models/namespace_users.go
+++ b/pkg/models/namespace_users.go
@@ -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
}
diff --git a/pkg/models/namespace_users_rights_test.go b/pkg/models/namespace_users_rights_test.go
index 20de120f..b48586c3 100644
--- a/pkg/models/namespace_users_rights_test.go
+++ b/pkg/models/namespace_users_rights_test.go
@@ -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,
diff --git a/pkg/models/namespace_users_test.go b/pkg/models/namespace_users_test.go
index 4bcb49d9..0fc7fd8f 100644
--- a/pkg/models/namespace_users_test.go
+++ b/pkg/models/namespace_users_test.go
@@ -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,
diff --git a/pkg/models/task_assignees.go b/pkg/models/task_assignees.go
index b588a649..2a59569a 100644
--- a/pkg/models/task_assignees.go
+++ b/pkg/models/task_assignees.go
@@ -17,6 +17,7 @@
package models
import (
+ "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
@@ -38,8 +39,8 @@ func (TaskAssginee) TableName() string {
// TaskAssigneeWithUser is a helper type to deal with user joins
type TaskAssigneeWithUser struct {
- TaskID int64
- User `xorm:"extends"`
+ TaskID int64
+ 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,15 +268,15 @@ 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"`
- TaskID int64 `json:"-" param:"listtask"`
+ Assignees []*user.User `json:"assignees"`
+ TaskID int64 `json:"-" param:"listtask"`
web.CRUDable `json:"-"`
web.Rights `json:"-"`
diff --git a/pkg/models/task_attachment.go b/pkg/models/task_attachment.go
index b62f8952..0ff9e9bf 100644
--- a/pkg/models/task_attachment.go
+++ b/pkg/models/task_attachment.go
@@ -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"
@@ -29,8 +30,8 @@ type TaskAttachment struct {
TaskID int64 `xorm:"int(11) not null" json:"task_id" param:"task"`
FileID int64 `xorm:"int(11) not null" json:"-"`
- CreatedByID int64 `xorm:"int(11) not null" json:"-"`
- CreatedBy *User `xorm:"-" json:"created_by"`
+ CreatedByID int64 `xorm:"int(11) not null" json:"-"`
+ 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
diff --git a/pkg/models/task_attachment_test.go b/pkg/models/task_attachment_test.go
index cdb863e9..292405ca 100644
--- a/pkg/models/task_attachment_test.go
+++ b/pkg/models/task_attachment_test.go
@@ -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}
diff --git a/pkg/models/task_collection.go b/pkg/models/task_collection.go
index 73840c76..de19f646 100644
--- a/pkg/models/task_collection.go
+++ b/pkg/models/task_collection.go
@@ -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
}
diff --git a/pkg/models/task_collection_test.go b/pkg/models/task_collection_test.go
index 26807a6c..d3b440b6 100644
--- a/pkg/models/task_collection_test.go
+++ b/pkg/models/task_collection_test.go
@@ -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,
diff --git a/pkg/models/task_relation.go b/pkg/models/task_relation.go
index c11d9911..75b8b4fe 100644
--- a/pkg/models/task_relation.go
+++ b/pkg/models/task_relation.go
@@ -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"`
diff --git a/pkg/models/task_relation_test.go b/pkg/models/task_relation_test.go
index 52f6c4f4..b804f0e3 100644
--- a/pkg/models/task_relation_test.go
+++ b/pkg/models/task_relation_test.go
@@ -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)
diff --git a/pkg/models/tasks.go b/pkg/models/tasks.go
index ee99e6ef..a6469c81 100644
--- a/pkg/models/tasks.go
+++ b/pkg/models/tasks.go
@@ -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
}
diff --git a/pkg/models/tasks_test.go b/pkg/models/tasks_test.go
index 2d40bf9e..af6ba540 100644
--- a/pkg/models/tasks_test.go
+++ b/pkg/models/tasks_test.go
@@ -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)
diff --git a/pkg/models/team_members.go b/pkg/models/team_members.go
index 39acedc9..9fb2f81f 100644
--- a/pkg/models/team_members.go
+++ b/pkg/models/team_members.go
@@ -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
}
diff --git a/pkg/models/team_members_test.go b/pkg/models/team_members_test.go
index 3d43ff39..4f9a4a30 100644
--- a/pkg/models/team_members_test.go
+++ b/pkg/models/team_members_test.go
@@ -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"}
diff --git a/pkg/models/teams.go b/pkg/models/teams.go
index db8a6d4d..b77047f7 100644
--- a/pkg/models/teams.go
+++ b/pkg/models/teams.go
@@ -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
}
diff --git a/pkg/models/teams_rights_test.go b/pkg/models/teams_rights_test.go
index 45ac3446..3c8c27dc 100644
--- a/pkg/models/teams_rights_test.go
+++ b/pkg/models/teams_rights_test.go
@@ -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,
diff --git a/pkg/models/teams_test.go b/pkg/models/teams_test.go
index 01d7360b..e08f89a5 100644
--- a/pkg/models/teams_test.go
+++ b/pkg/models/teams_test.go
@@ -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
diff --git a/pkg/models/unit_tests.go b/pkg/models/unit_tests.go
index 84fa0979..57d00869 100644
--- a/pkg/models/unit_tests.go
+++ b/pkg/models/unit_tests.go
@@ -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)
}
diff --git a/pkg/models/users_list.go b/pkg/models/user_list.go
similarity index 79%
rename from pkg/models/users_list.go
rename to pkg/models/user_list.go
index c0aefe12..d23b993c 100644
--- a/pkg/models/users_list.go
+++ b/pkg/models/user_list.go
@@ -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 .
+// along with Vikunja. If not, see .
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{}
diff --git a/pkg/models/user_test.go b/pkg/models/user_test.go
deleted file mode 100644
index f400875c..00000000
--- a/pkg/models/user_test.go
+++ /dev/null
@@ -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 .
-
-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))
-}
diff --git a/pkg/models/users_list_test.go b/pkg/models/users_list_test.go
index 2512088d..3d2cf900 100644
--- a/pkg/models/users_list_test.go
+++ b/pkg/models/users_list_test.go
@@ -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 .
+
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)
diff --git a/pkg/modules/migration/create_from_structure.go b/pkg/modules/migration/create_from_structure.go
index 07164e64..7796715f 100644
--- a/pkg/modules/migration/create_from_structure.go
+++ b/pkg/modules/migration/create_from_structure.go
@@ -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 {
diff --git a/pkg/modules/migration/handler/handler.go b/pkg/modules/migration/handler/handler.go
index 805e9374..a8678024 100644
--- a/pkg/modules/migration/handler/handler.go
+++ b/pkg/modules/migration/handler/handler.go
@@ -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)
}
diff --git a/pkg/modules/migration/migration_status.go b/pkg/modules/migration/migration_status.go
index 4ec8bec8..e5209340 100644
--- a/pkg/modules/migration/migration_status.go
+++ b/pkg/modules/migration/migration_status.go
@@ -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
diff --git a/pkg/modules/migration/migrator.go b/pkg/modules/migration/migrator.go
index 8ea27391..059a2be5 100644
--- a/pkg/modules/migration/migrator.go
+++ b/pkg/modules/migration/migrator.go
@@ -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.
diff --git a/pkg/modules/migration/wunderlist/wunderlist.go b/pkg/modules/migration/wunderlist/wunderlist.go
index 3930146b..1d9c6bee 100644
--- a/pkg/modules/migration/wunderlist/wunderlist.go
+++ b/pkg/modules/migration/wunderlist/wunderlist.go
@@ -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)
diff --git a/pkg/routes/api/v1/auth.go b/pkg/routes/api/v1/auth.go
index ee7688e1..17553179 100644
--- a/pkg/routes/api/v1/auth.go
+++ b/pkg/routes/api/v1/auth.go
@@ -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."})
}
diff --git a/pkg/routes/api/v1/list_by_namespace.go b/pkg/routes/api/v1/list_by_namespace.go
index 6287c153..9bc5b54c 100644
--- a/pkg/routes/api/v1/list_by_namespace.go
+++ b/pkg/routes/api/v1/list_by_namespace.go
@@ -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
}
diff --git a/pkg/routes/api/v1/login.go b/pkg/routes/api/v1/login.go
index 2eeea4fe..e92bad3b 100644
--- a/pkg/routes/api/v1/login.go
+++ b/pkg/routes/api/v1/login.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/task_attachment.go b/pkg/routes/api/v1/task_attachment.go
index 4d189ed0..d1d60355 100644
--- a/pkg/routes/api/v1/task_attachment.go
+++ b/pkg/routes/api/v1/task_attachment.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/user_add_update.go b/pkg/routes/api/v1/user_add_update.go
index 08aa4390..42e5a025 100644
--- a/pkg/routes/api/v1/user_add_update.go
+++ b/pkg/routes/api/v1/user_add_update.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/user_confirm_email.go b/pkg/routes/api/v1/user_confirm_email.go
index f5021ad0..66b4e2dd 100644
--- a/pkg/routes/api/v1/user_confirm_email.go
+++ b/pkg/routes/api/v1/user_confirm_email.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/user_delete.go b/pkg/routes/api/v1/user_delete.go
deleted file mode 100644
index 8940b22b..00000000
--- a/pkg/routes/api/v1/user_delete.go
+++ /dev/null
@@ -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 .
-
-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"})
-}
diff --git a/pkg/routes/api/v1/user_list.go b/pkg/routes/api/v1/user_list.go
index 8ae33399..abfca4c4 100644
--- a/pkg/routes/api/v1/user_list.go
+++ b/pkg/routes/api/v1/user_list.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/user_password_reset.go b/pkg/routes/api/v1/user_password_reset.go
index 62512c79..4b2bb6d8 100644
--- a/pkg/routes/api/v1/user_password_reset.go
+++ b/pkg/routes/api/v1/user_password_reset.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/user_show.go b/pkg/routes/api/v1/user_show.go
index 5cae05c5..390a5879 100644
--- a/pkg/routes/api/v1/user_show.go
+++ b/pkg/routes/api/v1/user_show.go
@@ -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)
}
diff --git a/pkg/routes/api/v1/user_update_password.go b/pkg/routes/api/v1/user_update_password.go
index 74c251e5..4c775eb0 100644
--- a/pkg/routes/api/v1/user_update_password.go
+++ b/pkg/routes/api/v1/user_update_password.go
@@ -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)
}
diff --git a/pkg/routes/caldav/handler.go b/pkg/routes/caldav/handler.go
index afab3527..52d36160 100644
--- a/pkg/routes/caldav/handler.go
+++ b/pkg/routes/caldav/handler.go
@@ -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
}
diff --git a/pkg/routes/caldav/listStorageProvider.go b/pkg/routes/caldav/listStorageProvider.go
index 88419892..1d9f8663 100644
--- a/pkg/routes/caldav/listStorageProvider.go
+++ b/pkg/routes/caldav/listStorageProvider.go
@@ -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
}
diff --git a/pkg/routes/metrics.go b/pkg/routes/metrics.go
index b960f602..1f811abf 100644
--- a/pkg/routes/metrics.go
+++ b/pkg/routes/metrics.go
@@ -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,
diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go
index fdb6705d..6facec41 100644
--- a/pkg/routes/routes.go
+++ b/pkg/routes/routes.go
@@ -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
diff --git a/pkg/user/db.go b/pkg/user/db.go
new file mode 100644
index 00000000..a1f3b731
--- /dev/null
+++ b/pkg/user/db.go
@@ -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 .
+
+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{},
+ }
+}
diff --git a/pkg/user/error.go b/pkg/user/error.go
new file mode 100644
index 00000000..1a26a5b7
--- /dev/null
+++ b/pkg/user/error.go
@@ -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 .
+
+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."}
+}
diff --git a/pkg/user/main_test.go b/pkg/user/main_test.go
new file mode 100644
index 00000000..57a0e921
--- /dev/null
+++ b/pkg/user/main_test.go
@@ -0,0 +1,29 @@
+// 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 .
+
+package user
+
+import (
+ "os"
+ "testing"
+)
+
+// TestMain is the main test function used to bootstrap the test env
+func TestMain(m *testing.M) {
+ InitTests()
+ os.Exit(m.Run())
+}
diff --git a/pkg/user/test.go b/pkg/user/test.go
new file mode 100644
index 00000000..f2a61cd2
--- /dev/null
+++ b/pkg/user/test.go
@@ -0,0 +1,42 @@
+// 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 .
+
+package user
+
+import (
+ "code.vikunja.io/api/pkg/db"
+ "code.vikunja.io/api/pkg/log"
+)
+
+// InitTests handles the actual bootstrapping of the test env
+func InitTests() {
+ var err error
+ x, err = db.CreateTestEngine()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = x.Sync2(GetTables()...)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ err = db.InitTestFixtures("users")
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/pkg/models/user.go b/pkg/user/user.go
similarity index 89%
rename from pkg/models/user.go
rename to pkg/user/user.go
index e2c2e810..42cfc33d 100644
--- a/pkg/models/user.go
+++ b/pkg/user/user.go
@@ -1,20 +1,21 @@
-// Vikunja is a todo-list application to facilitate your life.
-// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
+// Copyright2018-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 .
+// along with Vikunja. If not, see .
-package models
+package user
import (
"code.vikunja.io/api/pkg/config"
@@ -29,8 +30,8 @@ import (
"reflect"
)
-// UserLogin Object to recive user credentials in JSON format
-type UserLogin struct {
+// Login Object to recive user credentials in JSON format
+type Login struct {
// The username used to log in.
Username string `json:"username"`
// The password for the user.
@@ -76,7 +77,9 @@ func (User) TableName() string {
return "users"
}
-func getUserWithError(a web.Auth) (*User, error) {
+// GetFromAuth returns a user object from a web.Auth object and returns an error if the underlying type
+// is not a user object
+func GetFromAuth(a web.Auth) (*User, error) {
u, is := a.(*User)
if !is {
return &User{}, fmt.Errorf("user is not user element, is %s", reflect.TypeOf(a))
@@ -153,7 +156,7 @@ func getUser(user *User, withEmail bool) (userOut *User, err error) {
}
// CheckUserCredentials checks user credentials
-func CheckUserCredentials(u *UserLogin) (*User, error) {
+func CheckUserCredentials(u *Login) (*User, error) {
// Check if we have any credentials
if u.Password == "" || u.Username == "" {
return &User{}, ErrNoUsernamePassword{}
@@ -273,13 +276,6 @@ func CreateUser(user *User) (newUser *User, err error) {
return &User{}, err
}
- // Create the user's namespace
- newN := &Namespace{Name: newUserOut.Username, Description: newUserOut.Username + "'s namespace.", Owner: newUserOut}
- err = newN.Create(newUserOut)
- if err != nil {
- return &User{}, err
- }
-
// Dont send a mail if we're testing
if !config.MailerEnabled.GetBool() {
return newUserOut, err
@@ -361,23 +357,3 @@ func UpdateUserPassword(user *User, newPassword string) (err error) {
return err
}
-
-// DeleteUserByID deletes a user by its ID
-func DeleteUserByID(id int64, doer *User) error {
- // Check if the id is 0
- if id == 0 {
- return ErrIDCannotBeZero{}
- }
-
- // Delete the user
- _, err := x.Id(id).Delete(&User{})
-
- if err != nil {
- return err
- }
-
- // Update the metrics
- metrics.UpdateCount(-1, metrics.ActiveUsersKey)
-
- return err
-}
diff --git a/pkg/models/user_email_confirm.go b/pkg/user/user_email_confirm.go
similarity index 69%
rename from pkg/models/user_email_confirm.go
rename to pkg/user/user_email_confirm.go
index 216d89b7..68378c2b 100644
--- a/pkg/models/user_email_confirm.go
+++ b/pkg/user/user_email_confirm.go
@@ -1,20 +1,21 @@
-// Vikunja is a todo-list application to facilitate your life.
-// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
+// Copyright2018-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 .
+// along with Vikunja. If not, see .
-package models
+package user
// EmailConfirm holds the token to confirm a mail address
type EmailConfirm struct {
@@ -22,8 +23,8 @@ type EmailConfirm struct {
Token string `json:"token"`
}
-// UserEmailConfirm handles the confirmation of an email address
-func UserEmailConfirm(c *EmailConfirm) (err error) {
+// ConfirmEmail handles the confirmation of an email address
+func ConfirmEmail(c *EmailConfirm) (err error) {
// Check if we have an email confirm token
if c.Token == "" {
diff --git a/pkg/models/user_email_confirm_test.go b/pkg/user/user_email_confirm_test.go
similarity index 69%
rename from pkg/models/user_email_confirm_test.go
rename to pkg/user/user_email_confirm_test.go
index e2401805..bfb38138 100644
--- a/pkg/models/user_email_confirm_test.go
+++ b/pkg/user/user_email_confirm_test.go
@@ -1,22 +1,26 @@
-// Vikunja is a todo-list application to facilitate your life.
-// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
+// Copyright2018-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 .
+// along with Vikunja. If not, see .
-package models
+package user
-import "testing"
+import (
+ "code.vikunja.io/api/pkg/db"
+ "testing"
+)
func TestUserEmailConfirm(t *testing.T) {
type args struct {
@@ -59,8 +63,9 @@ func TestUserEmailConfirm(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if err := UserEmailConfirm(tt.args.c); (err != nil) != tt.wantErr {
- t.Errorf("UserEmailConfirm() error = %v, wantErr %v", err, tt.wantErr)
+ db.LoadAndAssertFixtures(t)
+ if err := ConfirmEmail(tt.args.c); (err != nil) != tt.wantErr {
+ t.Errorf("ConfirmEmail() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
diff --git a/pkg/models/user_password_reset.go b/pkg/user/user_password_reset.go
similarity index 85%
rename from pkg/models/user_password_reset.go
rename to pkg/user/user_password_reset.go
index f2d273bc..24d47d2b 100644
--- a/pkg/models/user_password_reset.go
+++ b/pkg/user/user_password_reset.go
@@ -1,20 +1,21 @@
-// Vikunja is a todo-list application to facilitate your life.
-// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
+// Copyright2018-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 .
+// along with Vikunja. If not, see .
-package models
+package user
import (
"code.vikunja.io/api/pkg/config"
@@ -30,8 +31,8 @@ type PasswordReset struct {
NewPassword string `json:"new_password"`
}
-// UserPasswordReset resets a users password
-func UserPasswordReset(reset *PasswordReset) (err error) {
+// ResetPassword resets a users password
+func ResetPassword(reset *PasswordReset) (err error) {
// Check if the password is not empty
if reset.NewPassword == "" {
diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go
new file mode 100644
index 00000000..4ff75759
--- /dev/null
+++ b/pkg/user/user_test.go
@@ -0,0 +1,301 @@
+// 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 .
+
+package user
+
+import (
+ "code.vikunja.io/api/pkg/db"
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestCreateUser(t *testing.T) {
+ // Our dummy user for testing
+ dummyuser := &User{
+ Username: "testuser",
+ Password: "1234",
+ Email: "noone@example.com",
+ }
+
+ t.Run("normal", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ createdUser, err := CreateUser(dummyuser)
+ assert.NoError(t, err)
+ assert.NotZero(t, createdUser.Created)
+ })
+ t.Run("already existing", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CreateUser(&User{
+ Username: "user1",
+ Password: "12345",
+ Email: "email@example.com",
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrUsernameExists(err))
+ })
+ t.Run("same email", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CreateUser(&User{
+ Username: "testuser",
+ Password: "12345",
+ Email: "user1@example.com",
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrUserEmailExists(err))
+ })
+ t.Run("no username", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CreateUser(&User{
+ Username: "",
+ Password: "12345",
+ Email: "user1@example.com",
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrNoUsernamePassword(err))
+ })
+ t.Run("no password", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CreateUser(&User{
+ Username: "testuser",
+ Password: "",
+ Email: "user1@example.com",
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrNoUsernamePassword(err))
+ })
+ t.Run("no email", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CreateUser(&User{
+ Username: "testuser",
+ Password: "12345",
+ Email: "",
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrNoUsernamePassword(err))
+ })
+}
+
+func TestGetUser(t *testing.T) {
+ t.Run("by name", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ theuser, err := GetUser(&User{
+ Username: "user1",
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, theuser.ID, int64(1))
+ assert.Empty(t, theuser.Email)
+ })
+ t.Run("by email", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ theuser, err := GetUser(&User{
+ Email: "user1@example.com",
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, theuser.ID, int64(1))
+ assert.Empty(t, theuser.Email)
+ })
+ t.Run("by id", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ theuser, err := GetUserByID(1)
+ assert.NoError(t, err)
+ assert.Equal(t, theuser.ID, int64(1))
+ assert.Equal(t, theuser.Username, "user1")
+ assert.Empty(t, theuser.Email)
+ })
+ t.Run("invalid id", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := GetUserByID(99999)
+ assert.Error(t, err)
+ assert.True(t, IsErrUserDoesNotExist(err))
+ })
+ t.Run("nonexistant", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := GetUserByID(0)
+ assert.Error(t, err)
+ assert.True(t, IsErrUserDoesNotExist(err))
+ })
+ t.Run("empty name", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := GetUserByUsername("")
+ assert.Error(t, err)
+ assert.True(t, IsErrUserDoesNotExist(err))
+ })
+ t.Run("with email", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ theuser, err := GetUserWithEmail(&User{ID: 1})
+ assert.NoError(t, err)
+ assert.Equal(t, theuser.ID, int64(1))
+ assert.Equal(t, theuser.Username, "user1")
+ assert.NotEmpty(t, theuser.Email)
+ })
+}
+
+func TestCheckUserCredentials(t *testing.T) {
+ t.Run("normal", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CheckUserCredentials(&Login{"user1", "1234"})
+ assert.NoError(t, err)
+ })
+ t.Run("unverified email", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CheckUserCredentials(&Login{"user5", "1234"})
+ assert.Error(t, err)
+ assert.True(t, IsErrEmailNotConfirmed(err))
+ })
+ t.Run("wrong password", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CheckUserCredentials(&Login{"user1", "12345"})
+ assert.Error(t, err)
+ assert.True(t, IsErrWrongUsernameOrPassword(err))
+ })
+ t.Run("nonexistant user", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CheckUserCredentials(&Login{"dfstestuu", "1234"})
+ assert.Error(t, err)
+ assert.True(t, IsErrWrongUsernameOrPassword(err))
+ })
+ t.Run("empty password", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CheckUserCredentials(&Login{"user1", ""})
+ assert.Error(t, err)
+ assert.True(t, IsErrNoUsernamePassword(err))
+ })
+ t.Run("empty username", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := CheckUserCredentials(&Login{"", "1234"})
+ assert.Error(t, err)
+ assert.True(t, IsErrNoUsernamePassword(err))
+ })
+}
+
+func TestUpdateUser(t *testing.T) {
+ t.Run("normal", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ uuser, err := UpdateUser(&User{
+ ID: 1,
+ Password: "LoremIpsum",
+ Email: "testing@example.com",
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", uuser.Password) // Password should not change
+ assert.Equal(t, "user1", uuser.Username) // Username should not change either
+ })
+ t.Run("change username", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ uuser, err := UpdateUser(&User{
+ ID: 1,
+ Username: "changedname",
+ })
+ assert.NoError(t, err)
+ assert.Equal(t, "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", uuser.Password) // Password should not change
+ assert.Equal(t, "changedname", uuser.Username)
+ })
+ t.Run("nonexistant", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ _, err := UpdateUser(&User{
+ ID: 99999,
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrUserDoesNotExist(err))
+ })
+}
+
+func TestUpdateUserPassword(t *testing.T) {
+
+ t.Run("normal", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ err := UpdateUserPassword(&User{
+ ID: 1,
+ }, "12345",
+ )
+ assert.NoError(t, err)
+ })
+ t.Run("nonexistant user", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ err := UpdateUserPassword(&User{
+ ID: 9999,
+ }, "12345")
+ assert.Error(t, err)
+ assert.True(t, IsErrUserDoesNotExist(err))
+ })
+ t.Run("empty password", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ err := UpdateUserPassword(&User{
+ ID: 1,
+ }, "",
+ )
+ assert.Error(t, err)
+ assert.True(t, IsErrEmptyNewPassword(err))
+ })
+}
+
+func TestListUsers(t *testing.T) {
+ t.Run("normal", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ all, err := ListUsers("user1")
+ assert.NoError(t, err)
+ assert.True(t, len(all) > 0)
+ assert.Equal(t, all[0].Username, "user1")
+ })
+ t.Run("all users", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ all, err := ListUsers("")
+ assert.NoError(t, err)
+ assert.Len(t, all, 13)
+ })
+}
+
+func TestUserPasswordReset(t *testing.T) {
+ t.Run("normal", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ reset := &PasswordReset{
+ Token: "passwordresettesttoken",
+ NewPassword: "12345",
+ }
+ err := ResetPassword(reset)
+ assert.NoError(t, err)
+ })
+ t.Run("without password", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ reset := &PasswordReset{
+ Token: "passwordresettesttoken",
+ }
+ err := ResetPassword(reset)
+ assert.Error(t, err)
+ assert.True(t, IsErrNoUsernamePassword(err))
+ })
+ t.Run("empty token", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ reset := &PasswordReset{
+ Token: "somethingsomething",
+ NewPassword: "12345",
+ }
+ err := ResetPassword(reset)
+ assert.Error(t, err)
+ assert.True(t, IsErrInvalidPasswordResetToken(err))
+ })
+ t.Run("wrong token", func(t *testing.T) {
+ db.LoadAndAssertFixtures(t)
+ reset := &PasswordReset{
+ Token: "somethingsomething",
+ NewPassword: "12345",
+ }
+ err := ResetPassword(reset)
+ assert.Error(t, err)
+ assert.True(t, IsErrInvalidPasswordResetToken(err))
+ })
+}
diff --git a/pkg/user/users_list.go b/pkg/user/users_list.go
new file mode 100644
index 00000000..dd838aab
--- /dev/null
+++ b/pkg/user/users_list.go
@@ -0,0 +1,36 @@
+// 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 .
+
+package user
+
+// 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
+}