From 47d025cf07857e7724c2a6f7d5d59606a661a00d Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 21:51:05 +0100 Subject: [PATCH 01/19] Moved user related stuff to seperate package --- pkg/caldav/caldav.go | 4 +- pkg/integrations/integrations.go | 17 +- pkg/models/bulk_task_test.go | 9 +- pkg/models/error.go | 267 ---------------- pkg/models/label.go | 11 +- pkg/models/label_rights.go | 3 +- pkg/models/label_task.go | 9 +- pkg/models/label_task_test.go | 27 +- pkg/models/label_test.go | 49 +-- pkg/models/link_sharing.go | 9 +- pkg/models/list.go | 17 +- pkg/models/list_rights.go | 9 +- pkg/models/list_team_test.go | 3 +- pkg/models/list_test.go | 11 +- pkg/models/list_users.go | 15 +- pkg/models/list_users_rights_test.go | 7 +- pkg/models/list_users_test.go | 9 +- pkg/models/models.go | 3 +- pkg/models/namespace.go | 17 +- pkg/models/namespace_team_rights_test.go | 7 +- pkg/models/namespace_team_test.go | 5 +- pkg/models/namespace_test.go | 5 +- pkg/models/namespace_users.go | 11 +- pkg/models/namespace_users_rights_test.go | 7 +- pkg/models/namespace_users_test.go | 9 +- pkg/models/task_assignees.go | 25 +- pkg/models/task_attachment.go | 7 +- pkg/models/task_attachment_test.go | 7 +- pkg/models/task_collection.go | 3 +- pkg/models/task_collection_test.go | 19 +- pkg/models/task_relation.go | 3 +- pkg/models/task_relation_test.go | 23 +- pkg/models/tasks.go | 9 +- pkg/models/tasks_test.go | 5 +- pkg/models/team_members.go | 9 +- pkg/models/team_members_test.go | 3 +- pkg/models/teams.go | 9 +- pkg/models/teams_rights_test.go | 9 +- pkg/models/teams_test.go | 3 +- pkg/models/{users_list.go => user_list.go} | 36 +-- pkg/models/users_list_test.go | 50 ++- .../migration/create_from_structure.go | 3 +- pkg/modules/migration/handler/handler.go | 5 +- pkg/modules/migration/migration_status.go | 8 +- pkg/modules/migration/migrator.go | 6 +- .../migration/wunderlist/wunderlist.go | 3 +- pkg/routes/api/v1/auth.go | 5 +- pkg/routes/api/v1/list_by_namespace.go | 5 +- pkg/routes/api/v1/login.go | 7 +- pkg/routes/api/v1/task_attachment.go | 5 +- pkg/routes/api/v1/user_add_update.go | 12 +- pkg/routes/api/v1/user_confirm_email.go | 5 +- pkg/routes/api/v1/user_delete.go | 65 ---- pkg/routes/api/v1/user_list.go | 5 +- pkg/routes/api/v1/user_password_reset.go | 9 +- pkg/routes/api/v1/user_show.go | 6 +- pkg/routes/api/v1/user_update_password.go | 9 +- pkg/routes/caldav/handler.go | 7 +- pkg/routes/caldav/listStorageProvider.go | 3 +- pkg/routes/metrics.go | 3 +- pkg/routes/routes.go | 5 +- pkg/user/db.go | 50 +++ pkg/user/error.go | 291 ++++++++++++++++++ pkg/{models => user}/user.go | 42 +-- pkg/{models => user}/user_email_confirm.go | 13 +- .../user_email_confirm_test.go | 17 +- pkg/{models => user}/user_password_reset.go | 13 +- pkg/{models => user}/user_test.go | 22 +- pkg/user/users_list.go | 36 +++ 69 files changed, 755 insertions(+), 665 deletions(-) rename pkg/models/{users_list.go => user_list.go} (79%) delete mode 100644 pkg/routes/api/v1/user_delete.go create mode 100644 pkg/user/db.go create mode 100644 pkg/user/error.go rename pkg/{models => user}/user.go (90%) rename pkg/{models => user}/user_email_confirm.go (76%) rename pkg/{models => user}/user_email_confirm_test.go (78%) rename pkg/{models => user}/user_password_reset.go (88%) rename pkg/{models => user}/user_test.go (89%) create mode 100644 pkg/user/users_list.go diff --git a/pkg/caldav/caldav.go b/pkg/caldav/caldav.go index d988407ed..c6cc1f2fa 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/integrations/integrations.go b/pkg/integrations/integrations.go index 40bf50279..04656113a 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.", @@ -114,7 +115,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 +153,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 +186,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/models/bulk_task_test.go b/pkg/models/bulk_task_test.go index 289ba09cf..61bd1bf3e 100644 --- a/pkg/models/bulk_task_test.go +++ b/pkg/models/bulk_task_test.go @@ -1,6 +1,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "testing" ) @@ -9,7 +10,7 @@ func TestBulkTask_Update(t *testing.T) { IDs []int64 Tasks []*Task Task Task - User *User + User *user.User } tests := []struct { name string @@ -24,7 +25,7 @@ func TestBulkTask_Update(t *testing.T) { Task: Task{ Text: "bulkupdated", }, - User: &User{ID: 1}, + User: &user.User{ID: 1}, }, }, { @@ -34,7 +35,7 @@ func TestBulkTask_Update(t *testing.T) { Task: Task{ Text: "bulkupdated", }, - User: &User{ID: 1}, + User: &user.User{ID: 1}, }, wantForbidden: true, }, @@ -45,7 +46,7 @@ func TestBulkTask_Update(t *testing.T) { Task: Task{ Text: "bulkupdated", }, - User: &User{ID: 1}, + User: &user.User{ID: 1}, }, wantForbidden: true, }, diff --git a/pkg/models/error.go b/pkg/models/error.go index 0aa69d391..110a11980 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/label.go b/pkg/models/label.go index 9f226bafc..8e525cbc5 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 c7c6fe6fe..9c884defd 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 bb2f57f20..6c7faa476 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 5d619857f..08d716f95 100644 --- a/pkg/models/label_task_test.go +++ b/pkg/models/label_task_test.go @@ -1,6 +1,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "gopkg.in/d4l3k/messagediff.v1" "reflect" "runtime" @@ -37,7 +38,7 @@ func TestLabelTask_ReadAll(t *testing.T) { TaskID: 1, }, args: args{ - a: &User{ID: 1}, + a: &user.User{ID: 1}, }, wantLabels: []*labelWithTaskID{ { @@ -46,7 +47,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 +63,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 +74,7 @@ func TestLabelTask_ReadAll(t *testing.T) { TaskID: 9999, }, args: args{ - a: &User{ID: 1}, + a: &user.User{ID: 1}, }, wantErr: true, errType: IsErrTaskDoesNotExist, @@ -131,7 +132,7 @@ func TestLabelTask_Create(t *testing.T) { LabelID: 1, }, args: args{ - a: &User{ID: 1}, + a: &user.User{ID: 1}, }, }, { @@ -141,7 +142,7 @@ func TestLabelTask_Create(t *testing.T) { LabelID: 1, }, args: args{ - a: &User{ID: 1}, + a: &user.User{ID: 1}, }, wantErr: true, errType: IsErrLabelIsAlreadyOnTask, @@ -153,7 +154,7 @@ func TestLabelTask_Create(t *testing.T) { LabelID: 9999, }, args: args{ - a: &User{ID: 1}, + a: &user.User{ID: 1}, }, wantForbidden: true, }, @@ -164,7 +165,7 @@ func TestLabelTask_Create(t *testing.T) { LabelID: 1, }, args: args{ - a: &User{ID: 1}, + a: &user.User{ID: 1}, }, wantForbidden: true, wantErr: true, @@ -219,7 +220,7 @@ func TestLabelTask_Delete(t *testing.T) { TaskID: 1, LabelID: 1, }, - auth: &User{ID: 1}, + auth: &user.User{ID: 1}, }, { name: "delete nonexistant", @@ -227,7 +228,7 @@ func TestLabelTask_Delete(t *testing.T) { TaskID: 1, LabelID: 1, }, - auth: &User{ID: 1}, + auth: &user.User{ID: 1}, wantForbidden: true, }, { @@ -236,7 +237,7 @@ func TestLabelTask_Delete(t *testing.T) { TaskID: 1, LabelID: 9999, }, - auth: &User{ID: 1}, + auth: &user.User{ID: 1}, wantForbidden: true, }, { @@ -245,7 +246,7 @@ func TestLabelTask_Delete(t *testing.T) { TaskID: 9999, LabelID: 1, }, - auth: &User{ID: 1}, + auth: &user.User{ID: 1}, wantForbidden: true, }, { @@ -254,7 +255,7 @@ func TestLabelTask_Delete(t *testing.T) { TaskID: 14, LabelID: 1, }, - auth: &User{ID: 1}, + auth: &user.User{ID: 1}, wantForbidden: true, }, } diff --git a/pkg/models/label_test.go b/pkg/models/label_test.go index 96c2b61ee..92b7537f4 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 9012eee8c..115e3405c 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 0f3a47265..b18da771f 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 0a5eef8dd..d3f96c8c6 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 b6e9c68ba..891165883 100644 --- a/pkg/models/list_team_test.go +++ b/pkg/models/list_team_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "code.vikunja.io/web" "github.com/stretchr/testify/assert" "reflect" @@ -33,7 +34,7 @@ func TestTeamList(t *testing.T) { } // Dummyuser - u, err := GetUserByID(1) + u, err := user.GetUserByID(1) assert.NoError(t, err) // Check normal creation diff --git a/pkg/models/list_test.go b/pkg/models/list_test.go index 7431b5ed1..774432c11 100644 --- a/pkg/models/list_test.go +++ b/pkg/models/list_test.go @@ -17,13 +17,14 @@ package models import ( + user2 "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "reflect" "testing" ) func TestList_CreateOrUpdate(t *testing.T) { - user := &User{ + user := &user2.User{ ID: 1, Username: "user1", Email: "user1@example.com", @@ -54,7 +55,7 @@ func TestList_CreateOrUpdate(t *testing.T) { }) t.Run("nonexistant owner", func(t *testing.T) { initFixtures(t) - user := &User{ID: 9482385} + user := &user2.User{ID: 9482385} list := List{ Title: "test", Description: "Lorem Ipsum", @@ -133,12 +134,12 @@ func TestList_ReadAll(t *testing.T) { t.Run("all in namespace", func(t *testing.T) { initFixtures(t) // Get all lists for our namespace - lists, err := GetListsByNamespaceID(1, &User{}) + lists, err := GetListsByNamespaceID(1, &user2.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} + u := &user2.User{ID: 1} list := List{} lists3, _, _, err := list.ReadAll(u, "", 1, 50) @@ -148,7 +149,7 @@ 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} + user := &user2.User{ID: 999999} list := List{} _, _, _, err := list.ReadAll(user, "", 1, 50) assert.Error(t, err) diff --git a/pkg/models/list_users.go b/pkg/models/list_users.go index f2b5a7472..20564ef91 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 1fac26357..1660e39e8 100644 --- a/pkg/models/list_users_rights_test.go +++ b/pkg/models/list_users_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "testing" "code.vikunja.io/web" @@ -48,7 +49,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 +59,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,7 +69,7 @@ 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}, }, diff --git a/pkg/models/list_users_test.go b/pkg/models/list_users_test.go index 07daafafc..f5641d74b 100644 --- a/pkg/models/list_users_test.go +++ b/pkg/models/list_users_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "gopkg.in/d4l3k/messagediff.v1" "reflect" "runtime" @@ -155,11 +156,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 +170,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 +186,7 @@ func TestListUser_ReadAll(t *testing.T) { ListID: 3, }, args: args{ - a: &User{ID: 4}, + a: &user.User{ID: 4}, }, wantErr: true, errType: IsErrNeedToHaveListReadAccess, diff --git a/pkg/models/models.go b/pkg/models/models.go index 33275901d..4248f6a4f 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 932d0a704..7b68de052 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 09b3d7830..bbb3936f6 100644 --- a/pkg/models/namespace_team_rights_test.go +++ b/pkg/models/namespace_team_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "testing" "code.vikunja.io/web" @@ -48,7 +49,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 +59,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,7 +69,7 @@ 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}, }, diff --git a/pkg/models/namespace_team_test.go b/pkg/models/namespace_team_test.go index ef07cafc2..dc42e198b 100644 --- a/pkg/models/namespace_team_test.go +++ b/pkg/models/namespace_team_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "code.vikunja.io/web" "github.com/stretchr/testify/assert" "reflect" @@ -32,7 +33,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 +81,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)) diff --git a/pkg/models/namespace_test.go b/pkg/models/namespace_test.go index 81b4ef991..d998e93aa 100644 --- a/pkg/models/namespace_test.go +++ b/pkg/models/namespace_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "reflect" "testing" @@ -33,7 +34,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,7 +58,7 @@ 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) diff --git a/pkg/models/namespace_users.go b/pkg/models/namespace_users.go index b311b51fb..b6256316b 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 20de120f5..787bafb94 100644 --- a/pkg/models/namespace_users_rights_test.go +++ b/pkg/models/namespace_users_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "testing" "code.vikunja.io/web" @@ -48,7 +49,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 +59,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,7 +69,7 @@ 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}, }, diff --git a/pkg/models/namespace_users_test.go b/pkg/models/namespace_users_test.go index 4bcb49d9c..c640477fa 100644 --- a/pkg/models/namespace_users_test.go +++ b/pkg/models/namespace_users_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "code.vikunja.io/web" "gopkg.in/d4l3k/messagediff.v1" "reflect" @@ -152,11 +153,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 +167,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 +183,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) { NamespaceID: 3, }, args: args{ - a: &User{ID: 4}, + a: &user.User{ID: 4}, }, wantErr: true, errType: IsErrNeedToHaveNamespaceReadAccess, diff --git a/pkg/models/task_assignees.go b/pkg/models/task_assignees.go index b588a6497..2a59569ae 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 b62f89528..0ff9e9bfd 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 cdb863e9d..292405caf 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 73840c768..de19f6462 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 26807a6ce..3c7af31c6 100644 --- a/pkg/models/task_collection_test.go +++ b/pkg/models/task_collection_test.go @@ -19,6 +19,7 @@ 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" @@ -29,20 +30,20 @@ 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 +464,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { CreatedByID: 1, CreatedBy: user1, ListID: 1, - Assignees: []*User{ + Assignees: []*user.User{ user1, user2, }, @@ -538,7 +539,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 +586,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 +632,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 +649,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 +665,7 @@ func TestTaskCollection_ReadAll(t *testing.T) { }, args: args{ search: "", - a: &User{ID: 1}, + a: &user.User{ID: 1}, page: 0, }, want: []*Task{ diff --git a/pkg/models/task_relation.go b/pkg/models/task_relation.go index c11d99119..75b8b4fe1 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 52f6c4f4b..0ecf90f9d 100644 --- a/pkg/models/task_relation_test.go +++ b/pkg/models/task_relation_test.go @@ -18,6 +18,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" ) @@ -29,7 +30,7 @@ func TestTaskRelation_Create(t *testing.T) { 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) { @@ -38,7 +39,7 @@ func TestTaskRelation_Create(t *testing.T) { 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) { @@ -47,7 +48,7 @@ func TestTaskRelation_Create(t *testing.T) { 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)) }) @@ -56,7 +57,7 @@ func TestTaskRelation_Create(t *testing.T) { 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)) }) @@ -91,7 +92,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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) }) @@ -101,7 +102,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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) }) @@ -111,7 +112,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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) }) @@ -121,7 +122,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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) }) @@ -131,7 +132,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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) }) @@ -141,7 +142,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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) @@ -152,7 +153,7 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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 ee99e6eff..a6469c81b 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 2d40bf9e9..3e77908c3 100644 --- a/pkg/models/tasks_test.go +++ b/pkg/models/tasks_test.go @@ -17,12 +17,13 @@ package models import ( + user2 "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" ) func TestTask_Create(t *testing.T) { - user := &User{ + user := &user2.User{ ID: 1, Username: "user1", Email: "user1@example.com", @@ -70,7 +71,7 @@ func TestTask_Create(t *testing.T) { }) t.Run("noneixtant user", func(t *testing.T) { initFixtures(t) - nUser := &User{ID: 99999999} + nUser := &user2.User{ID: 99999999} task := &Task{ Text: "Test", Description: "Lorem Ipsum Dolor", diff --git a/pkg/models/team_members.go b/pkg/models/team_members.go index 39acedc93..9fb2f81f4 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 3d43ff39e..affac62aa 100644 --- a/pkg/models/team_members_test.go +++ b/pkg/models/team_members_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" ) @@ -30,7 +31,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 diff --git a/pkg/models/teams.go b/pkg/models/teams.go index db8a6d4df..b77047f7b 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 45ac3446d..e7a15c75d 100644 --- a/pkg/models/teams_rights_test.go +++ b/pkg/models/teams_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/user" "testing" "code.vikunja.io/web" @@ -28,7 +29,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 +51,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 +61,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,7 +71,7 @@ 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}, }, diff --git a/pkg/models/teams_test.go b/pkg/models/teams_test.go index 01d7360bf..e08f89a5b 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/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 c0aefe128..fb74f10d4 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 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/users_list_test.go b/pkg/models/users_list_test.go index 2512088d9..29ca70945 100644 --- a/pkg/models/users_list_test.go +++ b/pkg/models/users_list_test.go @@ -1,7 +1,25 @@ +// Copyright 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" + "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "gopkg.in/d4l3k/messagediff.v1" "testing" @@ -12,27 +30,27 @@ 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 +58,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 +66,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 +130,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 diff --git a/pkg/modules/migration/create_from_structure.go b/pkg/modules/migration/create_from_structure.go index 07164e642..7796715f3 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 805e93747..a86780248 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 4ec8bec88..e52093403 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 8ea27391a..059a2be51 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 3930146b2..1d9c6beed 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 ee7688e1e..17553179e 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 6287c1537..9bc5b54c3 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 2eeea4fe3..dbd324f55 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.UserLogin{} 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 4d189ed0b..d1d60355b 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 08aa4390a..42e5a0254 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 f5021ad01..f2e4a1a4f 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.UserEmailConfirm(&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 8940b22b4..000000000 --- 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 8ae333999..abfca4c46 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 62512c790..1dedbffd8 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.UserPasswordReset(&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 5cae05c5a..390a5879b 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 74c251e53..01692266b 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.UserLogin{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 afab35273..52d361607 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 88419892e..1d9f8663c 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 b960f6025..1f811abfb 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 fdb6705df..842fda091 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.UserLogin{ 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 000000000..a1f3b731e --- /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 000000000..66b701be9 --- /dev/null +++ b/pkg/user/error.go @@ -0,0 +1,291 @@ +// Copyright 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/models/user.go b/pkg/user/user.go similarity index 90% rename from pkg/models/user.go rename to pkg/user/user.go index e2c2e8108..94b38dff8 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. +// Copyright 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" @@ -76,7 +77,7 @@ func (User) TableName() string { return "users" } -func getUserWithError(a web.Auth) (*User, error) { +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)) @@ -273,13 +274,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 +355,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 76% rename from pkg/models/user_email_confirm.go rename to pkg/user/user_email_confirm.go index 216d89b71..8eb8550f9 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. +// Copyright 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 { diff --git a/pkg/models/user_email_confirm_test.go b/pkg/user/user_email_confirm_test.go similarity index 78% rename from pkg/models/user_email_confirm_test.go rename to pkg/user/user_email_confirm_test.go index e24018051..48be79bdc 100644 --- a/pkg/models/user_email_confirm_test.go +++ b/pkg/user/user_email_confirm_test.go @@ -1,22 +1,25 @@ -// Vikunja is a todo-list application to facilitate your life. -// Copyright 2018-2020 Vikunja and contributors. All rights reserved. +// Copyright 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 ( + "testing" +) func TestUserEmailConfirm(t *testing.T) { type args struct { diff --git a/pkg/models/user_password_reset.go b/pkg/user/user_password_reset.go similarity index 88% rename from pkg/models/user_password_reset.go rename to pkg/user/user_password_reset.go index f2d273bc9..6f9404902 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. +// Copyright 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" diff --git a/pkg/models/user_test.go b/pkg/user/user_test.go similarity index 89% rename from pkg/models/user_test.go rename to pkg/user/user_test.go index f400875c5..0e73c80ac 100644 --- a/pkg/models/user_test.go +++ b/pkg/user/user_test.go @@ -1,20 +1,21 @@ -// Vikunja is a todo-list application to facilitate your life. -// Copyright 2018-2020 Vikunja and contributors. All rights reserved. +// Copyright 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/utils" @@ -132,15 +133,6 @@ func TestCreateUser(t *testing.T) { 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) { diff --git a/pkg/user/users_list.go b/pkg/user/users_list.go new file mode 100644 index 000000000..20fdc7106 --- /dev/null +++ b/pkg/user/users_list.go @@ -0,0 +1,36 @@ +// Copyright 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 +} -- 2.40.1 From 9f0ced76ea1834ed8e3a7b9b3a96bc07d3f6f08d Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 22:42:16 +0100 Subject: [PATCH 02/19] Moved all fixtures to db package --- pkg/{files => db}/fixtures/files.yml | 0 pkg/{models => db}/fixtures/label_task.yml | 0 pkg/{models => db}/fixtures/labels.yml | 0 pkg/{models => db}/fixtures/link_sharing.yml | 0 pkg/{models => db}/fixtures/list.yml | 0 pkg/{models => db}/fixtures/namespaces.yml | 0 pkg/{models => db}/fixtures/task_assignees.yml | 0 pkg/{models => db}/fixtures/task_attachments.yml | 0 pkg/{models => db}/fixtures/task_relations.yml | 0 pkg/{models => db}/fixtures/task_reminders.yml | 0 pkg/{models => db}/fixtures/tasks.yml | 0 pkg/{models => db}/fixtures/team_list.yml | 0 pkg/{models => db}/fixtures/team_members.yml | 0 pkg/{models => db}/fixtures/team_namespaces.yml | 0 pkg/{models => db}/fixtures/teams.yml | 0 pkg/{models => db}/fixtures/users.yml | 0 pkg/{models => db}/fixtures/users_list.yml | 0 pkg/{models => db}/fixtures/users_namespace.yml | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename pkg/{files => db}/fixtures/files.yml (100%) rename pkg/{models => db}/fixtures/label_task.yml (100%) rename pkg/{models => db}/fixtures/labels.yml (100%) rename pkg/{models => db}/fixtures/link_sharing.yml (100%) rename pkg/{models => db}/fixtures/list.yml (100%) rename pkg/{models => db}/fixtures/namespaces.yml (100%) rename pkg/{models => db}/fixtures/task_assignees.yml (100%) rename pkg/{models => db}/fixtures/task_attachments.yml (100%) rename pkg/{models => db}/fixtures/task_relations.yml (100%) rename pkg/{models => db}/fixtures/task_reminders.yml (100%) rename pkg/{models => db}/fixtures/tasks.yml (100%) rename pkg/{models => db}/fixtures/team_list.yml (100%) rename pkg/{models => db}/fixtures/team_members.yml (100%) rename pkg/{models => db}/fixtures/team_namespaces.yml (100%) rename pkg/{models => db}/fixtures/teams.yml (100%) rename pkg/{models => db}/fixtures/users.yml (100%) rename pkg/{models => db}/fixtures/users_list.yml (100%) rename pkg/{models => db}/fixtures/users_namespace.yml (100%) 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 -- 2.40.1 From e7de0e80ed11dc8dfba8b2c99a8eaf31d4e7918f Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 22:42:34 +0100 Subject: [PATCH 03/19] Moved all fixtures to db package --- pkg/models/fixtures/files.yml | 1 - 1 file changed, 1 deletion(-) delete mode 120000 pkg/models/fixtures/files.yml diff --git a/pkg/models/fixtures/files.yml b/pkg/models/fixtures/files.yml deleted file mode 120000 index aa8894413..000000000 --- a/pkg/models/fixtures/files.yml +++ /dev/null @@ -1 +0,0 @@ -../../files/fixtures/files.yml \ No newline at end of file -- 2.40.1 From 1c1632ec9938621102b7c489d33c9789c3a9d394 Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 22:43:07 +0100 Subject: [PATCH 04/19] Better handling of creating test enging --- pkg/db/db.go | 28 ---------- pkg/db/test.go | 88 ++++++++++++++++++++++++++++++++ pkg/files/filehandling.go | 14 +---- pkg/integrations/integrations.go | 2 +- pkg/migration/migration.go | 4 ++ pkg/models/main_test.go | 2 +- 6 files changed, 95 insertions(+), 43 deletions(-) create mode 100644 pkg/db/test.go diff --git a/pkg/db/db.go b/pkg/db/db.go index b65dc6809..4d9a46ef2 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/db/test.go b/pkg/db/test.go new file mode 100644 index 000000000..e29c7965f --- /dev/null +++ b/pkg/db/test.go @@ -0,0 +1,88 @@ +// Copyright 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" + "gopkg.in/testfixtures.v2" + "os" + "path/filepath" +) + +// 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 +} + +func InitTestFixtures() (err error) { + // Create the db schema + // migration.Migrate(x) + + // 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 + var fixturesHelper testfixtures.Helper = &testfixtures.SQLite{} + if config.DatabaseType.GetString() == "mysql" { + fixturesHelper = &testfixtures.MySQL{} + } + fixturesDir := filepath.Join(config.ServiceRootpath.GetString(), "pkg", "db", "fixtures") + err = InitFixtures(fixturesHelper, fixturesDir) + if err != nil { + log.Fatal(err) + } + + return nil +} + +func InitTestDB() (x *xorm.Engine, err error) { + x, err = CreateTestEngine() + if err != nil { + return + } + + err = InitTestFixtures() + return x, err +} diff --git a/pkg/files/filehandling.go b/pkg/files/filehandling.go index 53c12e9e8..9baa0c823 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" ) @@ -73,17 +71,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() if err != nil { log.Fatal(err) } diff --git a/pkg/integrations/integrations.go b/pkg/integrations/integrations.go index 04656113a..198effd4e 100644 --- a/pkg/integrations/integrations.go +++ b/pkg/integrations/integrations.go @@ -82,7 +82,7 @@ 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()) + models.SetupTests() err = db.LoadFixtures() if err != nil { diff --git a/pkg/migration/migration.go b/pkg/migration/migration.go index 0d7bbfeb0..b55390a80 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/main_test.go b/pkg/models/main_test.go index 7c1911aa5..86421ee0e 100644 --- a/pkg/models/main_test.go +++ b/pkg/models/main_test.go @@ -33,7 +33,7 @@ func TestMain(m *testing.M) { // Some tests use the file engine, so we'll need to initialize that files.InitTests() - SetupTests(config.ServiceRootpath.GetString()) + SetupTests() os.Exit(m.Run()) } -- 2.40.1 From 2cf1e7194537f7c60aecc11387ab97767655b857 Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 22:43:28 +0100 Subject: [PATCH 05/19] Fix user related tests --- pkg/cmd/cmd.go | 5 +++ pkg/models/list_test.go | 28 +++++++------- pkg/models/list_users_test.go | 4 +- pkg/models/namespace_test.go | 4 +- pkg/models/namespace_users_test.go | 4 +- pkg/models/tasks_test.go | 16 ++++---- pkg/models/team_members_test.go | 2 +- pkg/models/unit_tests.go | 62 +++++++----------------------- 8 files changed, 48 insertions(+), 77 deletions(-) diff --git a/pkg/cmd/cmd.go b/pkg/cmd/cmd.go index 62d70f8ad..d2c1b3859 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/models/list_test.go b/pkg/models/list_test.go index 774432c11..7ad7e9b72 100644 --- a/pkg/models/list_test.go +++ b/pkg/models/list_test.go @@ -17,14 +17,14 @@ package models import ( - user2 "code.vikunja.io/api/pkg/user" + "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "reflect" "testing" ) func TestList_CreateOrUpdate(t *testing.T) { - user := &user2.User{ + usr := &user.User{ ID: 1, Username: "user1", Email: "user1@example.com", @@ -38,7 +38,7 @@ func TestList_CreateOrUpdate(t *testing.T) { 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) { @@ -49,21 +49,21 @@ func TestList_CreateOrUpdate(t *testing.T) { 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 := &user2.User{ID: 9482385} + 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) @@ -74,7 +74,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)) }) @@ -114,7 +114,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)) }) @@ -134,12 +134,12 @@ func TestList_ReadAll(t *testing.T) { t.Run("all in namespace", func(t *testing.T) { initFixtures(t) // Get all lists for our namespace - lists, err := GetListsByNamespaceID(1, &user2.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 := &user2.User{ID: 1} + u := &user.User{ID: 1} list := List{} lists3, _, _, err := list.ReadAll(u, "", 1, 50) @@ -149,10 +149,10 @@ func TestList_ReadAll(t *testing.T) { assert.Equal(t, 16, s.Len()) }) t.Run("lists for nonexistant user", func(t *testing.T) { - user := &user2.User{ID: 999999} + 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_test.go b/pkg/models/list_users_test.go index f5641d74b..ae3311de7 100644 --- a/pkg/models/list_users_test.go +++ b/pkg/models/list_users_test.go @@ -90,7 +90,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", @@ -317,7 +317,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", diff --git a/pkg/models/namespace_test.go b/pkg/models/namespace_test.go index d998e93aa..24d3ca51d 100644 --- a/pkg/models/namespace_test.go +++ b/pkg/models/namespace_test.go @@ -62,7 +62,7 @@ func TestNamespace_Create(t *testing.T) { 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) @@ -86,7 +86,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_test.go b/pkg/models/namespace_users_test.go index c640477fa..1f02d9e01 100644 --- a/pkg/models/namespace_users_test.go +++ b/pkg/models/namespace_users_test.go @@ -88,7 +88,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", @@ -315,7 +315,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", diff --git a/pkg/models/tasks_test.go b/pkg/models/tasks_test.go index 3e77908c3..f80f90560 100644 --- a/pkg/models/tasks_test.go +++ b/pkg/models/tasks_test.go @@ -17,13 +17,13 @@ package models import ( - user2 "code.vikunja.io/api/pkg/user" + user "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" ) func TestTask_Create(t *testing.T) { - user := &user2.User{ + usr := &user.User{ ID: 1, Username: "user1", Email: "user1@example.com", @@ -38,7 +38,7 @@ func TestTask_Create(t *testing.T) { 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) @@ -54,7 +54,7 @@ func TestTask_Create(t *testing.T) { Description: "Lorem Ipsum Dolor", ListID: 1, } - err := task.Create(user) + err := task.Create(usr) assert.Error(t, err) assert.True(t, IsErrTaskCannotBeEmpty(err)) }) @@ -65,13 +65,13 @@ func TestTask_Create(t *testing.T) { 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) { + t.Run("noneixtant usr", func(t *testing.T) { initFixtures(t) - nUser := &user2.User{ID: 99999999} + nUser := &user.User{ID: 99999999} task := &Task{ Text: "Test", Description: "Lorem Ipsum Dolor", @@ -79,7 +79,7 @@ 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)) }) } diff --git a/pkg/models/team_members_test.go b/pkg/models/team_members_test.go index affac62aa..85d534907 100644 --- a/pkg/models/team_members_test.go +++ b/pkg/models/team_members_test.go @@ -72,7 +72,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/unit_tests.go b/pkg/models/unit_tests.go index 84fa09790..e00d9c8e6 100644 --- a/pkg/models/unit_tests.go +++ b/pkg/models/unit_tests.go @@ -17,27 +17,31 @@ 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() + if err != nil { + log.Fatal(err) } // Start the pseudo mail queue @@ -49,44 +53,6 @@ func SetupTests(pathToRoot string) { } } -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() -- 2.40.1 From f3a294237fa0ea19506a08d97b43b1e31157fc8d Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 22:47:20 +0100 Subject: [PATCH 06/19] Fix init of test engine creation --- go.mod | 1 - pkg/integrations/integrations.go | 1 + pkg/models/main_test.go | 3 +++ pkg/models/tasks_test.go | 2 +- pkg/user/main_test.go | 29 ++++++++++++++++++++++ pkg/user/test.go | 42 ++++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 pkg/user/main_test.go create mode 100644 pkg/user/test.go diff --git a/go.mod b/go.mod index 2b3043919..b1a8ffc57 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/integrations/integrations.go b/pkg/integrations/integrations.go index 198effd4e..008271e3b 100644 --- a/pkg/integrations/integrations.go +++ b/pkg/integrations/integrations.go @@ -82,6 +82,7 @@ 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() + user.InitTests() models.SetupTests() err = db.LoadFixtures() diff --git a/pkg/models/main_test.go b/pkg/models/main_test.go index 86421ee0e..c3c912f63 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,6 +34,8 @@ func TestMain(m *testing.M) { // Some tests use the file engine, so we'll need to initialize that files.InitTests() + user.InitTests() + SetupTests() os.Exit(m.Run()) diff --git a/pkg/models/tasks_test.go b/pkg/models/tasks_test.go index f80f90560..33ebea94b 100644 --- a/pkg/models/tasks_test.go +++ b/pkg/models/tasks_test.go @@ -17,7 +17,7 @@ package models import ( - user "code.vikunja.io/api/pkg/user" + "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" ) diff --git a/pkg/user/main_test.go b/pkg/user/main_test.go new file mode 100644 index 000000000..57a0e9211 --- /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 000000000..a3c5e7e36 --- /dev/null +++ b/pkg/user/test.go @@ -0,0 +1,42 @@ +// Copyright 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() + if err != nil { + log.Fatal(err) + } +} -- 2.40.1 From b2bdfce365ff412680b3415e64e14574620c1154 Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 22:53:18 +0100 Subject: [PATCH 07/19] Fix integration tests --- pkg/integrations/login_test.go | 10 +++++----- pkg/integrations/register_test.go | 14 +++++++------- pkg/integrations/user_change_password_test.go | 8 ++++---- pkg/integrations/user_confirm_email_test.go | 8 ++++---- .../user_password_request_token_test.go | 6 +++--- pkg/integrations/user_password_reset_test.go | 6 +++--- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/pkg/integrations/login_test.go b/pkg/integrations/login_test.go index 546e0270c..e6ad21810 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 34b28de03..3ce59a083 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 5d639e29e..e9afdc5ef 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 9e439af2d..35bd769f5 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 e171d7b8b..12f1f72cd 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 50e09c899..28867b218 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) }) } -- 2.40.1 From be733b5b0d7b935f710bbf90ab9ab1ba05f8c489 Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 23:04:43 +0100 Subject: [PATCH 08/19] Fix lint --- pkg/db/test.go | 14 +------------- pkg/routes/api/v1/login.go | 2 +- pkg/routes/api/v1/user_confirm_email.go | 2 +- pkg/routes/api/v1/user_password_reset.go | 2 +- pkg/routes/api/v1/user_update_password.go | 2 +- pkg/routes/routes.go | 2 +- pkg/user/user.go | 8 +++++--- pkg/user/user_email_confirm.go | 4 ++-- pkg/user/user_email_confirm_test.go | 4 ++-- pkg/user/user_password_reset.go | 4 ++-- pkg/user/user_test.go | 16 ++++++++-------- 11 files changed, 25 insertions(+), 35 deletions(-) diff --git a/pkg/db/test.go b/pkg/db/test.go index e29c7965f..d0849de1e 100644 --- a/pkg/db/test.go +++ b/pkg/db/test.go @@ -54,10 +54,8 @@ func CreateTestEngine() (engine *xorm.Engine, err error) { return } +// InitTestFixtures populates the db with all fixtures from the fixtures folder func InitTestFixtures() (err error) { - // Create the db schema - // migration.Migrate(x) - // 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 @@ -76,13 +74,3 @@ func InitTestFixtures() (err error) { return nil } - -func InitTestDB() (x *xorm.Engine, err error) { - x, err = CreateTestEngine() - if err != nil { - return - } - - err = InitTestFixtures() - return x, err -} diff --git a/pkg/routes/api/v1/login.go b/pkg/routes/api/v1/login.go index dbd324f55..e92bad3b2 100644 --- a/pkg/routes/api/v1/login.go +++ b/pkg/routes/api/v1/login.go @@ -42,7 +42,7 @@ type Token struct { // @Failure 403 {object} models.Message "Invalid username or password." // @Router /login [post] func Login(c echo.Context) error { - u := user2.UserLogin{} + u := user2.Login{} if err := c.Bind(&u); err != nil { return c.JSON(http.StatusBadRequest, models.Message{"Please provide a username and password."}) } diff --git a/pkg/routes/api/v1/user_confirm_email.go b/pkg/routes/api/v1/user_confirm_email.go index f2e4a1a4f..66b4e2ddd 100644 --- a/pkg/routes/api/v1/user_confirm_email.go +++ b/pkg/routes/api/v1/user_confirm_email.go @@ -42,7 +42,7 @@ func UserConfirmEmail(c echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, "No token provided.") } - err := user.UserEmailConfirm(&emailConfirm) + err := user.ConfirmEmail(&emailConfirm) 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 1dedbffd8..4b2bb6d8b 100644 --- a/pkg/routes/api/v1/user_password_reset.go +++ b/pkg/routes/api/v1/user_password_reset.go @@ -42,7 +42,7 @@ func UserResetPassword(c echo.Context) error { return echo.NewHTTPError(http.StatusBadRequest, "No password provided.") } - err := user.UserPasswordReset(&pwReset) + err := user.ResetPassword(&pwReset) 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 01692266b..4c775eb06 100644 --- a/pkg/routes/api/v1/user_update_password.go +++ b/pkg/routes/api/v1/user_update_password.go @@ -61,7 +61,7 @@ func UserChangePassword(c echo.Context) error { } // Check the current password - if _, err = user.CheckUserCredentials(&user.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) } diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go index 842fda091..6facec419 100644 --- a/pkg/routes/routes.go +++ b/pkg/routes/routes.go @@ -408,7 +408,7 @@ func registerCalDavRoutes(c *echo.Group) { } func caldavBasicAuth(username, password string, c echo.Context) (bool, error) { - creds := &user.UserLogin{ + creds := &user.Login{ Username: username, Password: password, } diff --git a/pkg/user/user.go b/pkg/user/user.go index 94b38dff8..c214a50e6 100644 --- a/pkg/user/user.go +++ b/pkg/user/user.go @@ -30,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. @@ -77,6 +77,8 @@ func (User) TableName() string { return "users" } +// 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 { @@ -154,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{} diff --git a/pkg/user/user_email_confirm.go b/pkg/user/user_email_confirm.go index 8eb8550f9..5e3a136cd 100644 --- a/pkg/user/user_email_confirm.go +++ b/pkg/user/user_email_confirm.go @@ -23,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/user/user_email_confirm_test.go b/pkg/user/user_email_confirm_test.go index 48be79bdc..e52825882 100644 --- a/pkg/user/user_email_confirm_test.go +++ b/pkg/user/user_email_confirm_test.go @@ -62,8 +62,8 @@ 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) + if err := ConfirmEmail(tt.args.c); (err != nil) != tt.wantErr { + t.Errorf("ConfirmEmail() error = %v, wantErr %v", err, tt.wantErr) } }) } diff --git a/pkg/user/user_password_reset.go b/pkg/user/user_password_reset.go index 6f9404902..4f5809bd8 100644 --- a/pkg/user/user_password_reset.go +++ b/pkg/user/user_password_reset.go @@ -31,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 index 0e73c80ac..940ab1ee8 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -79,24 +79,24 @@ func TestCreateUser(t *testing.T) { assert.True(t, IsErrUserDoesNotExist(err)) // Check the user credentials with an unverified email - _, err = CheckUserCredentials(&UserLogin{"user5", "1234"}) + _, err = CheckUserCredentials(&Login{"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"}) + user, err := CheckUserCredentials(&Login{"testuu", "1234"}) assert.NoError(t, err) assert.Equal(t, "testuu", user.Username) // Check wrong password (should also fail) - _, err = CheckUserCredentials(&UserLogin{"testuu", "12345"}) + _, err = CheckUserCredentials(&Login{"testuu", "12345"}) assert.Error(t, err) assert.True(t, IsErrWrongUsernameOrPassword(err)) // Check usercredentials for a nonexistent user (should fail) - _, err = CheckUserCredentials(&UserLogin{"dfstestuu", "1234"}) + _, err = CheckUserCredentials(&Login{"dfstestuu", "1234"}) assert.Error(t, err) assert.True(t, IsErrWrongUsernameOrPassword(err)) @@ -117,7 +117,7 @@ func TestCreateUser(t *testing.T) { assert.NoError(t, err) // Check if it was changed - _, err = CheckUserCredentials(&UserLogin{theuser.Username, newpassword}) + _, err = CheckUserCredentials(&Login{theuser.Username, newpassword}) assert.NoError(t, err) // Check if the searchterm works @@ -154,17 +154,17 @@ func TestUserPasswordReset(t *testing.T) { // Try resetting it without a password reset.NewPassword = "" - err = UserPasswordReset(reset) + err = ResetPassword(reset) assert.True(t, IsErrNoUsernamePassword(err)) // Reset it reset.NewPassword = "1234" - err = UserPasswordReset(reset) + err = ResetPassword(reset) assert.NoError(t, err) // Try resetting it with a wrong token reset.Token = utils.MakeRandomString(400) - err = UserPasswordReset(reset) + err = ResetPassword(reset) assert.Error(t, err) assert.True(t, IsErrInvalidPasswordResetToken(err)) } -- 2.40.1 From 7da3ac6ca39e975dbe8ef87641c896a210695503 Mon Sep 17 00:00:00 2001 From: kolaente Date: Fri, 24 Jan 2020 23:05:42 +0100 Subject: [PATCH 09/19] Fix ineffasign --- pkg/user/user_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go index 940ab1ee8..f0e3e29f1 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -27,10 +27,6 @@ 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", -- 2.40.1 From da8ad96610bf41cd681931d771bbceb8be35cbc3 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 13:28:46 +0100 Subject: [PATCH 10/19] Fix loading fixtures --- pkg/db/test.go | 11 ++--------- pkg/db/test_fixtures.go | 23 +++++++++++++++++++++-- pkg/files/filehandling.go | 2 +- pkg/models/unit_tests.go | 19 ++++++++++++++++++- pkg/user/test.go | 2 +- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/pkg/db/test.go b/pkg/db/test.go index d0849de1e..0820b1cdd 100644 --- a/pkg/db/test.go +++ b/pkg/db/test.go @@ -22,9 +22,7 @@ import ( "code.vikunja.io/api/pkg/log" "github.com/go-xorm/core" "github.com/go-xorm/xorm" - "gopkg.in/testfixtures.v2" "os" - "path/filepath" ) // CreateTestEngine creates an instance of the db engine which lives in memory @@ -55,19 +53,14 @@ func CreateTestEngine() (engine *xorm.Engine, err error) { } // InitTestFixtures populates the db with all fixtures from the fixtures folder -func InitTestFixtures() (err error) { +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 - var fixturesHelper testfixtures.Helper = &testfixtures.SQLite{} - if config.DatabaseType.GetString() == "mysql" { - fixturesHelper = &testfixtures.MySQL{} - } - fixturesDir := filepath.Join(config.ServiceRootpath.GetString(), "pkg", "db", "fixtures") - err = InitFixtures(fixturesHelper, fixturesDir) + err = InitFixtures(tablenames...) if err != nil { log.Fatal(err) } diff --git a/pkg/db/test_fixtures.go b/pkg/db/test_fixtures.go index 3ad9708b4..c39a24627 100644 --- a/pkg/db/test_fixtures.go +++ b/pkg/db/test_fixtures.go @@ -18,15 +18,34 @@ package db import ( + "code.vikunja.io/api/pkg/config" "gopkg.in/testfixtures.v2" + "path/filepath" ) 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 } diff --git a/pkg/files/filehandling.go b/pkg/files/filehandling.go index 9baa0c823..2a8da4d54 100644 --- a/pkg/files/filehandling.go +++ b/pkg/files/filehandling.go @@ -71,7 +71,7 @@ func InitTests() { log.Fatal(err) } - err = db.InitTestFixtures() + err = db.InitTestFixtures("files") if err != nil { log.Fatal(err) } diff --git a/pkg/models/unit_tests.go b/pkg/models/unit_tests.go index e00d9c8e6..d673b9aae 100644 --- a/pkg/models/unit_tests.go +++ b/pkg/models/unit_tests.go @@ -39,7 +39,24 @@ func SetupTests() { log.Fatal(err) } - err = db.InitTestFixtures() + err = db.InitTestFixtures( + "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) } diff --git a/pkg/user/test.go b/pkg/user/test.go index a3c5e7e36..fe921b6d7 100644 --- a/pkg/user/test.go +++ b/pkg/user/test.go @@ -35,7 +35,7 @@ func InitTests() { log.Fatal(err) } - err = db.InitTestFixtures() + err = db.InitTestFixtures("users") if err != nil { log.Fatal(err) } -- 2.40.1 From bab91b4fbcd3f3739fe47ebdbaef15317f867949 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 13:30:23 +0100 Subject: [PATCH 11/19] Fix models test --- pkg/models/unit_tests.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/models/unit_tests.go b/pkg/models/unit_tests.go index d673b9aae..4fa10ae38 100644 --- a/pkg/models/unit_tests.go +++ b/pkg/models/unit_tests.go @@ -40,6 +40,7 @@ func SetupTests() { } err = db.InitTestFixtures( + "files", "label_task", "labels", "link_sharing", -- 2.40.1 From 6c88b4ecc98dafd9a76e7d6353a24bb6da3ca5a2 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 13:56:25 +0100 Subject: [PATCH 12/19] Fix db fixtures init in tests --- pkg/db/test_fixtures.go | 7 ++++++ pkg/files/filehandling.go | 7 +++--- pkg/models/bulk_task_test.go | 3 +++ pkg/models/label_task_test.go | 11 +++++++-- pkg/models/list_team_test.go | 5 +++++ pkg/models/list_test.go | 23 +++++++++++-------- pkg/models/list_users_rights_test.go | 3 +++ pkg/models/list_users_test.go | 11 ++++++++- pkg/models/namespace_team_rights_test.go | 3 +++ pkg/models/namespace_team_test.go | 5 +++++ pkg/models/namespace_test.go | 3 +++ pkg/models/namespace_users_rights_test.go | 3 +++ pkg/models/namespace_users_test.go | 11 ++++++++- pkg/models/task_collection_test.go | 5 ++--- pkg/models/task_relation_test.go | 27 +++++++++++++++++++++++ pkg/models/tasks_test.go | 23 ++++++++++--------- pkg/models/team_members_test.go | 2 ++ pkg/models/teams_rights_test.go | 3 +++ pkg/models/unit_tests.go | 13 ----------- pkg/models/users_list_test.go | 7 ++---- pkg/user/user_email_confirm_test.go | 4 ++++ pkg/user/user_test.go | 8 +++++-- 22 files changed, 137 insertions(+), 50 deletions(-) diff --git a/pkg/db/test_fixtures.go b/pkg/db/test_fixtures.go index c39a24627..d6bdaf435 100644 --- a/pkg/db/test_fixtures.go +++ b/pkg/db/test_fixtures.go @@ -19,8 +19,10 @@ 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 @@ -53,3 +55,8 @@ func InitFixtures(tablenames ...string) (err error) { func LoadFixtures() error { return fixtures.Load() } + +func LoadAndAssertFixtures(t *testing.T) { + err := LoadFixtures() + assert.NoError(t, err) +} diff --git a/pkg/files/filehandling.go b/pkg/files/filehandling.go index 2a8da4d54..3540b26e5 100644 --- a/pkg/files/filehandling.go +++ b/pkg/files/filehandling.go @@ -43,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) } diff --git a/pkg/models/bulk_task_test.go b/pkg/models/bulk_task_test.go index 61bd1bf3e..39aa9f846 100644 --- a/pkg/models/bulk_task_test.go +++ b/pkg/models/bulk_task_test.go @@ -1,6 +1,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "testing" ) @@ -53,6 +54,8 @@ func TestBulkTask_Update(t *testing.T) { } 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/label_task_test.go b/pkg/models/label_task_test.go index 08d716f95..cd497e859 100644 --- a/pkg/models/label_task_test.go +++ b/pkg/models/label_task_test.go @@ -1,6 +1,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "gopkg.in/d4l3k/messagediff.v1" "reflect" @@ -82,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, @@ -139,7 +142,7 @@ func TestLabelTask_Create(t *testing.T) { name: "already existing", fields: fields{ TaskID: 1, - LabelID: 1, + LabelID: 4, }, args: args{ a: &user.User{ID: 1}, @@ -174,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, @@ -218,7 +223,7 @@ func TestLabelTask_Delete(t *testing.T) { name: "normal", fields: fields{ TaskID: 1, - LabelID: 1, + LabelID: 4, }, auth: &user.User{ID: 1}, }, @@ -261,6 +266,8 @@ func TestLabelTask_Delete(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, diff --git a/pkg/models/list_team_test.go b/pkg/models/list_team_test.go index 891165883..984c70694 100644 --- a/pkg/models/list_team_test.go +++ b/pkg/models/list_team_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "code.vikunja.io/web" "github.com/stretchr/testify/assert" @@ -26,6 +27,8 @@ import ( ) func TestTeamList(t *testing.T) { + db.LoadAndAssertFixtures(t) + // Dummy relation tl := TeamList{ TeamID: 1, @@ -165,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 7ad7e9b72..0c88428f2 100644 --- a/pkg/models/list_test.go +++ b/pkg/models/list_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "reflect" @@ -32,7 +33,7 @@ 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", @@ -42,7 +43,7 @@ func TestList_CreateOrUpdate(t *testing.T) { assert.NoError(t, err) }) t.Run("nonexistant namespace", func(t *testing.T) { - initFixtures(t) + db.LoadAndAssertFixtures(t) list := List{ Title: "test", Description: "Lorem Ipsum", @@ -54,7 +55,7 @@ func TestList_CreateOrUpdate(t *testing.T) { assert.True(t, IsErrNamespaceDoesNotExist(err)) }) t.Run("nonexistant owner", func(t *testing.T) { - initFixtures(t) + db.LoadAndAssertFixtures(t) usr := &user.User{ID: 9482385} list := List{ Title: "test", @@ -66,7 +67,7 @@ func TestList_CreateOrUpdate(t *testing.T) { 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", @@ -82,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", @@ -95,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", @@ -106,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", @@ -122,7 +123,7 @@ func TestList_CreateOrUpdate(t *testing.T) { } func TestList_Delete(t *testing.T) { - initFixtures(t) + db.LoadAndAssertFixtures(t) list := List{ ID: 1, } @@ -132,13 +133,15 @@ 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.User{}) assert.NoError(t, err) assert.Equal(t, len(lists), 2) }) t.Run("all lists for user", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + u := &user.User{ID: 1} list := List{} lists3, _, _, err := list.ReadAll(u, "", 1, 50) @@ -149,6 +152,8 @@ func TestList_ReadAll(t *testing.T) { assert.Equal(t, 16, s.Len()) }) t.Run("lists for nonexistant user", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + usr := &user.User{ID: 999999} list := List{} _, _, _, err := list.ReadAll(usr, "", 1, 50) diff --git a/pkg/models/list_users_rights_test.go b/pkg/models/list_users_rights_test.go index 1660e39e8..1ba105fe7 100644 --- a/pkg/models/list_users_rights_test.go +++ b/pkg/models/list_users_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "testing" @@ -76,6 +77,8 @@ func TestListUser_CanDoSomething(t *testing.T) { } 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 ae3311de7..ab3c61db8 100644 --- a/pkg/models/list_users_test.go +++ b/pkg/models/list_users_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "gopkg.in/d4l3k/messagediff.v1" "reflect" @@ -59,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, @@ -104,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, @@ -194,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, @@ -272,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, @@ -338,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/namespace_team_rights_test.go b/pkg/models/namespace_team_rights_test.go index bbb3936f6..1634445a1 100644 --- a/pkg/models/namespace_team_rights_test.go +++ b/pkg/models/namespace_team_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "testing" @@ -76,6 +77,8 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) { } 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 dc42e198b..a97ab9f1b 100644 --- a/pkg/models/namespace_team_test.go +++ b/pkg/models/namespace_team_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "code.vikunja.io/web" "github.com/stretchr/testify/assert" @@ -26,6 +27,8 @@ import ( ) func TestTeamNamespace(t *testing.T) { + db.LoadAndAssertFixtures(t) + // Dummy team <-> namespace relation tn := TeamNamespace{ TeamID: 1, @@ -157,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 24d3ca51d..d510a7686 100644 --- a/pkg/models/namespace_test.go +++ b/pkg/models/namespace_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "reflect" @@ -24,6 +25,8 @@ import ( ) func TestNamespace_Create(t *testing.T) { + db.LoadAndAssertFixtures(t) + // Create test database //assert.NoError(t, LoadFixtures()) diff --git a/pkg/models/namespace_users_rights_test.go b/pkg/models/namespace_users_rights_test.go index 787bafb94..b48586c3c 100644 --- a/pkg/models/namespace_users_rights_test.go +++ b/pkg/models/namespace_users_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "testing" @@ -76,6 +77,8 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) { } 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 1f02d9e01..0fc7fd8f6 100644 --- a/pkg/models/namespace_users_test.go +++ b/pkg/models/namespace_users_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "code.vikunja.io/web" "gopkg.in/d4l3k/messagediff.v1" @@ -57,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, @@ -102,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, @@ -191,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, @@ -270,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, @@ -336,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_collection_test.go b/pkg/models/task_collection_test.go index 3c7af31c6..d3b440b66 100644 --- a/pkg/models/task_collection_test.go +++ b/pkg/models/task_collection_test.go @@ -21,14 +21,11 @@ import ( "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.User{ ID: 1, @@ -678,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_test.go b/pkg/models/task_relation_test.go index 0ecf90f9d..b804f0e35 100644 --- a/pkg/models/task_relation_test.go +++ b/pkg/models/task_relation_test.go @@ -18,6 +18,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" @@ -25,6 +26,8 @@ import ( func TestTaskRelation_Create(t *testing.T) { t.Run("Normal", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 1, OtherTaskID: 2, @@ -34,6 +37,8 @@ func TestTaskRelation_Create(t *testing.T) { assert.NoError(t, err) }) t.Run("Two Tasks In Different Lists", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 1, OtherTaskID: 13, @@ -43,6 +48,8 @@ func TestTaskRelation_Create(t *testing.T) { assert.NoError(t, err) }) t.Run("Already Existing", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 1, OtherTaskID: 29, @@ -53,6 +60,8 @@ func TestTaskRelation_Create(t *testing.T) { assert.True(t, IsErrRelationAlreadyExists(err)) }) t.Run("Same Task", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 1, OtherTaskID: 1, @@ -65,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, @@ -74,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, @@ -87,6 +100,8 @@ 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, @@ -97,6 +112,8 @@ func TestTaskRelation_CanCreate(t *testing.T) { assert.True(t, can) }) t.Run("Two tasks on different lists", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 1, OtherTaskID: 13, @@ -107,6 +124,8 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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, @@ -117,6 +136,8 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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, @@ -127,6 +148,8 @@ func TestTaskRelation_CanCreate(t *testing.T) { 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, @@ -137,6 +160,8 @@ func TestTaskRelation_CanCreate(t *testing.T) { assert.False(t, can) }) t.Run("Nonexisting base task", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 999999, OtherTaskID: 1, @@ -148,6 +173,8 @@ func TestTaskRelation_CanCreate(t *testing.T) { assert.False(t, can) }) t.Run("Nonexisting other task", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + rel := TaskRelation{ TaskID: 1, OtherTaskID: 999999, diff --git a/pkg/models/tasks_test.go b/pkg/models/tasks_test.go index 33ebea94b..af6ba5401 100644 --- a/pkg/models/tasks_test.go +++ b/pkg/models/tasks_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" @@ -32,7 +33,7 @@ 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", @@ -48,7 +49,7 @@ 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", @@ -59,7 +60,7 @@ func TestTask_Create(t *testing.T) { 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", @@ -69,8 +70,8 @@ func TestTask_Create(t *testing.T) { assert.Error(t, err) assert.True(t, IsErrListDoesNotExist(err)) }) - t.Run("noneixtant usr", func(t *testing.T) { - initFixtures(t) + t.Run("noneixtant user", func(t *testing.T) { + db.LoadAndAssertFixtures(t) nUser := &user.User{ID: 99999999} task := &Task{ Text: "Test", @@ -85,7 +86,7 @@ func TestTask_Create(t *testing.T) { func TestTask_Update(t *testing.T) { t.Run("normal", func(t *testing.T) { - initFixtures(t) + db.LoadAndAssertFixtures(t) task := &Task{ ID: 1, Text: "test10000", @@ -96,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", @@ -111,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, } @@ -122,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) @@ -137,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_test.go b/pkg/models/team_members_test.go index 85d534907..4f9a4a304 100644 --- a/pkg/models/team_members_test.go +++ b/pkg/models/team_members_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 TestTeamMember_Create(t *testing.T) { + db.LoadAndAssertFixtures(t) // Dummy team member dummyteammember := TeamMember{ diff --git a/pkg/models/teams_rights_test.go b/pkg/models/teams_rights_test.go index e7a15c75d..3c8c27dc5 100644 --- a/pkg/models/teams_rights_test.go +++ b/pkg/models/teams_rights_test.go @@ -17,6 +17,7 @@ package models import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" "testing" @@ -78,6 +79,8 @@ func TestTeam_CanDoSomething(t *testing.T) { } 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/unit_tests.go b/pkg/models/unit_tests.go index 4fa10ae38..57d008697 100644 --- a/pkg/models/unit_tests.go +++ b/pkg/models/unit_tests.go @@ -21,8 +21,6 @@ import ( "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/log" "code.vikunja.io/api/pkg/mail" - "github.com/stretchr/testify/assert" - "testing" ) // SetupTests takes care of seting up the db, fixtures etc. @@ -64,15 +62,4 @@ func SetupTests() { // 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 initFixtures(t *testing.T) { - // Init db fixtures - err := db.LoadFixtures() - assert.NoError(t, err) } diff --git a/pkg/models/users_list_test.go b/pkg/models/users_list_test.go index 29ca70945..5e88c83ca 100644 --- a/pkg/models/users_list_test.go +++ b/pkg/models/users_list_test.go @@ -20,16 +20,11 @@ package models import ( "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" - "github.com/stretchr/testify/assert" "gopkg.in/d4l3k/messagediff.v1" "testing" ) func TestListUsersFromList(t *testing.T) { - - err := db.LoadFixtures() - assert.NoError(t, err) - testuser1 := &user.User{ ID: 1, Username: "user1", @@ -165,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/user/user_email_confirm_test.go b/pkg/user/user_email_confirm_test.go index e52825882..4a72877da 100644 --- a/pkg/user/user_email_confirm_test.go +++ b/pkg/user/user_email_confirm_test.go @@ -18,10 +18,14 @@ package user import ( + "code.vikunja.io/api/pkg/db" "testing" ) func TestUserEmailConfirm(t *testing.T) { + + db.LoadAndAssertFixtures(t) + type args struct { c *EmailConfirm } diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go index f0e3e29f1..ea7c4f14e 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -18,14 +18,15 @@ package user import ( + "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/utils" "github.com/stretchr/testify/assert" "testing" ) func TestCreateUser(t *testing.T) { - // Create test database - //assert.NoError(t, LoadFixtures()) + + db.LoadAndAssertFixtures(t) // Our dummy user for testing dummyuser := &User{ @@ -132,6 +133,9 @@ func TestCreateUser(t *testing.T) { } func TestUserPasswordReset(t *testing.T) { + + db.LoadAndAssertFixtures(t) + // Request a new token tr := &PasswordTokenRequest{ Email: "user1@example.com", -- 2.40.1 From 39fd190d8ff2bd79b910bcaa0467ccbd4819fcc2 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 13:58:01 +0100 Subject: [PATCH 13/19] Fix lint --- pkg/db/test_fixtures.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/db/test_fixtures.go b/pkg/db/test_fixtures.go index d6bdaf435..16d75a2b3 100644 --- a/pkg/db/test_fixtures.go +++ b/pkg/db/test_fixtures.go @@ -56,6 +56,7 @@ 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) -- 2.40.1 From fc58082cab45e151f5a3022cdf788a2fa42f86b6 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 14:25:24 +0100 Subject: [PATCH 14/19] Docs --- docs/content/doc/development/structure.md | 37 +++++++++++++++++++++++ docs/content/doc/development/test.md | 26 ++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/docs/content/doc/development/structure.md b/docs/content/doc/development/structure.md index 8e819b6c4..29dc1eba3 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 1fdcfe893..55ddc883f 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). -- 2.40.1 From 4906db8c2be434887d5547acd9e3b6994142f48d Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 14:37:20 +0100 Subject: [PATCH 15/19] Start refactoring user tests --- pkg/user/user_email_confirm_test.go | 4 +- pkg/user/user_test.go | 107 +++++++++++++++++++--------- 2 files changed, 73 insertions(+), 38 deletions(-) diff --git a/pkg/user/user_email_confirm_test.go b/pkg/user/user_email_confirm_test.go index 4a72877da..7d46471eb 100644 --- a/pkg/user/user_email_confirm_test.go +++ b/pkg/user/user_email_confirm_test.go @@ -23,9 +23,6 @@ import ( ) func TestUserEmailConfirm(t *testing.T) { - - db.LoadAndAssertFixtures(t) - type args struct { c *EmailConfirm } @@ -66,6 +63,7 @@ func TestUserEmailConfirm(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + 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/user/user_test.go b/pkg/user/user_test.go index ea7c4f14e..5c4ce4eb3 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -25,43 +25,73 @@ import ( ) func TestCreateUser(t *testing.T) { - - db.LoadAndAssertFixtures(t) - // Our dummy user for testing dummyuser := &User{ - Username: "testuu", + Username: "testuser", 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)) + 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) + 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) { // Check if he exists theuser, err := GetUser(createdUser) assert.NoError(t, err) @@ -75,6 +105,9 @@ func TestCreateUser(t *testing.T) { assert.Error(t, err) assert.True(t, IsErrUserDoesNotExist(err)) +} + +func TestCheckUserCredentials(t *testing.T) { // Check the user credentials with an unverified email _, err = CheckUserCredentials(&Login{"user5", "1234"}) assert.Error(t, err) @@ -96,7 +129,9 @@ func TestCreateUser(t *testing.T) { _, err = CheckUserCredentials(&Login{"dfstestuu", "1234"}) assert.Error(t, err) assert.True(t, IsErrWrongUsernameOrPassword(err)) +} +func TestUpdateUser(t *testing.T) { // Update the user uuser, err := UpdateUser(&User{ID: theuser.ID, Password: "444444"}) assert.NoError(t, err) @@ -117,6 +152,13 @@ func TestCreateUser(t *testing.T) { _, err = CheckUserCredentials(&Login{theuser.Username, newpassword}) assert.NoError(t, err) + // 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)) +} + +func TestListUsers(t *testing.T) { // Check if the searchterm works all, err := ListUsers("test") assert.NoError(t, err) @@ -125,11 +167,6 @@ func TestCreateUser(t *testing.T) { 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)) } func TestUserPasswordReset(t *testing.T) { -- 2.40.1 From 826bd493d31370cd4e1de947484f5919df3dbf48 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 17:28:35 +0100 Subject: [PATCH 16/19] More user tests --- pkg/user/user_test.go | 185 +++++++++++++++++++++++++++--------------- 1 file changed, 120 insertions(+), 65 deletions(-) diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go index 5c4ce4eb3..8536071ff 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -79,7 +79,6 @@ func TestCreateUser(t *testing.T) { assert.True(t, IsErrNoUsernamePassword(err)) }) t.Run("no email", func(t *testing.T) { - db.LoadAndAssertFixtures(t) db.LoadAndAssertFixtures(t) _, err := CreateUser(&User{ Username: "testuser", @@ -92,83 +91,137 @@ func TestCreateUser(t *testing.T) { } func TestGetUser(t *testing.T) { - // 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)) - + 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)) + }) + 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)) + }) + 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") + }) + 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)) + }) } func TestCheckUserCredentials(t *testing.T) { - // Check the user credentials with an unverified email - _, err = CheckUserCredentials(&Login{"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(&Login{"testuu", "1234"}) - assert.NoError(t, err) - assert.Equal(t, "testuu", user.Username) - - // Check wrong password (should also fail) - _, err = CheckUserCredentials(&Login{"testuu", "12345"}) - assert.Error(t, err) - assert.True(t, IsErrWrongUsernameOrPassword(err)) - - // Check usercredentials for a nonexistent user (should fail) - _, err = CheckUserCredentials(&Login{"dfstestuu", "1234"}) - assert.Error(t, err) - assert.True(t, IsErrWrongUsernameOrPassword(err)) + 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)) + }) } func TestUpdateUser(t *testing.T) { - // 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 + 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)) + }) +} - // Try updating one which does not exist - _, err = UpdateUser(&User{ID: 99999, Username: "dg"}) - assert.Error(t, err) - assert.True(t, IsErrUserDoesNotExist(err)) +func TestUpdateUserPassword(t *testing.T) { - // Update a users password - newpassword := "55555" - err = UpdateUserPassword(theuser, newpassword) - assert.NoError(t, err) - - // Check if it was changed - _, err = CheckUserCredentials(&Login{theuser.Username, newpassword}) - assert.NoError(t, err) - - // 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)) + 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)) + }) } func TestListUsers(t *testing.T) { - // 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) + 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) { + all, err := ListUsers("") + assert.NoError(t, err) + assert.Len(t, all, 13) + }) } +/* func TestUserPasswordReset(t *testing.T) { db.LoadAndAssertFixtures(t) @@ -205,3 +258,5 @@ func TestUserPasswordReset(t *testing.T) { assert.Error(t, err) assert.True(t, IsErrInvalidPasswordResetToken(err)) } + +*/ -- 2.40.1 From 09befbd0c24ce2df31393deb70642ff8208ce5b9 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 17:34:53 +0100 Subject: [PATCH 17/19] More user tests --- pkg/user/user_test.go | 77 ++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go index 8536071ff..ac538f12a 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -19,7 +19,6 @@ package user import ( "code.vikunja.io/api/pkg/db" - "code.vikunja.io/api/pkg/utils" "github.com/stretchr/testify/assert" "testing" ) @@ -215,48 +214,50 @@ func TestListUsers(t *testing.T) { 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) { - - db.LoadAndAssertFixtures(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 = ResetPassword(reset) - assert.True(t, IsErrNoUsernamePassword(err)) - - // Reset it - reset.NewPassword = "1234" - err = ResetPassword(reset) - assert.NoError(t, err) - - // Try resetting it with a wrong token - reset.Token = utils.MakeRandomString(400) - err = ResetPassword(reset) - assert.Error(t, err) - assert.True(t, IsErrInvalidPasswordResetToken(err)) + 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)) + }) } - -*/ -- 2.40.1 From e0edbc9fdd20b8165216a01d50228d3440540658 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 17:43:37 +0100 Subject: [PATCH 18/19] Add more user tests --- pkg/user/user_test.go | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/pkg/user/user_test.go b/pkg/user/user_test.go index ac538f12a..4ff757594 100644 --- a/pkg/user/user_test.go +++ b/pkg/user/user_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // @@ -97,6 +97,7 @@ func TestGetUser(t *testing.T) { }) 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) @@ -105,6 +106,7 @@ func TestGetUser(t *testing.T) { }) 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) @@ -112,6 +114,7 @@ func TestGetUser(t *testing.T) { 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) @@ -125,6 +128,20 @@ func TestGetUser(t *testing.T) { 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) { @@ -151,6 +168,18 @@ func TestCheckUserCredentials(t *testing.T) { 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) { @@ -203,6 +232,15 @@ func TestUpdateUserPassword(t *testing.T) { 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) { -- 2.40.1 From d4342c1956ada5db98d3ae209add7fbc21da4591 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 26 Jan 2020 17:53:41 +0100 Subject: [PATCH 19/19] fix copyright date --- pkg/db/test.go | 2 +- pkg/models/user_list.go | 2 +- pkg/models/users_list_test.go | 2 +- pkg/user/error.go | 2 +- pkg/user/test.go | 2 +- pkg/user/user.go | 2 +- pkg/user/user_email_confirm.go | 2 +- pkg/user/user_email_confirm_test.go | 2 +- pkg/user/user_password_reset.go | 2 +- pkg/user/users_list.go | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/db/test.go b/pkg/db/test.go index 0820b1cdd..a71310845 100644 --- a/pkg/db/test.go +++ b/pkg/db/test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/models/user_list.go b/pkg/models/user_list.go index fb74f10d4..d23b993ca 100644 --- a/pkg/models/user_list.go +++ b/pkg/models/user_list.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/models/users_list_test.go b/pkg/models/users_list_test.go index 5e88c83ca..3d2cf900c 100644 --- a/pkg/models/users_list_test.go +++ b/pkg/models/users_list_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/error.go b/pkg/user/error.go index 66b701be9..1a26a5b71 100644 --- a/pkg/user/error.go +++ b/pkg/user/error.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/test.go b/pkg/user/test.go index fe921b6d7..f2a61cd29 100644 --- a/pkg/user/test.go +++ b/pkg/user/test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/user.go b/pkg/user/user.go index c214a50e6..42cfc33d3 100644 --- a/pkg/user/user.go +++ b/pkg/user/user.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/user_email_confirm.go b/pkg/user/user_email_confirm.go index 5e3a136cd..68378c2bf 100644 --- a/pkg/user/user_email_confirm.go +++ b/pkg/user/user_email_confirm.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/user_email_confirm_test.go b/pkg/user/user_email_confirm_test.go index 7d46471eb..bfb38138e 100644 --- a/pkg/user/user_email_confirm_test.go +++ b/pkg/user/user_email_confirm_test.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/user_password_reset.go b/pkg/user/user_password_reset.go index 4f5809bd8..24d47d2b5 100644 --- a/pkg/user/user_password_reset.go +++ b/pkg/user/user_password_reset.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // diff --git a/pkg/user/users_list.go b/pkg/user/users_list.go index 20fdc7106..dd838aab3 100644 --- a/pkg/user/users_list.go +++ b/pkg/user/users_list.go @@ -1,4 +1,4 @@ -// Copyright 2020 Vikunja and contriubtors. All rights reserved. +// Copyright2018-2020 Vikunja and contriubtors. All rights reserved. // // This file is part of Vikunja. // -- 2.40.1