Refactor User and DB handling (#123)
fix copyright date Add more user tests More user tests More user tests Start refactoring user tests Docs Fix lint Fix db fixtures init in tests Fix models test Fix loading fixtures Fix ineffasign Fix lint Fix integration tests Fix init of test engine creation Fix user related tests Better handling of creating test enging Moved all fixtures to db package Moved all fixtures to db package Moved user related stuff to seperate package Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/123
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -9,7 +11,7 @@ func TestBulkTask_Update(t *testing.T) {
|
||||
IDs []int64
|
||||
Tasks []*Task
|
||||
Task Task
|
||||
User *User
|
||||
User *user.User
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -24,7 +26,7 @@ func TestBulkTask_Update(t *testing.T) {
|
||||
Task: Task{
|
||||
Text: "bulkupdated",
|
||||
},
|
||||
User: &User{ID: 1},
|
||||
User: &user.User{ID: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -34,7 +36,7 @@ func TestBulkTask_Update(t *testing.T) {
|
||||
Task: Task{
|
||||
Text: "bulkupdated",
|
||||
},
|
||||
User: &User{ID: 1},
|
||||
User: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
},
|
||||
@ -45,13 +47,15 @@ func TestBulkTask_Update(t *testing.T) {
|
||||
Task: Task{
|
||||
Text: "bulkupdated",
|
||||
},
|
||||
User: &User{ID: 1},
|
||||
User: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
bt := &BulkTask{
|
||||
IDs: tt.fields.IDs,
|
||||
Tasks: tt.fields.Tasks,
|
||||
|
@ -46,273 +46,6 @@ func (err ErrGenericForbidden) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrorCodeGenericForbidden, Message: "You're not allowed to do this."}
|
||||
}
|
||||
|
||||
// =====================
|
||||
// User Operation Errors
|
||||
// =====================
|
||||
|
||||
// ErrUsernameExists represents a "UsernameAlreadyExists" kind of error.
|
||||
type ErrUsernameExists struct {
|
||||
UserID int64
|
||||
Username string
|
||||
}
|
||||
|
||||
// IsErrUsernameExists checks if an error is a ErrUsernameExists.
|
||||
func IsErrUsernameExists(err error) bool {
|
||||
_, ok := err.(ErrUsernameExists)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUsernameExists) Error() string {
|
||||
return fmt.Sprintf("User with that username already exists [user id: %d, username: %s]", err.UserID, err.Username)
|
||||
}
|
||||
|
||||
// ErrorCodeUsernameExists holds the unique world-error code of this error
|
||||
const ErrorCodeUsernameExists = 1001
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrUsernameExists) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUsernameExists, Message: "A user with this username already exists."}
|
||||
}
|
||||
|
||||
// ErrUserEmailExists represents a "UserEmailExists" kind of error.
|
||||
type ErrUserEmailExists struct {
|
||||
UserID int64
|
||||
Email string
|
||||
}
|
||||
|
||||
// IsErrUserEmailExists checks if an error is a ErrUserEmailExists.
|
||||
func IsErrUserEmailExists(err error) bool {
|
||||
_, ok := err.(ErrUserEmailExists)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUserEmailExists) Error() string {
|
||||
return fmt.Sprintf("User with that email already exists [user id: %d, email: %s]", err.UserID, err.Email)
|
||||
}
|
||||
|
||||
// ErrorCodeUserEmailExists holds the unique world-error code of this error
|
||||
const ErrorCodeUserEmailExists = 1002
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrUserEmailExists) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUserEmailExists, Message: "A user with this email address already exists."}
|
||||
}
|
||||
|
||||
// ErrNoUsernamePassword represents a "NoUsernamePassword" kind of error.
|
||||
type ErrNoUsernamePassword struct{}
|
||||
|
||||
// IsErrNoUsernamePassword checks if an error is a ErrNoUsernamePassword.
|
||||
func IsErrNoUsernamePassword(err error) bool {
|
||||
_, ok := err.(ErrNoUsernamePassword)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrNoUsernamePassword) Error() string {
|
||||
return fmt.Sprintf("No username and password provided")
|
||||
}
|
||||
|
||||
// ErrCodeNoUsernamePassword holds the unique world-error code of this error
|
||||
const ErrCodeNoUsernamePassword = 1004
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrNoUsernamePassword) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeNoUsernamePassword, Message: "Please specify a username and a password."}
|
||||
}
|
||||
|
||||
// ErrUserDoesNotExist represents a "UserDoesNotExist" kind of error.
|
||||
type ErrUserDoesNotExist struct {
|
||||
UserID int64
|
||||
}
|
||||
|
||||
// IsErrUserDoesNotExist checks if an error is a ErrUserDoesNotExist.
|
||||
func IsErrUserDoesNotExist(err error) bool {
|
||||
_, ok := err.(ErrUserDoesNotExist)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrUserDoesNotExist) Error() string {
|
||||
return fmt.Sprintf("User does not exist [user id: %d]", err.UserID)
|
||||
}
|
||||
|
||||
// ErrCodeUserDoesNotExist holds the unique world-error code of this error
|
||||
const ErrCodeUserDoesNotExist = 1005
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrUserDoesNotExist) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeUserDoesNotExist, Message: "The user does not exist."}
|
||||
}
|
||||
|
||||
// ErrCouldNotGetUserID represents a "ErrCouldNotGetUserID" kind of error.
|
||||
type ErrCouldNotGetUserID struct{}
|
||||
|
||||
// IsErrCouldNotGetUserID checks if an error is a ErrCouldNotGetUserID.
|
||||
func IsErrCouldNotGetUserID(err error) bool {
|
||||
_, ok := err.(ErrCouldNotGetUserID)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrCouldNotGetUserID) Error() string {
|
||||
return fmt.Sprintf("Could not get user ID")
|
||||
}
|
||||
|
||||
// ErrCodeCouldNotGetUserID holds the unique world-error code of this error
|
||||
const ErrCodeCouldNotGetUserID = 1006
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrCouldNotGetUserID) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeCouldNotGetUserID, Message: "Could not get user id."}
|
||||
}
|
||||
|
||||
// ErrNoPasswordResetToken represents an error where no password reset token exists for that user
|
||||
type ErrNoPasswordResetToken struct {
|
||||
UserID int64
|
||||
}
|
||||
|
||||
func (err ErrNoPasswordResetToken) Error() string {
|
||||
return fmt.Sprintf("No token to reset a password [UserID: %d]", err.UserID)
|
||||
}
|
||||
|
||||
// ErrCodeNoPasswordResetToken holds the unique world-error code of this error
|
||||
const ErrCodeNoPasswordResetToken = 1008
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrNoPasswordResetToken) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeNoPasswordResetToken, Message: "No token to reset a user's password provided."}
|
||||
}
|
||||
|
||||
// ErrInvalidPasswordResetToken is an error where the password reset token is invalid
|
||||
type ErrInvalidPasswordResetToken struct {
|
||||
Token string
|
||||
}
|
||||
|
||||
func (err ErrInvalidPasswordResetToken) Error() string {
|
||||
return fmt.Sprintf("Invalid token to reset a password [Token: %s]", err.Token)
|
||||
}
|
||||
|
||||
// ErrCodeInvalidPasswordResetToken holds the unique world-error code of this error
|
||||
const ErrCodeInvalidPasswordResetToken = 1009
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrInvalidPasswordResetToken) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidPasswordResetToken, Message: "Invalid token to reset a user's password."}
|
||||
}
|
||||
|
||||
// IsErrInvalidPasswordResetToken checks if an error is a ErrInvalidPasswordResetToken.
|
||||
func IsErrInvalidPasswordResetToken(err error) bool {
|
||||
_, ok := err.(ErrInvalidPasswordResetToken)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrInvalidEmailConfirmToken is an error where the email confirm token is invalid
|
||||
type ErrInvalidEmailConfirmToken struct {
|
||||
Token string
|
||||
}
|
||||
|
||||
func (err ErrInvalidEmailConfirmToken) Error() string {
|
||||
return fmt.Sprintf("Invalid email confirm token [Token: %s]", err.Token)
|
||||
}
|
||||
|
||||
// ErrCodeInvalidEmailConfirmToken holds the unique world-error code of this error
|
||||
const ErrCodeInvalidEmailConfirmToken = 1010
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrInvalidEmailConfirmToken) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidEmailConfirmToken, Message: "Invalid email confirm token."}
|
||||
}
|
||||
|
||||
// IsErrInvalidEmailConfirmToken checks if an error is a ErrInvalidEmailConfirmToken.
|
||||
func IsErrInvalidEmailConfirmToken(err error) bool {
|
||||
_, ok := err.(ErrInvalidEmailConfirmToken)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrWrongUsernameOrPassword is an error where the email was not confirmed
|
||||
type ErrWrongUsernameOrPassword struct {
|
||||
}
|
||||
|
||||
func (err ErrWrongUsernameOrPassword) Error() string {
|
||||
return fmt.Sprintf("Wrong username or password")
|
||||
}
|
||||
|
||||
// ErrCodeWrongUsernameOrPassword holds the unique world-error code of this error
|
||||
const ErrCodeWrongUsernameOrPassword = 1011
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrWrongUsernameOrPassword) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeWrongUsernameOrPassword, Message: "Wrong username or password."}
|
||||
}
|
||||
|
||||
// IsErrWrongUsernameOrPassword checks if an error is a IsErrEmailNotConfirmed.
|
||||
func IsErrWrongUsernameOrPassword(err error) bool {
|
||||
_, ok := err.(ErrWrongUsernameOrPassword)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrEmailNotConfirmed is an error where the email was not confirmed
|
||||
type ErrEmailNotConfirmed struct {
|
||||
UserID int64
|
||||
}
|
||||
|
||||
func (err ErrEmailNotConfirmed) Error() string {
|
||||
return fmt.Sprintf("Email is not confirmed [UserID: %d]", err.UserID)
|
||||
}
|
||||
|
||||
// ErrCodeEmailNotConfirmed holds the unique world-error code of this error
|
||||
const ErrCodeEmailNotConfirmed = 1012
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrEmailNotConfirmed) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmailNotConfirmed, Message: "Please confirm your email address."}
|
||||
}
|
||||
|
||||
// IsErrEmailNotConfirmed checks if an error is a IsErrEmailNotConfirmed.
|
||||
func IsErrEmailNotConfirmed(err error) bool {
|
||||
_, ok := err.(ErrEmailNotConfirmed)
|
||||
return ok
|
||||
}
|
||||
|
||||
// ErrEmptyNewPassword represents a "EmptyNewPassword" kind of error.
|
||||
type ErrEmptyNewPassword struct{}
|
||||
|
||||
// IsErrEmptyNewPassword checks if an error is a ErrEmptyNewPassword.
|
||||
func IsErrEmptyNewPassword(err error) bool {
|
||||
_, ok := err.(ErrEmptyNewPassword)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrEmptyNewPassword) Error() string {
|
||||
return fmt.Sprintf("New password is empty")
|
||||
}
|
||||
|
||||
// ErrCodeEmptyNewPassword holds the unique world-error code of this error
|
||||
const ErrCodeEmptyNewPassword = 1013
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrEmptyNewPassword) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyNewPassword, Message: "Please specify new password."}
|
||||
}
|
||||
|
||||
// ErrEmptyOldPassword represents a "EmptyOldPassword" kind of error.
|
||||
type ErrEmptyOldPassword struct{}
|
||||
|
||||
// IsErrEmptyOldPassword checks if an error is a ErrEmptyOldPassword.
|
||||
func IsErrEmptyOldPassword(err error) bool {
|
||||
_, ok := err.(ErrEmptyOldPassword)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrEmptyOldPassword) Error() string {
|
||||
return fmt.Sprintf("Old password is empty")
|
||||
}
|
||||
|
||||
// ErrCodeEmptyOldPassword holds the unique world-error code of this error
|
||||
const ErrCodeEmptyOldPassword = 1014
|
||||
|
||||
// HTTPError holds the http error description
|
||||
func (err ErrEmptyOldPassword) HTTPError() web.HTTPError {
|
||||
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyOldPassword, Message: "Please specify old password."}
|
||||
}
|
||||
|
||||
// ===================
|
||||
// Empty things errors
|
||||
// ===================
|
||||
|
@ -1 +0,0 @@
|
||||
../../files/fixtures/files.yml
|
@ -1,8 +0,0 @@
|
||||
- id: 1
|
||||
task_id: 1
|
||||
label_id: 4
|
||||
created: 0
|
||||
- id: 2
|
||||
task_id: 2
|
||||
label_id: 4
|
||||
created: 0
|
@ -1,20 +0,0 @@
|
||||
- id: 1
|
||||
title: 'Label #1'
|
||||
created_by_id: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 2
|
||||
title: 'Label #2'
|
||||
created_by_id: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 3
|
||||
title: 'Label #3 - other user'
|
||||
created_by_id: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 4
|
||||
title: 'Label #4 - visible via other task'
|
||||
created_by_id: 2
|
||||
updated: 0
|
||||
created: 0
|
@ -1,24 +0,0 @@
|
||||
- id: 1
|
||||
hash: test
|
||||
list_id: 1
|
||||
right: 0
|
||||
sharing_type: 1
|
||||
shared_by_id: 1
|
||||
created: 0
|
||||
updated: 0
|
||||
- id: 2
|
||||
hash: test2
|
||||
list_id: 2
|
||||
right: 1
|
||||
sharing_type: 1
|
||||
shared_by_id: 1
|
||||
created: 0
|
||||
updated: 0
|
||||
- id: 3
|
||||
hash: test3
|
||||
list_id: 3
|
||||
right: 2
|
||||
sharing_type: 1
|
||||
shared_by_id: 1
|
||||
created: 0
|
||||
updated: 0
|
@ -1,182 +0,0 @@
|
||||
-
|
||||
id: 1
|
||||
title: Test1
|
||||
description: Lorem Ipsum
|
||||
identifier: test1
|
||||
owner_id: 1
|
||||
namespace_id: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 2
|
||||
title: Test2
|
||||
description: Lorem Ipsum
|
||||
identifier: test2
|
||||
owner_id: 3
|
||||
namespace_id: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 3
|
||||
title: Test3
|
||||
description: Lorem Ipsum
|
||||
identifier: test3
|
||||
owner_id: 3
|
||||
namespace_id: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 4
|
||||
title: Test4
|
||||
description: Lorem Ipsum
|
||||
identifier: test4
|
||||
owner_id: 3
|
||||
namespace_id: 3
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 5
|
||||
title: Test5
|
||||
description: Lorem Ipsum
|
||||
identifier: test5
|
||||
owner_id: 5
|
||||
namespace_id: 5
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 6
|
||||
title: Test6
|
||||
description: Lorem Ipsum
|
||||
identifier: test6
|
||||
owner_id: 6
|
||||
namespace_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 7
|
||||
title: Test7
|
||||
description: Lorem Ipsum
|
||||
identifier: test7
|
||||
owner_id: 6
|
||||
namespace_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 8
|
||||
title: Test8
|
||||
description: Lorem Ipsum
|
||||
identifier: test8
|
||||
owner_id: 6
|
||||
namespace_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 9
|
||||
title: Test9
|
||||
description: Lorem Ipsum
|
||||
identifier: test9
|
||||
owner_id: 6
|
||||
namespace_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 10
|
||||
title: Test10
|
||||
description: Lorem Ipsum
|
||||
identifier: test10
|
||||
owner_id: 6
|
||||
namespace_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 11
|
||||
title: Test11
|
||||
description: Lorem Ipsum
|
||||
identifier: test11
|
||||
owner_id: 6
|
||||
namespace_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 12
|
||||
title: Test12
|
||||
description: Lorem Ipsum
|
||||
identifier: test12
|
||||
owner_id: 6
|
||||
namespace_id: 7
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 13
|
||||
title: Test13
|
||||
description: Lorem Ipsum
|
||||
identifier: test13
|
||||
owner_id: 6
|
||||
namespace_id: 8
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 14
|
||||
title: Test14
|
||||
description: Lorem Ipsum
|
||||
identifier: test14
|
||||
owner_id: 6
|
||||
namespace_id: 9
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 15
|
||||
title: Test15
|
||||
description: Lorem Ipsum
|
||||
identifier: test15
|
||||
owner_id: 6
|
||||
namespace_id: 10
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 16
|
||||
title: Test16
|
||||
description: Lorem Ipsum
|
||||
identifier: test16
|
||||
owner_id: 6
|
||||
namespace_id: 11
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 17
|
||||
title: Test17
|
||||
description: Lorem Ipsum
|
||||
identifier: test17
|
||||
owner_id: 6
|
||||
namespace_id: 12
|
||||
updated: 0
|
||||
created: 0
|
||||
# This list is owned by user 7, and several other users have access to it via different methods.
|
||||
# It is used to test the listUsers method.
|
||||
-
|
||||
id: 18
|
||||
title: Test18
|
||||
description: Lorem Ipsum
|
||||
identifier: test18
|
||||
owner_id: 7
|
||||
namespace_id: 13
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 19
|
||||
title: Test19
|
||||
description: Lorem Ipsum
|
||||
identifier: test19
|
||||
owner_id: 7
|
||||
namespace_id: 14
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 20
|
||||
title: Test20
|
||||
description: Lorem Ipsum
|
||||
identifier: test20
|
||||
owner_id: 13
|
||||
namespace_id: 15
|
||||
updated: 0
|
||||
created: 0
|
@ -1,78 +0,0 @@
|
||||
- id: 1
|
||||
name: testnamespace
|
||||
description: Lorem Ipsum
|
||||
owner_id: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 2
|
||||
name: testnamespace2
|
||||
description: Lorem Ipsum
|
||||
owner_id: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 3
|
||||
name: testnamespace3
|
||||
description: Lorem Ipsum
|
||||
owner_id: 3
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 6
|
||||
name: testnamespace6
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 7
|
||||
name: testnamespace7
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 8
|
||||
name: testnamespace8
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 9
|
||||
name: testnamespace9
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 10
|
||||
name: testnamespace10
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 11
|
||||
name: testnamespace11
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 12
|
||||
name: testnamespace12
|
||||
description: Lorem Ipsum
|
||||
owner_id: 6
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 13
|
||||
name: testnamespace13
|
||||
description: Lorem Ipsum
|
||||
owner_id: 7
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 14
|
||||
name: testnamespace14
|
||||
description: Lorem Ipsum
|
||||
owner_id: 7
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 15
|
||||
name: testnamespace15
|
||||
description: Lorem Ipsum
|
||||
owner_id: 13
|
||||
updated: 0
|
||||
created: 0
|
@ -1,8 +0,0 @@
|
||||
- id: 1
|
||||
task_id: 30
|
||||
user_id: 1
|
||||
created: 0
|
||||
- id: 2
|
||||
task_id: 30
|
||||
user_id: 2
|
||||
created: 0
|
@ -1,11 +0,0 @@
|
||||
- id: 1
|
||||
task_id: 1
|
||||
file_id: 1
|
||||
created_by_id: 1
|
||||
created: 0
|
||||
# The file for this attachment does not exist
|
||||
- id: 2
|
||||
task_id: 1
|
||||
file_id: 9999
|
||||
created_by_id: 1
|
||||
created: 0
|
@ -1,12 +0,0 @@
|
||||
- id: 1
|
||||
task_id: 1
|
||||
other_task_id: 29
|
||||
relation_kind: 'subtask'
|
||||
created_by_id: 1
|
||||
created: 0
|
||||
- id: 2
|
||||
task_id: 29
|
||||
other_task_id: 1
|
||||
relation_kind: 'parenttask'
|
||||
created_by_id: 1
|
||||
created: 0
|
@ -1,8 +0,0 @@
|
||||
- id: 1
|
||||
task_id: 27
|
||||
reminder_unix: 1543626724
|
||||
created: 1543626724
|
||||
- id: 2
|
||||
task_id: 27
|
||||
reminder_unix: 1543626824
|
||||
created: 1543626724
|
@ -1,246 +0,0 @@
|
||||
- id: 1
|
||||
text: 'task #1'
|
||||
description: 'Lorem Ipsum'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 2
|
||||
text: 'task #2 done'
|
||||
done: true
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 2
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 3
|
||||
text: 'task #3 high prio'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 3
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
priority: 100
|
||||
- id: 4
|
||||
text: 'task #4 low prio'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 4
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
priority: 1
|
||||
- id: 5
|
||||
text: 'task #5 higher due date'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 5
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
due_date_unix: 1543636724
|
||||
- id: 6
|
||||
text: 'task #6 lower due date'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 6
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
due_date_unix: 1543616724
|
||||
- id: 7
|
||||
text: 'task #7 with start date'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 7
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
start_date_unix: 1544600000
|
||||
- id: 8
|
||||
text: 'task #8 with end date'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 8
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
end_date_unix: 1544700000
|
||||
- id: 9
|
||||
text: 'task #9 with start and end date'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 9
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
start_date_unix: 1544600000
|
||||
end_date_unix: 1544700000
|
||||
- id: 10
|
||||
text: 'task #10 basic'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 10
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 11
|
||||
text: 'task #11 basic'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 11
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 12
|
||||
text: 'task #12 basic'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 12
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 13
|
||||
text: 'task #13 basic other list'
|
||||
created_by_id: 1
|
||||
list_id: 2
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 14
|
||||
text: 'task #14 basic other list'
|
||||
created_by_id: 5
|
||||
list_id: 5
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 15
|
||||
text: 'task #15'
|
||||
created_by_id: 6
|
||||
list_id: 6
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 16
|
||||
text: 'task #16'
|
||||
created_by_id: 6
|
||||
list_id: 7
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 17
|
||||
text: 'task #17'
|
||||
created_by_id: 6
|
||||
list_id: 8
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 18
|
||||
text: 'task #18'
|
||||
created_by_id: 6
|
||||
list_id: 9
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 19
|
||||
text: 'task #19'
|
||||
created_by_id: 6
|
||||
list_id: 10
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 20
|
||||
text: 'task #20'
|
||||
created_by_id: 6
|
||||
list_id: 11
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 21
|
||||
text: 'task #21'
|
||||
created_by_id: 6
|
||||
list_id: 12
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 22
|
||||
text: 'task #22'
|
||||
created_by_id: 6
|
||||
list_id: 13
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 23
|
||||
text: 'task #23'
|
||||
created_by_id: 6
|
||||
list_id: 14
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 24
|
||||
text: 'task #24'
|
||||
created_by_id: 6
|
||||
list_id: 15
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 25
|
||||
text: 'task #25'
|
||||
created_by_id: 6
|
||||
list_id: 16
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 26
|
||||
text: 'task #26'
|
||||
created_by_id: 6
|
||||
list_id: 17
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 27
|
||||
text: 'task #27 with reminders'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 12
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 28
|
||||
text: 'task #28 with repeat after'
|
||||
done: false
|
||||
created_by_id: 1
|
||||
repeat_after: 3600
|
||||
list_id: 1
|
||||
index: 13
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 29
|
||||
text: 'task #29 with parent task (1)'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 14
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 30
|
||||
text: 'task #30 with assignees'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 15
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 31
|
||||
text: 'task #31 with color'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 16
|
||||
hex_color: f0f0f0
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 32
|
||||
text: 'task #32'
|
||||
created_by_id: 1
|
||||
list_id: 3
|
||||
index: 1
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
- id: 33
|
||||
text: 'task #33 with percent done'
|
||||
created_by_id: 1
|
||||
list_id: 1
|
||||
index: 17
|
||||
percent_done: 0.5
|
||||
created: 1543626724
|
||||
updated: 1543626724
|
||||
|
@ -1,48 +0,0 @@
|
||||
- id: 1
|
||||
team_id: 1
|
||||
list_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
# This team has read only access on list 6
|
||||
- id: 2
|
||||
team_id: 2
|
||||
list_id: 6
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
# This team has write access on list 7
|
||||
- id: 3
|
||||
team_id: 3
|
||||
list_id: 7
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
# This team has admin access on list 8
|
||||
- id: 4
|
||||
team_id: 4
|
||||
list_id: 8
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
# Readonly acces on list 19
|
||||
- id: 5
|
||||
team_id: 8
|
||||
list_id: 19
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
# Write acces on list 19
|
||||
- id: 6
|
||||
team_id: 9
|
||||
list_id: 19
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
# Admin acces on list 19
|
||||
- id: 7
|
||||
team_id: 10
|
||||
list_id: 19
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
@ -1,57 +0,0 @@
|
||||
-
|
||||
team_id: 1
|
||||
user_id: 1
|
||||
admin: true
|
||||
created: 0
|
||||
-
|
||||
team_id: 1
|
||||
user_id: 2
|
||||
created: 0
|
||||
-
|
||||
team_id: 2
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 3
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 4
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 5
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 6
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 7
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 8
|
||||
user_id: 1
|
||||
created: 0
|
||||
-
|
||||
team_id: 9
|
||||
user_id: 2
|
||||
created: 0
|
||||
-
|
||||
team_id: 10
|
||||
user_id: 3
|
||||
created: 0
|
||||
-
|
||||
team_id: 11
|
||||
user_id: 8
|
||||
created: 0
|
||||
-
|
||||
team_id: 12
|
||||
user_id: 9
|
||||
created: 0
|
||||
-
|
||||
team_id: 13
|
||||
user_id: 10
|
||||
created: 0
|
@ -1,52 +0,0 @@
|
||||
- id: 1
|
||||
team_id: 1
|
||||
namespace_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 2
|
||||
team_id: 2
|
||||
namespace_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 3
|
||||
team_id: 5
|
||||
namespace_id: 7
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 4
|
||||
team_id: 6
|
||||
namespace_id: 8
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 5
|
||||
team_id: 7
|
||||
namespace_id: 9
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 6
|
||||
team_id: 11
|
||||
namespace_id: 14
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 7
|
||||
team_id: 12
|
||||
namespace_id: 14
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 8
|
||||
team_id: 13
|
||||
namespace_id: 14
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
@ -1,40 +0,0 @@
|
||||
- id: 1
|
||||
name: testteam1
|
||||
description: Lorem Ipsum
|
||||
created_by_id: 1
|
||||
- id: 2
|
||||
name: testteam2_read_only_on_list6
|
||||
created_by_id: 1
|
||||
- id: 3
|
||||
name: testteam3_write_on_list7
|
||||
created_by_id: 1
|
||||
- id: 4
|
||||
name: testteam4_admin_on_list8
|
||||
created_by_id: 1
|
||||
- id: 5
|
||||
name: testteam2_read_only_on_namespace7
|
||||
created_by_id: 1
|
||||
- id: 6
|
||||
name: testteam3_write_on_namespace8
|
||||
created_by_id: 1
|
||||
- id: 7
|
||||
name: testteam4_admin_on_namespace9
|
||||
created_by_id: 1
|
||||
- id: 8
|
||||
name: testteam8
|
||||
created_by_id: 7
|
||||
- id: 9
|
||||
name: testteam9
|
||||
created_by_id: 7
|
||||
- id: 10
|
||||
name: testteam10
|
||||
created_by_id: 7
|
||||
- id: 11
|
||||
name: testteam11
|
||||
created_by_id: 7
|
||||
- id: 12
|
||||
name: testteam12
|
||||
created_by_id: 7
|
||||
- id: 13
|
||||
name: testteam13
|
||||
created_by_id: 7
|
@ -1,97 +0,0 @@
|
||||
-
|
||||
id: 1
|
||||
username: 'user1'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user1@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 2
|
||||
username: 'user2'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user2@example.com'
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 3
|
||||
username: 'user3'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user3@example.com'
|
||||
password_reset_token: passwordresettesttoken
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 4
|
||||
username: 'user4'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user4@example.com'
|
||||
email_confirm_token: tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael
|
||||
updated: 0
|
||||
created: 0
|
||||
-
|
||||
id: 5
|
||||
username: 'user5'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user5@example.com'
|
||||
email_confirm_token: tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael
|
||||
is_active: false
|
||||
updated: 0
|
||||
created: 0
|
||||
# This use is used to create a whole bunch of lists which are then shared directly with a user
|
||||
- id: 6
|
||||
username: 'user6'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user6@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 7
|
||||
username: 'user7'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user7@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 8
|
||||
username: 'user8'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user8@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 9
|
||||
username: 'user9'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user9@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 10
|
||||
username: 'user10'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user10@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 11
|
||||
username: 'user11'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user11@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 12
|
||||
username: 'user12'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user12@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 13
|
||||
username: 'user13'
|
||||
password: '$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.' # 1234
|
||||
email: 'user14@example.com'
|
||||
is_active: true
|
||||
updated: 0
|
||||
created: 0
|
@ -1,48 +0,0 @@
|
||||
- id: 1
|
||||
user_id: 1
|
||||
list_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 2
|
||||
user_id: 2
|
||||
list_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 3
|
||||
user_id: 1
|
||||
list_id: 9
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 4
|
||||
user_id: 1
|
||||
list_id: 10
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 5
|
||||
user_id: 1
|
||||
list_id: 11
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 6
|
||||
user_id: 4
|
||||
list_id: 19
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 7
|
||||
user_id: 5
|
||||
list_id: 19
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 8
|
||||
user_id: 6
|
||||
list_id: 19
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
@ -1,52 +0,0 @@
|
||||
- id: 1
|
||||
user_id: 1
|
||||
namespace_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 2
|
||||
user_id: 2
|
||||
namespace_id: 3
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 3
|
||||
user_id: 1
|
||||
namespace_id: 10
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 4
|
||||
user_id: 1
|
||||
namespace_id: 11
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
|
||||
- id: 5
|
||||
user_id: 1
|
||||
namespace_id: 12
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 6
|
||||
user_id: 11
|
||||
namespace_id: 14
|
||||
right: 0
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 7
|
||||
user_id: 12
|
||||
namespace_id: 14
|
||||
right: 1
|
||||
updated: 0
|
||||
created: 0
|
||||
- id: 8
|
||||
user_id: 13
|
||||
namespace_id: 14
|
||||
right: 2
|
||||
updated: 0
|
||||
created: 0
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"time"
|
||||
)
|
||||
@ -34,7 +35,7 @@ type Label struct {
|
||||
|
||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||
// The user who created this label
|
||||
CreatedBy *User `xorm:"-" json:"created_by"`
|
||||
CreatedBy *user.User `xorm:"-" json:"created_by"`
|
||||
|
||||
// A unix timestamp when this label was created. You cannot change this value.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
@ -63,7 +64,7 @@ func (Label) TableName() string {
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /labels [put]
|
||||
func (l *Label) Create(a web.Auth) (err error) {
|
||||
u, err := getUserWithError(a)
|
||||
u, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -136,7 +137,7 @@ func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls in
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
u := &User{ID: a.GetID()}
|
||||
u := &user.User{ID: a.GetID()}
|
||||
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(u)
|
||||
@ -175,7 +176,7 @@ func (l *Label) ReadOne() (err error) {
|
||||
}
|
||||
*l = *label
|
||||
|
||||
user, err := GetUserByID(l.CreatedByID)
|
||||
user, err := user.GetUserByID(l.CreatedByID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -198,7 +199,7 @@ func getLabelByIDSimple(labelID int64) (*Label, error) {
|
||||
}
|
||||
|
||||
// Helper method to get all task ids a user has
|
||||
func getUserTaskIDs(u *User) (taskIDs []int64, err error) {
|
||||
func getUserTaskIDs(u *user.User) (taskIDs []int64, err error) {
|
||||
|
||||
// Get all lists
|
||||
lists, _, _, err := getRawListsForUser("", u, -1, 0)
|
||||
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/go-xorm/builder"
|
||||
)
|
||||
@ -65,7 +66,7 @@ func (l *Label) hasAccessToLabel(a web.Auth) (bool, error) {
|
||||
// TODO: add an extra check for link share handling
|
||||
|
||||
// Get all tasks
|
||||
taskIDs, err := getUserTaskIDs(&User{ID: a.GetID()})
|
||||
taskIDs, err := getUserTaskIDs(&user.User{ID: a.GetID()})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/go-xorm/builder"
|
||||
)
|
||||
@ -120,7 +121,7 @@ func (lt *LabelTask) ReadAll(a web.Auth, search string, page int, perPage int) (
|
||||
}
|
||||
|
||||
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
|
||||
User: &User{ID: a.GetID()},
|
||||
User: &user.User{ID: a.GetID()},
|
||||
Search: search,
|
||||
Page: page,
|
||||
TaskIDs: []int64{lt.TaskID},
|
||||
@ -135,7 +136,7 @@ type labelWithTaskID struct {
|
||||
|
||||
// LabelByTaskIDsOptions is a struct to not clutter the function with too many optional parameters.
|
||||
type LabelByTaskIDsOptions struct {
|
||||
User *User
|
||||
User *user.User
|
||||
Search string
|
||||
Page int
|
||||
PerPage int
|
||||
@ -185,7 +186,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
|
||||
for _, l := range labels {
|
||||
userids = append(userids, l.CreatedByID)
|
||||
}
|
||||
users := make(map[int64]*User)
|
||||
users := make(map[int64]*user.User)
|
||||
err = x.In("id", userids).Find(&users)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
@ -290,7 +291,7 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
|
||||
return err
|
||||
}
|
||||
if !hasAccessToLabel {
|
||||
user, _ := creator.(*User)
|
||||
user, _ := creator.(*user.User)
|
||||
return ErrUserHasNoAccessToLabel{LabelID: l.ID, UserID: user.ID}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@ -37,7 +39,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||
TaskID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantLabels: []*labelWithTaskID{
|
||||
{
|
||||
@ -46,7 +48,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: &User{
|
||||
CreatedBy: &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -62,7 +64,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||
TaskID: 14,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrNoRightToSeeTask,
|
||||
@ -73,7 +75,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||
TaskID: 9999,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrTaskDoesNotExist,
|
||||
@ -81,6 +83,8 @@ func TestLabelTask_ReadAll(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
l := &LabelTask{
|
||||
ID: tt.fields.ID,
|
||||
TaskID: tt.fields.TaskID,
|
||||
@ -131,17 +135,17 @@ func TestLabelTask_Create(t *testing.T) {
|
||||
LabelID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "already existing",
|
||||
fields: fields{
|
||||
TaskID: 1,
|
||||
LabelID: 1,
|
||||
LabelID: 4,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrLabelIsAlreadyOnTask,
|
||||
@ -153,7 +157,7 @@ func TestLabelTask_Create(t *testing.T) {
|
||||
LabelID: 9999,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
},
|
||||
@ -164,7 +168,7 @@ func TestLabelTask_Create(t *testing.T) {
|
||||
LabelID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantForbidden: true,
|
||||
wantErr: true,
|
||||
@ -173,6 +177,8 @@ func TestLabelTask_Create(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
l := &LabelTask{
|
||||
ID: tt.fields.ID,
|
||||
TaskID: tt.fields.TaskID,
|
||||
@ -217,9 +223,9 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||
name: "normal",
|
||||
fields: fields{
|
||||
TaskID: 1,
|
||||
LabelID: 1,
|
||||
LabelID: 4,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "delete nonexistant",
|
||||
@ -227,7 +233,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||
TaskID: 1,
|
||||
LabelID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
@ -236,7 +242,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||
TaskID: 1,
|
||||
LabelID: 9999,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
@ -245,7 +251,7 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||
TaskID: 9999,
|
||||
LabelID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
@ -254,12 +260,14 @@ func TestLabelTask_Delete(t *testing.T) {
|
||||
TaskID: 14,
|
||||
LabelID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
l := &LabelTask{
|
||||
ID: tt.fields.ID,
|
||||
TaskID: tt.fields.TaskID,
|
||||
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@ -32,7 +33,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
@ -43,7 +44,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||
a web.Auth
|
||||
page int
|
||||
}
|
||||
user1 := &User{
|
||||
user1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -60,7 +61,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||
{
|
||||
name: "normal",
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
wantLs: []*labelWithTaskID{
|
||||
{
|
||||
@ -85,7 +86,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: &User{
|
||||
CreatedBy: &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -98,7 +99,7 @@ func TestLabel_ReadAll(t *testing.T) {
|
||||
{
|
||||
name: "invalid user",
|
||||
args: args{
|
||||
a: &User{ID: -1},
|
||||
a: &user.User{ID: -1},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
@ -136,13 +137,13 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
Rights web.Rights
|
||||
}
|
||||
user1 := &User{
|
||||
user1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -169,7 +170,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "Get nonexistant label",
|
||||
@ -179,7 +180,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||
wantErr: true,
|
||||
errType: IsErrLabelDoesNotExist,
|
||||
wantForbidden: true,
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "no rights",
|
||||
@ -187,7 +188,7 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||
ID: 3,
|
||||
},
|
||||
wantForbidden: true,
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "Get label #4 - other user",
|
||||
@ -198,14 +199,14 @@ func TestLabel_ReadOne(t *testing.T) {
|
||||
ID: 4,
|
||||
Title: "Label #4 - visible via other task",
|
||||
CreatedByID: 2,
|
||||
CreatedBy: &User{
|
||||
CreatedBy: &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
},
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -248,7 +249,7 @@ func TestLabel_Create(t *testing.T) {
|
||||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
@ -272,7 +273,7 @@ func TestLabel_Create(t *testing.T) {
|
||||
HexColor: "ffccff",
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -308,7 +309,7 @@ func TestLabel_Update(t *testing.T) {
|
||||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
@ -327,7 +328,7 @@ func TestLabel_Update(t *testing.T) {
|
||||
ID: 1,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "nonexisting",
|
||||
@ -335,7 +336,7 @@ func TestLabel_Update(t *testing.T) {
|
||||
ID: 99999,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
wantErr: true,
|
||||
},
|
||||
@ -345,7 +346,7 @@ func TestLabel_Update(t *testing.T) {
|
||||
ID: 3,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
@ -354,7 +355,7 @@ func TestLabel_Update(t *testing.T) {
|
||||
ID: 4,
|
||||
Title: "new and better",
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
@ -390,7 +391,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||
Description string
|
||||
HexColor string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Created int64
|
||||
Updated int64
|
||||
CRUDable web.CRUDable
|
||||
@ -409,14 +410,14 @@ func TestLabel_Delete(t *testing.T) {
|
||||
fields: fields{
|
||||
ID: 1,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
},
|
||||
{
|
||||
name: "nonexisting",
|
||||
fields: fields{
|
||||
ID: 99999,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true, // When the label does not exist, it is forbidden. We should fix this, but for everything.
|
||||
},
|
||||
{
|
||||
@ -424,7 +425,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||
fields: fields{
|
||||
ID: 3,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
{
|
||||
@ -432,7 +433,7 @@ func TestLabel_Delete(t *testing.T) {
|
||||
fields: fields{
|
||||
ID: 4,
|
||||
},
|
||||
auth: &User{ID: 1},
|
||||
auth: &user.User{ID: 1},
|
||||
wantForbidden: true,
|
||||
},
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
@ -48,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
|
||||
|
@ -18,6 +18,7 @@ package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
@ -36,7 +37,7 @@ type List struct {
|
||||
NamespaceID int64 `xorm:"int(11) INDEX not null" json:"-" param:"namespace"`
|
||||
|
||||
// The user who created this list.
|
||||
Owner *User `xorm:"-" json:"owner" valid:"-"`
|
||||
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
|
||||
// An array of tasks which belong to the list.
|
||||
// Deprecated: you should use the dedicated task list endpoint because it has support for pagination and filtering
|
||||
Tasks []*Task `xorm:"-" json:"-"`
|
||||
@ -51,7 +52,7 @@ type List struct {
|
||||
}
|
||||
|
||||
// GetListsByNamespaceID gets all lists in a namespace
|
||||
func GetListsByNamespaceID(nID int64, doer *User) (lists []*List, err error) {
|
||||
func GetListsByNamespaceID(nID int64, doer *user.User) (lists []*List, err error) {
|
||||
if nID == -1 {
|
||||
err = x.Select("l.*").
|
||||
Table("list").
|
||||
@ -103,7 +104,7 @@ func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result
|
||||
return lists, 0, 0, err
|
||||
}
|
||||
|
||||
lists, resultCount, totalItems, err := getRawListsForUser(search, &User{ID: a.GetID()}, page, perPage)
|
||||
lists, resultCount, totalItems, err := getRawListsForUser(search, &user.User{ID: a.GetID()}, page, perPage)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
@ -127,7 +128,7 @@ func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result
|
||||
// @Router /lists/{id} [get]
|
||||
func (l *List) ReadOne() (err error) {
|
||||
// Get list owner
|
||||
l.Owner, err = GetUserByID(l.OwnerID)
|
||||
l.Owner, err = user.GetUserByID(l.OwnerID)
|
||||
return
|
||||
}
|
||||
|
||||
@ -176,8 +177,8 @@ func GetListSimplByTaskID(taskID int64) (l *List, err error) {
|
||||
}
|
||||
|
||||
// Gets the lists only, without any tasks or so
|
||||
func getRawListsForUser(search string, u *User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
||||
fullUser, err := GetUserByID(u.ID)
|
||||
func getRawListsForUser(search string, u *user.User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
|
||||
fullUser, err := user.GetUserByID(u.ID)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
@ -237,7 +238,7 @@ func AddListDetails(lists []*List) (err error) {
|
||||
}
|
||||
|
||||
// Get all list owners
|
||||
owners := []*User{}
|
||||
owners := []*user.User{}
|
||||
err = x.In("id", ownerIDs).Find(&owners)
|
||||
if err != nil {
|
||||
return
|
||||
@ -348,7 +349,7 @@ func updateListByTaskID(taskID int64) (err error) {
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /namespaces/{namespaceID}/lists [put]
|
||||
func (l *List) Create(a web.Auth) (err error) {
|
||||
doer, err := getUserWithError(a)
|
||||
doer, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/go-xorm/builder"
|
||||
)
|
||||
@ -39,7 +40,7 @@ func (l *List) CanWrite(a web.Auth) (bool, error) {
|
||||
}
|
||||
|
||||
// Check if the user is either owner or can write to the list
|
||||
if originalList.isOwner(&User{ID: a.GetID()}) {
|
||||
if originalList.isOwner(&user.User{ID: a.GetID()}) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@ -60,7 +61,7 @@ func (l *List) CanRead(a web.Auth) (bool, error) {
|
||||
(shareAuth.Right == RightRead || shareAuth.Right == RightWrite || shareAuth.Right == RightAdmin), nil
|
||||
}
|
||||
|
||||
if l.isOwner(&User{ID: a.GetID()}) {
|
||||
if l.isOwner(&user.User{ID: a.GetID()}) {
|
||||
return true, nil
|
||||
}
|
||||
return l.checkRight(a, RightRead, RightWrite, RightAdmin)
|
||||
@ -100,14 +101,14 @@ func (l *List) IsAdmin(a web.Auth) (bool, error) {
|
||||
// Check all the things
|
||||
// Check if the user is either owner or can write to the list
|
||||
// Owners are always admins
|
||||
if originalList.isOwner(&User{ID: a.GetID()}) {
|
||||
if originalList.isOwner(&user.User{ID: a.GetID()}) {
|
||||
return true, nil
|
||||
}
|
||||
return originalList.checkRight(a, RightAdmin)
|
||||
}
|
||||
|
||||
// Little helper function to check if a user is list owner
|
||||
func (l *List) isOwner(u *User) bool {
|
||||
func (l *List) isOwner(u *user.User) bool {
|
||||
return l.OwnerID == u.ID
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
@ -25,6 +27,8 @@ import (
|
||||
)
|
||||
|
||||
func TestTeamList(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Dummy relation
|
||||
tl := TeamList{
|
||||
TeamID: 1,
|
||||
@ -33,7 +37,7 @@ func TestTeamList(t *testing.T) {
|
||||
}
|
||||
|
||||
// Dummyuser
|
||||
u, err := GetUserByID(1)
|
||||
u, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check normal creation
|
||||
@ -164,6 +168,8 @@ func TestTeamList_Update(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tl := &TeamList{
|
||||
ID: tt.fields.ID,
|
||||
TeamID: tt.fields.TeamID,
|
||||
|
@ -17,13 +17,15 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestList_CreateOrUpdate(t *testing.T) {
|
||||
user := &User{
|
||||
usr := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Email: "user1@example.com",
|
||||
@ -31,41 +33,41 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
|
||||
t.Run("create", func(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
NamespaceID: 1,
|
||||
}
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("nonexistant namespace", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
NamespaceID: 999999,
|
||||
}
|
||||
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
})
|
||||
t.Run("nonexistant owner", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
user := &User{ID: 9482385}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
usr := &user.User{ID: 9482385}
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
NamespaceID: 1,
|
||||
}
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
})
|
||||
t.Run("existing identifier", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
@ -73,7 +75,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
NamespaceID: 1,
|
||||
}
|
||||
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
||||
})
|
||||
@ -81,7 +83,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
|
||||
t.Run("update", func(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
ID: 1,
|
||||
Title: "test",
|
||||
@ -94,7 +96,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
|
||||
})
|
||||
t.Run("nonexistant", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
ID: 99999999,
|
||||
Title: "test",
|
||||
@ -105,7 +107,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
|
||||
})
|
||||
t.Run("existing identifier", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
Title: "test",
|
||||
Description: "Lorem Ipsum",
|
||||
@ -113,7 +115,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
NamespaceID: 1,
|
||||
}
|
||||
|
||||
err := list.Create(user)
|
||||
err := list.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
||||
})
|
||||
@ -121,7 +123,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestList_Delete(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
list := List{
|
||||
ID: 1,
|
||||
}
|
||||
@ -131,14 +133,16 @@ func TestList_Delete(t *testing.T) {
|
||||
|
||||
func TestList_ReadAll(t *testing.T) {
|
||||
t.Run("all in namespace", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
// Get all lists for our namespace
|
||||
lists, err := GetListsByNamespaceID(1, &User{})
|
||||
lists, err := GetListsByNamespaceID(1, &user.User{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(lists), 2)
|
||||
})
|
||||
t.Run("all lists for user", func(t *testing.T) {
|
||||
u := &User{ID: 1}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
u := &user.User{ID: 1}
|
||||
list := List{}
|
||||
lists3, _, _, err := list.ReadAll(u, "", 1, 50)
|
||||
|
||||
@ -148,10 +152,12 @@ func TestList_ReadAll(t *testing.T) {
|
||||
assert.Equal(t, 16, s.Len())
|
||||
})
|
||||
t.Run("lists for nonexistant user", func(t *testing.T) {
|
||||
user := &User{ID: 999999}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
usr := &user.User{ID: 999999}
|
||||
list := List{}
|
||||
_, _, _, err := list.ReadAll(user, "", 1, 50)
|
||||
_, _, _, err := list.ReadAll(usr, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
})
|
||||
}
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
package models
|
||||
|
||||
import "code.vikunja.io/web"
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
// ListUser represents a list <-> user relation
|
||||
type ListUser struct {
|
||||
@ -47,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
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
@ -48,7 +50,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
||||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
@ -58,7 +60,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
||||
ListID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
@ -68,13 +70,15 @@ func TestListUser_CanDoSomething(t *testing.T) {
|
||||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@ -58,7 +60,7 @@ func TestListUser_Create(t *testing.T) {
|
||||
name: "ListUsers Create for duplicate",
|
||||
fields: fields{
|
||||
Username: "user1",
|
||||
ListID: 2,
|
||||
ListID: 3,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserAlreadyHasAccess,
|
||||
@ -89,7 +91,7 @@ func TestListUser_Create(t *testing.T) {
|
||||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
name: "ListUsers Create with the owner as shared user",
|
||||
@ -103,6 +105,8 @@ func TestListUser_Create(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
ul := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
@ -155,11 +159,11 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: []*UserWithRight{
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -169,7 +173,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||
Right: RightRead,
|
||||
},
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -185,7 +189,7 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||
ListID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrNeedToHaveListReadAccess,
|
||||
@ -193,6 +197,8 @@ func TestListUser_ReadAll(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
ul := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
@ -271,6 +277,8 @@ func TestListUser_Update(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
@ -316,7 +324,7 @@ func TestListUser_Delete(t *testing.T) {
|
||||
ListID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
name: "Try deleting a user which does not has access but exists",
|
||||
@ -337,6 +345,8 @@ func TestListUser_Delete(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lu := &ListUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
@ -19,6 +19,7 @@ package models
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
@ -33,7 +34,9 @@ func TestMain(m *testing.M) {
|
||||
// Some tests use the file engine, so we'll need to initialize that
|
||||
files.InitTests()
|
||||
|
||||
SetupTests(config.ServiceRootpath.GetString())
|
||||
user.InitTests()
|
||||
|
||||
SetupTests()
|
||||
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
_ "github.com/go-sql-driver/mysql" // Because.
|
||||
"github.com/go-xorm/xorm"
|
||||
|
||||
@ -33,7 +34,7 @@ var (
|
||||
// GetTables returns all structs which are also a table.
|
||||
func GetTables() []interface{} {
|
||||
return []interface{}{
|
||||
&User{},
|
||||
&user.User{},
|
||||
&List{},
|
||||
&Task{},
|
||||
&Team{},
|
||||
|
@ -18,6 +18,7 @@ package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/imdario/mergo"
|
||||
"time"
|
||||
@ -34,7 +35,7 @@ type Namespace struct {
|
||||
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
|
||||
// The user who owns this namespace
|
||||
Owner *User `xorm:"-" json:"owner" valid:"-"`
|
||||
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
|
||||
|
||||
// A unix timestamp when this namespace was created. You cannot change this value.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
@ -97,7 +98,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
|
||||
}
|
||||
|
||||
// Get the namespace Owner
|
||||
namespace.Owner, err = GetUserByID(namespace.OwnerID)
|
||||
namespace.Owner, err = user.GetUserByID(namespace.OwnerID)
|
||||
return
|
||||
}
|
||||
|
||||
@ -115,7 +116,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
|
||||
// @Router /namespaces/{id} [get]
|
||||
func (n *Namespace) ReadOne() (err error) {
|
||||
// Get the namespace Owner
|
||||
n.Owner, err = GetUserByID(n.OwnerID)
|
||||
n.Owner, err = user.GetUserByID(n.OwnerID)
|
||||
return
|
||||
}
|
||||
|
||||
@ -143,7 +144,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
|
||||
return nil, 0, 0, ErrGenericForbidden{}
|
||||
}
|
||||
|
||||
doer, err := getUserWithError(a)
|
||||
doer, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
@ -176,7 +177,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
|
||||
}
|
||||
|
||||
// Get all users
|
||||
users := []*User{}
|
||||
users := []*user.User{}
|
||||
err = x.Select("users.*").
|
||||
Table("namespaces").
|
||||
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
|
||||
@ -301,7 +302,7 @@ func (n *Namespace) Create(a web.Auth) (err error) {
|
||||
n.ID = 0 // This would otherwise prevent the creation of new lists after one was created
|
||||
|
||||
// Check if the User exists
|
||||
n.Owner, err = GetUserByID(a.GetID())
|
||||
n.Owner, err = user.GetUserByID(a.GetID())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -343,7 +344,7 @@ func (n *Namespace) Delete() (err error) {
|
||||
}
|
||||
|
||||
// Delete all lists with their tasks
|
||||
lists, err := GetListsByNamespaceID(n.ID, &User{})
|
||||
lists, err := GetListsByNamespaceID(n.ID, &user.User{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -401,7 +402,7 @@ func (n *Namespace) Update() (err error) {
|
||||
// Check if the (new) owner exists
|
||||
n.OwnerID = n.Owner.ID
|
||||
if currentNamespace.OwnerID != n.OwnerID {
|
||||
n.Owner, err = GetUserByID(n.OwnerID)
|
||||
n.Owner, err = user.GetUserByID(n.OwnerID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
@ -48,7 +50,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
||||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
@ -58,7 +60,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
||||
NamespaceID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
@ -68,13 +70,15 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
|
||||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tn := &TeamNamespace{
|
||||
ID: tt.fields.ID,
|
||||
TeamID: tt.fields.TeamID,
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
@ -25,6 +27,8 @@ import (
|
||||
)
|
||||
|
||||
func TestTeamNamespace(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Dummy team <-> namespace relation
|
||||
tn := TeamNamespace{
|
||||
TeamID: 1,
|
||||
@ -32,7 +36,7 @@ func TestTeamNamespace(t *testing.T) {
|
||||
Right: RightAdmin,
|
||||
}
|
||||
|
||||
dummyuser, err := GetUserByID(1)
|
||||
dummyuser, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Test normal creation
|
||||
@ -80,7 +84,7 @@ func TestTeamNamespace(t *testing.T) {
|
||||
assert.True(t, IsErrNamespaceDoesNotExist(err))
|
||||
|
||||
// Check with no right to read the namespace
|
||||
nouser := &User{ID: 393}
|
||||
nouser := &user.User{ID: 393}
|
||||
_, _, _, err = tn.ReadAll(nouser, "", 1, 50)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNeedToHaveNamespaceReadAccess(err))
|
||||
@ -156,6 +160,8 @@ func TestTeamNamespace_Update(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tl := &TeamNamespace{
|
||||
ID: tt.fields.ID,
|
||||
TeamID: tt.fields.TeamID,
|
||||
|
@ -17,12 +17,16 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNamespace_Create(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Create test database
|
||||
//assert.NoError(t, LoadFixtures())
|
||||
|
||||
@ -33,7 +37,7 @@ func TestNamespace_Create(t *testing.T) {
|
||||
}
|
||||
|
||||
// Doer
|
||||
doer, err := GetUserByID(1)
|
||||
doer, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try creating it
|
||||
@ -57,11 +61,11 @@ func TestNamespace_Create(t *testing.T) {
|
||||
assert.True(t, IsErrNamespaceNameCannotBeEmpty(err))
|
||||
|
||||
// Try inserting one with a nonexistant user
|
||||
nUser := &User{ID: 9482385}
|
||||
nUser := &user.User{ID: 9482385}
|
||||
dnsp2 := dummynamespace
|
||||
err = dnsp2.Create(nUser)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
|
||||
// Update it
|
||||
allowed, err = dummynamespace.CanUpdate(doer)
|
||||
@ -85,7 +89,7 @@ func TestNamespace_Create(t *testing.T) {
|
||||
dummynamespace.Owner.ID = 94829838572
|
||||
err = dummynamespace.Update()
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
|
||||
// Try updating without a name
|
||||
dummynamespace.Name = ""
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
package models
|
||||
|
||||
import "code.vikunja.io/web"
|
||||
import (
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
// NamespaceUser represents a namespace <-> user relation
|
||||
type NamespaceUser struct {
|
||||
@ -75,7 +78,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
user, err := user2.GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -117,7 +120,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
|
||||
func (nu *NamespaceUser) Delete() (err error) {
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
user, err := user2.GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -213,7 +216,7 @@ func (nu *NamespaceUser) Update() (err error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(nu.Username)
|
||||
user, err := user2.GetUserByUsername(nu.Username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
@ -48,7 +50,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
||||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
@ -58,7 +60,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
||||
NamespaceID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
@ -68,13 +70,15 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
|
||||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"reflect"
|
||||
@ -56,7 +58,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
name: "NamespaceUsers Create for duplicate",
|
||||
fields: fields{
|
||||
Username: "user1",
|
||||
NamespaceID: 2,
|
||||
NamespaceID: 3,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserAlreadyHasNamespaceAccess,
|
||||
@ -87,7 +89,7 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
name: "NamespaceUsers Create with the owner as shared user",
|
||||
@ -101,6 +103,8 @@ func TestNamespaceUser_Create(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
un := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
@ -152,11 +156,11 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 3},
|
||||
a: &user.User{ID: 3},
|
||||
},
|
||||
want: []*UserWithRight{
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -166,7 +170,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||
Right: RightRead,
|
||||
},
|
||||
{
|
||||
User: User{
|
||||
User: user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -182,7 +186,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||
NamespaceID: 3,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrNeedToHaveNamespaceReadAccess,
|
||||
@ -190,6 +194,8 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
un := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
UserID: tt.fields.UserID,
|
||||
@ -269,6 +275,8 @@ func TestNamespaceUser_Update(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
@ -314,7 +322,7 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||
NamespaceID: 2,
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrUserDoesNotExist,
|
||||
errType: user.IsErrUserDoesNotExist,
|
||||
},
|
||||
{
|
||||
name: "Try deleting a user which does not has access but exists",
|
||||
@ -335,6 +343,8 @@ func TestNamespaceUser_Delete(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
nu := &NamespaceUser{
|
||||
ID: tt.fields.ID,
|
||||
Username: tt.fields.Username,
|
||||
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
@ -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:"-"`
|
||||
|
@ -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
|
||||
|
@ -20,6 +20,7 @@ package models
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io"
|
||||
"os"
|
||||
@ -95,7 +96,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
||||
tf := &testfile{
|
||||
content: []byte("testingstuff"),
|
||||
}
|
||||
testuser := &User{ID: 1}
|
||||
testuser := &user.User{ID: 1}
|
||||
|
||||
err := ta.NewAttachment(tf, "testfile", 100, testuser)
|
||||
assert.NoError(t, err)
|
||||
@ -119,7 +120,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
|
||||
func TestTaskAttachment_ReadAll(t *testing.T) {
|
||||
files.InitTestFileFixtures(t)
|
||||
ta := &TaskAttachment{TaskID: 1}
|
||||
as, _, _, err := ta.ReadAll(&User{ID: 1}, "", 0, 50)
|
||||
as, _, _, err := ta.ReadAll(&user.User{ID: 1}, "", 0, 50)
|
||||
attachments, _ := as.([]*TaskAttachment)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, attachments, 3)
|
||||
@ -152,7 +153,7 @@ func TestTaskAttachment_Delete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTaskAttachment_Rights(t *testing.T) {
|
||||
u := &User{ID: 1}
|
||||
u := &user.User{ID: 1}
|
||||
t.Run("Can Read", func(t *testing.T) {
|
||||
t.Run("Allowed", func(t *testing.T) {
|
||||
ta := &TaskAttachment{TaskID: 1}
|
||||
|
@ -18,6 +18,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"time"
|
||||
)
|
||||
@ -108,7 +109,7 @@ func (tf *TaskCollection) ReadAll(a web.Auth, search string, page int, perPage i
|
||||
// If the list ID is not set, we get all tasks for the user.
|
||||
// This allows to use this function in Task.ReadAll with a possibility to deprecate the latter at some point.
|
||||
if tf.ListID == 0 {
|
||||
tf.Lists, _, _, err = getRawListsForUser("", &User{ID: a.GetID()}, -1, 0)
|
||||
tf.Lists, _, _, err = getRawListsForUser("", &user.User{ID: a.GetID()}, -1, 0)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
@ -19,30 +19,28 @@ package models
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
assert.NoError(t, db.LoadFixtures())
|
||||
|
||||
// Dummy users
|
||||
user1 := &User{
|
||||
user1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
|
||||
}
|
||||
user2 := &User{
|
||||
user2 := &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
|
||||
}
|
||||
user6 := &User{
|
||||
user6 := &user.User{
|
||||
ID: 6,
|
||||
Username: "user6",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -463,7 +461,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
CreatedByID: 1,
|
||||
CreatedBy: user1,
|
||||
ListID: 1,
|
||||
Assignees: []*User{
|
||||
Assignees: []*user.User{
|
||||
user1,
|
||||
user2,
|
||||
},
|
||||
@ -538,7 +536,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
fields: fields{},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
@ -585,7 +583,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
@ -631,7 +629,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
@ -648,7 +646,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
@ -664,7 +662,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
},
|
||||
args: args{
|
||||
search: "",
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
page: 0,
|
||||
},
|
||||
want: []*Task{
|
||||
@ -677,6 +675,8 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
lt := &TaskCollection{
|
||||
ListID: tt.fields.ListID,
|
||||
StartDateSortUnix: tt.fields.StartDateSortUnix,
|
||||
|
@ -18,6 +18,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
@ -83,7 +84,7 @@ type TaskRelation struct {
|
||||
|
||||
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
|
||||
// The user who created this relation
|
||||
CreatedBy *User `xorm:"-" json:"created_by"`
|
||||
CreatedBy *user.User `xorm:"-" json:"created_by"`
|
||||
|
||||
// A unix timestamp when this label was created. You cannot change this value.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
|
@ -18,45 +18,55 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTaskRelation_Create(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 2,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Two Tasks In Different Lists", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 13,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Already Existing", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 29,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrRelationAlreadyExists(err))
|
||||
})
|
||||
t.Run("Same Task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 1,
|
||||
}
|
||||
err := rel.Create(&User{ID: 1})
|
||||
err := rel.Create(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrRelationTasksCannotBeTheSame(err))
|
||||
})
|
||||
@ -64,6 +74,8 @@ func TestTaskRelation_Create(t *testing.T) {
|
||||
|
||||
func TestTaskRelation_Delete(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 29,
|
||||
@ -73,6 +85,8 @@ func TestTaskRelation_Delete(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("Not existing", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 9999,
|
||||
OtherTaskID: 3,
|
||||
@ -86,73 +100,87 @@ func TestTaskRelation_Delete(t *testing.T) {
|
||||
|
||||
func TestTaskRelation_CanCreate(t *testing.T) {
|
||||
t.Run("Normal", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 2,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, can)
|
||||
})
|
||||
t.Run("Two tasks on different lists", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 13,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, can)
|
||||
})
|
||||
t.Run("No update rights on base task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 14,
|
||||
OtherTaskID: 1,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("No update rights on base task, but read rights", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 15,
|
||||
OtherTaskID: 1,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("No read rights on other task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 14,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("Nonexisting base task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 999999,
|
||||
OtherTaskID: 1,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTaskDoesNotExist(err))
|
||||
assert.False(t, can)
|
||||
})
|
||||
t.Run("Nonexisting other task", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
rel := TaskRelation{
|
||||
TaskID: 1,
|
||||
OtherTaskID: 999999,
|
||||
RelationKind: RelationKindSubtask,
|
||||
}
|
||||
can, err := rel.CanCreate(&User{ID: 1})
|
||||
can, err := rel.CanCreate(&user.User{ID: 1})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTaskDoesNotExist(err))
|
||||
assert.False(t, can)
|
||||
|
@ -19,6 +19,7 @@ package models
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/files"
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"code.vikunja.io/web"
|
||||
"github.com/imdario/mergo"
|
||||
@ -55,7 +56,7 @@ type Task struct {
|
||||
// When this task ends.
|
||||
EndDateUnix int64 `xorm:"int(11) INDEX null" json:"endDate" query:"-"`
|
||||
// An array of users who are assigned to this task
|
||||
Assignees []*User `xorm:"-" json:"assignees"`
|
||||
Assignees []*user.User `xorm:"-" json:"assignees"`
|
||||
// An array of labels which are associated with this task.
|
||||
Labels []*Label `xorm:"-" json:"labels"`
|
||||
// The task color in hex
|
||||
@ -87,7 +88,7 @@ type Task struct {
|
||||
Updated int64 `xorm:"updated not null" json:"updated"`
|
||||
|
||||
// The user who initially created the task.
|
||||
CreatedBy *User `xorm:"-" json:"createdBy" valid:"-"`
|
||||
CreatedBy *user.User `xorm:"-" json:"createdBy" valid:"-"`
|
||||
|
||||
web.CRUDable `xorm:"-" json:"-"`
|
||||
web.Rights `xorm:"-" json:"-"`
|
||||
@ -365,7 +366,7 @@ func addMoreInfoToTasks(taskMap map[int64]*Task) (tasks []*Task, err error) {
|
||||
|
||||
// Get all users of a task
|
||||
// aka the ones who created a task
|
||||
users := make(map[int64]*User)
|
||||
users := make(map[int64]*user.User)
|
||||
err = x.In("id", userIDs).Find(&users)
|
||||
if err != nil {
|
||||
return
|
||||
@ -487,7 +488,7 @@ func (t *Task) Create(a web.Auth) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
u, err := GetUserByID(a.GetID())
|
||||
u, err := user.GetUserByID(a.GetID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,12 +17,14 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTask_Create(t *testing.T) {
|
||||
user := &User{
|
||||
usr := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Email: "user1@example.com",
|
||||
@ -31,13 +33,13 @@ func TestTask_Create(t *testing.T) {
|
||||
// We only test creating a task here, the rights are all well tested in the integration tests.
|
||||
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
Text: "Lorem",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
ListID: 1,
|
||||
}
|
||||
err := task.Create(user)
|
||||
err := task.Create(usr)
|
||||
assert.NoError(t, err)
|
||||
// Assert getting a uid
|
||||
assert.NotEmpty(t, task.UID)
|
||||
@ -47,30 +49,30 @@ func TestTask_Create(t *testing.T) {
|
||||
|
||||
})
|
||||
t.Run("empty text", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
Text: "",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
ListID: 1,
|
||||
}
|
||||
err := task.Create(user)
|
||||
err := task.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrTaskCannotBeEmpty(err))
|
||||
})
|
||||
t.Run("nonexistant list", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
Text: "Test",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
ListID: 9999999,
|
||||
}
|
||||
err := task.Create(user)
|
||||
err := task.Create(usr)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrListDoesNotExist(err))
|
||||
})
|
||||
t.Run("noneixtant user", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
nUser := &User{ID: 99999999}
|
||||
db.LoadAndAssertFixtures(t)
|
||||
nUser := &user.User{ID: 99999999}
|
||||
task := &Task{
|
||||
Text: "Test",
|
||||
Description: "Lorem Ipsum Dolor",
|
||||
@ -78,13 +80,13 @@ func TestTask_Create(t *testing.T) {
|
||||
}
|
||||
err := task.Create(nUser)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTask_Update(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
ID: 1,
|
||||
Text: "test10000",
|
||||
@ -95,7 +97,7 @@ func TestTask_Update(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("nonexistant task", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
ID: 9999999,
|
||||
Text: "test10000",
|
||||
@ -110,7 +112,7 @@ func TestTask_Update(t *testing.T) {
|
||||
|
||||
func TestTask_Delete(t *testing.T) {
|
||||
t.Run("normal", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{
|
||||
ID: 1,
|
||||
}
|
||||
@ -121,12 +123,14 @@ func TestTask_Delete(t *testing.T) {
|
||||
|
||||
func TestUpdateDone(t *testing.T) {
|
||||
t.Run("marking a task as done", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
oldTask := &Task{Done: false}
|
||||
newTask := &Task{Done: true}
|
||||
updateDone(oldTask, newTask)
|
||||
assert.NotEqual(t, int64(0), oldTask.DoneAtUnix)
|
||||
})
|
||||
t.Run("unmarking a task as done", func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
oldTask := &Task{Done: true}
|
||||
newTask := &Task{Done: false}
|
||||
updateDone(oldTask, newTask)
|
||||
@ -136,14 +140,14 @@ func TestUpdateDone(t *testing.T) {
|
||||
|
||||
func TestTask_ReadOne(t *testing.T) {
|
||||
t.Run("default", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{ID: 1}
|
||||
err := task.ReadOne()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "task #1", task.Text)
|
||||
})
|
||||
t.Run("nonexisting", func(t *testing.T) {
|
||||
initFixtures(t)
|
||||
db.LoadAndAssertFixtures(t)
|
||||
task := &Task{ID: 99999}
|
||||
err := task.ReadOne()
|
||||
assert.Error(t, err)
|
||||
|
@ -16,7 +16,10 @@
|
||||
|
||||
package models
|
||||
|
||||
import "code.vikunja.io/web"
|
||||
import (
|
||||
user2 "code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
// Create implements the create method to assign a user to a team
|
||||
// @Summary Add a user to a team
|
||||
@ -41,7 +44,7 @@ func (tm *TeamMember) Create(a web.Auth) (err error) {
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(tm.Username)
|
||||
user, err := user2.GetUserByUsername(tm.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -84,7 +87,7 @@ func (tm *TeamMember) Delete() (err error) {
|
||||
}
|
||||
|
||||
// Find the numeric user id
|
||||
user, err := GetUserByUsername(tm.Username)
|
||||
user, err := user2.GetUserByUsername(tm.Username)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -17,11 +17,14 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTeamMember_Create(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
// Dummy team member
|
||||
dummyteammember := TeamMember{
|
||||
@ -30,7 +33,7 @@ func TestTeamMember_Create(t *testing.T) {
|
||||
}
|
||||
|
||||
// Doer
|
||||
doer, err := GetUserByID(1)
|
||||
doer, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Insert a new team member
|
||||
@ -71,7 +74,7 @@ func TestTeamMember_Create(t *testing.T) {
|
||||
dummyteammember.Username = "user9484"
|
||||
err = dummyteammember.Create(doer)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
assert.True(t, user.IsErrUserDoesNotExist(err))
|
||||
|
||||
// Try adding a user to a team which does not exist
|
||||
tm = TeamMember{TeamID: 94824, Username: "user1"}
|
||||
|
@ -18,6 +18,7 @@ package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/web"
|
||||
)
|
||||
|
||||
@ -32,7 +33,7 @@ type Team struct {
|
||||
CreatedByID int64 `xorm:"int(11) not null INDEX" json:"-"`
|
||||
|
||||
// The user who created this team.
|
||||
CreatedBy *User `xorm:"-" json:"createdBy"`
|
||||
CreatedBy *user.User `xorm:"-" json:"createdBy"`
|
||||
// An array of all members in this team.
|
||||
Members []*TeamUser `xorm:"-" json:"members"`
|
||||
|
||||
@ -53,7 +54,7 @@ func (Team) TableName() string {
|
||||
// AfterLoad gets the created by user object
|
||||
func (t *Team) AfterLoad() {
|
||||
// Get the owner
|
||||
t.CreatedBy, _ = GetUserByID(t.CreatedByID)
|
||||
t.CreatedBy, _ = user.GetUserByID(t.CreatedByID)
|
||||
|
||||
// Get all members
|
||||
x.Select("*").
|
||||
@ -90,7 +91,7 @@ func (TeamMember) TableName() string {
|
||||
|
||||
// TeamUser is the team member type
|
||||
type TeamUser struct {
|
||||
User `xorm:"extends"`
|
||||
user.User `xorm:"extends"`
|
||||
// Whether or not the member is an admin of the team. See the docs for more about what a team admin can do
|
||||
Admin bool `json:"admin"`
|
||||
}
|
||||
@ -181,7 +182,7 @@ func (t *Team) ReadAll(a web.Auth, search string, page int, perPage int) (result
|
||||
// @Failure 500 {object} models.Message "Internal error"
|
||||
// @Router /teams [put]
|
||||
func (t *Team) Create(a web.Auth) (err error) {
|
||||
doer, err := getUserWithError(a)
|
||||
doer, err := user.GetFromAuth(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/web"
|
||||
@ -28,7 +30,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||
Name string
|
||||
Description string
|
||||
CreatedByID int64
|
||||
CreatedBy *User
|
||||
CreatedBy *user.User
|
||||
Members []*TeamUser
|
||||
Created int64
|
||||
Updated int64
|
||||
@ -50,7 +52,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||
ID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "IsAdmin": true, "CanRead": true, "CanDelete": true, "CanUpdate": true},
|
||||
},
|
||||
@ -60,7 +62,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||
ID: 300,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 1},
|
||||
a: &user.User{ID: 1},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
@ -70,13 +72,15 @@ func TestTeam_CanDoSomething(t *testing.T) {
|
||||
ID: 1,
|
||||
},
|
||||
args: args{
|
||||
a: &User{ID: 4},
|
||||
a: &user.User{ID: 4},
|
||||
},
|
||||
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
tm := &Team{
|
||||
ID: tt.fields.ID,
|
||||
Name: tt.fields.Name,
|
||||
|
@ -17,6 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
@ -30,7 +31,7 @@ func TestTeam_Create(t *testing.T) {
|
||||
}
|
||||
|
||||
// Doer
|
||||
doer, err := GetUserByID(1)
|
||||
doer, err := user.GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Insert it
|
||||
|
@ -17,78 +17,49 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
_ "code.vikunja.io/api/pkg/config" // To trigger its init() which initializes the config
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/mail"
|
||||
"fmt"
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/testfixtures.v2"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// SetupTests takes care of seting up the db, fixtures etc.
|
||||
// This is an extra function to be able to call the fixtures setup from the integration tests.
|
||||
func SetupTests(pathToRoot string) {
|
||||
func SetupTests() {
|
||||
var err error
|
||||
fixturesDir := filepath.Join(pathToRoot, "pkg", "models", "fixtures")
|
||||
if err = createTestEngine(fixturesDir); err != nil {
|
||||
log.Fatalf("Error creating test engine: %v\n", err)
|
||||
x, err = db.CreateTestEngine()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = x.Sync2(GetTables()...)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = db.InitTestFixtures(
|
||||
"files",
|
||||
"label_task",
|
||||
"labels",
|
||||
"link_sharing",
|
||||
"list",
|
||||
"namespaces",
|
||||
"task_assignees",
|
||||
"task_attachments",
|
||||
"task_relations",
|
||||
"task_reminders",
|
||||
"tasks",
|
||||
"team_list",
|
||||
"team_members",
|
||||
"team_namespaces",
|
||||
"teams",
|
||||
"users",
|
||||
"users_list",
|
||||
"users_namespace")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Start the pseudo mail queue
|
||||
mail.StartMailDaemon()
|
||||
|
||||
// Create test database
|
||||
if err = db.LoadFixtures(); err != nil {
|
||||
log.Fatalf("Error preparing test database: %v", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func createTestEngine(fixturesDir string) error {
|
||||
var err error
|
||||
var fixturesHelper testfixtures.Helper = &testfixtures.SQLite{}
|
||||
// If set, use the config we provided instead of normal
|
||||
if os.Getenv("VIKUNJA_TESTS_USE_CONFIG") == "1" {
|
||||
x, err = db.CreateTestEngine()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting test engine: %v", err)
|
||||
}
|
||||
|
||||
err = initSchema(x)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.DatabaseType.GetString() == "mysql" {
|
||||
fixturesHelper = &testfixtures.MySQL{}
|
||||
}
|
||||
} else {
|
||||
x, err = db.CreateTestEngine()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting test engine: %v", err)
|
||||
}
|
||||
|
||||
// Sync dat shit
|
||||
err = initSchema(x)
|
||||
if err != nil {
|
||||
return fmt.Errorf("sync database struct error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return db.InitFixtures(fixturesHelper, fixturesDir)
|
||||
}
|
||||
|
||||
func initSchema(tx *xorm.Engine) error {
|
||||
return tx.Sync2(GetTables()...)
|
||||
}
|
||||
|
||||
func initFixtures(t *testing.T) {
|
||||
// Init db fixtures
|
||||
err := db.LoadFixtures()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@ -1,383 +0,0 @@
|
||||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/mail"
|
||||
"code.vikunja.io/api/pkg/metrics"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"code.vikunja.io/web"
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/labstack/echo/v4"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// UserLogin Object to recive user credentials in JSON format
|
||||
type UserLogin struct {
|
||||
// The username used to log in.
|
||||
Username string `json:"username"`
|
||||
// The password for the user.
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// User holds information about an user
|
||||
type User struct {
|
||||
// The unique, numeric id of this user.
|
||||
ID int64 `xorm:"int(11) autoincr not null unique pk" json:"id"`
|
||||
// The username of the user. Is always unique.
|
||||
Username string `xorm:"varchar(250) not null unique" json:"username" valid:"length(3|250)" minLength:"3" maxLength:"250"`
|
||||
Password string `xorm:"varchar(250) not null" json:"-"`
|
||||
// The user's email address.
|
||||
Email string `xorm:"varchar(250) null" json:"email,omitempty" valid:"email,length(0|250)" maxLength:"250"`
|
||||
IsActive bool `xorm:"null" json:"-"`
|
||||
// The users md5-hashed email address, used to get the avatar from gravatar and the likes.
|
||||
AvatarURL string `xorm:"-" json:"avatarUrl"`
|
||||
|
||||
PasswordResetToken string `xorm:"varchar(450) null" json:"-"`
|
||||
EmailConfirmToken string `xorm:"varchar(450) null" json:"-"`
|
||||
|
||||
// A unix timestamp when this task was created. You cannot change this value.
|
||||
Created int64 `xorm:"created not null" json:"created"`
|
||||
// A unix timestamp when this task was last updated. You cannot change this value.
|
||||
Updated int64 `xorm:"updated not null" json:"updated"`
|
||||
|
||||
web.Auth `xorm:"-" json:"-"`
|
||||
}
|
||||
|
||||
// AfterLoad is used to delete all emails to not have them leaked to the user
|
||||
func (u *User) AfterLoad() {
|
||||
u.AvatarURL = utils.Md5String(u.Email)
|
||||
}
|
||||
|
||||
// GetID implements the Auth interface
|
||||
func (u *User) GetID() int64 {
|
||||
return u.ID
|
||||
}
|
||||
|
||||
// TableName returns the table name for users
|
||||
func (User) TableName() string {
|
||||
return "users"
|
||||
}
|
||||
|
||||
func getUserWithError(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))
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// APIUserPassword represents a user object without timestamps and a json password field.
|
||||
type APIUserPassword struct {
|
||||
// The unique, numeric id of this user.
|
||||
ID int64 `json:"id"`
|
||||
// The username of the username. Is always unique.
|
||||
Username string `json:"username" valid:"length(3|250)" minLength:"3" maxLength:"250"`
|
||||
// The user's password in clear text. Only used when registering the user.
|
||||
Password string `json:"password" valid:"length(8|250)" minLength:"8" maxLength:"250"`
|
||||
// The user's email address
|
||||
Email string `json:"email" valid:"email,length(0|250)" maxLength:"250"`
|
||||
}
|
||||
|
||||
// APIFormat formats an API User into a normal user struct
|
||||
func (apiUser *APIUserPassword) APIFormat() *User {
|
||||
return &User{
|
||||
ID: apiUser.ID,
|
||||
Username: apiUser.Username,
|
||||
Password: apiUser.Password,
|
||||
Email: apiUser.Email,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserByID gets informations about a user by its ID
|
||||
func GetUserByID(id int64) (user *User, err error) {
|
||||
// Apparently xorm does otherwise look for all users but return only one, which leads to returing one even if the ID is 0
|
||||
if id < 1 {
|
||||
return &User{}, ErrUserDoesNotExist{}
|
||||
}
|
||||
|
||||
return GetUser(&User{ID: id})
|
||||
}
|
||||
|
||||
// GetUserByUsername gets a user from its user name. This is an extra function to be able to add an extra error check.
|
||||
func GetUserByUsername(username string) (user *User, err error) {
|
||||
if username == "" {
|
||||
return &User{}, ErrUserDoesNotExist{}
|
||||
}
|
||||
|
||||
return GetUser(&User{Username: username})
|
||||
}
|
||||
|
||||
// GetUser gets a user object
|
||||
func GetUser(user *User) (userOut *User, err error) {
|
||||
return getUser(user, false)
|
||||
}
|
||||
|
||||
// GetUserWithEmail returns a user object with email
|
||||
func GetUserWithEmail(user *User) (userOut *User, err error) {
|
||||
return getUser(user, true)
|
||||
}
|
||||
|
||||
// getUser is a small helper function to avoid having duplicated code for almost the same use case
|
||||
func getUser(user *User, withEmail bool) (userOut *User, err error) {
|
||||
userOut = &User{} // To prevent a panic if user is nil
|
||||
*userOut = *user
|
||||
exists, err := x.Get(userOut)
|
||||
|
||||
if !exists {
|
||||
return &User{}, ErrUserDoesNotExist{UserID: user.ID}
|
||||
}
|
||||
|
||||
if !withEmail {
|
||||
userOut.Email = ""
|
||||
}
|
||||
|
||||
return userOut, err
|
||||
}
|
||||
|
||||
// CheckUserCredentials checks user credentials
|
||||
func CheckUserCredentials(u *UserLogin) (*User, error) {
|
||||
// Check if we have any credentials
|
||||
if u.Password == "" || u.Username == "" {
|
||||
return &User{}, ErrNoUsernamePassword{}
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserByUsername(u.Username)
|
||||
if err != nil {
|
||||
// hashing the password takes a long time, so we hash something to not make it clear if the username was wrong
|
||||
bcrypt.GenerateFromPassword([]byte(u.Username), 14)
|
||||
return &User{}, ErrWrongUsernameOrPassword{}
|
||||
}
|
||||
|
||||
// User is invalid if it needs to verify its email address
|
||||
if !user.IsActive {
|
||||
return &User{}, ErrEmailNotConfirmed{UserID: user.ID}
|
||||
}
|
||||
|
||||
// Check the users password
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(u.Password))
|
||||
if err != nil {
|
||||
if err == bcrypt.ErrMismatchedHashAndPassword {
|
||||
return &User{}, ErrWrongUsernameOrPassword{}
|
||||
}
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
// GetCurrentUser returns the current user based on its jwt token
|
||||
func GetCurrentUser(c echo.Context) (user *User, err error) {
|
||||
jwtinf := c.Get("user").(*jwt.Token)
|
||||
claims := jwtinf.Claims.(jwt.MapClaims)
|
||||
return GetUserFromClaims(claims)
|
||||
}
|
||||
|
||||
// GetUserFromClaims Returns a new user from jwt claims
|
||||
func GetUserFromClaims(claims jwt.MapClaims) (user *User, err error) {
|
||||
userID, ok := claims["id"].(float64)
|
||||
if !ok {
|
||||
return user, ErrCouldNotGetUserID{}
|
||||
}
|
||||
user = &User{
|
||||
ID: int64(userID),
|
||||
Email: claims["email"].(string),
|
||||
Username: claims["username"].(string),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CreateUser creates a new user and inserts it into the database
|
||||
func CreateUser(user *User) (newUser *User, err error) {
|
||||
|
||||
newUser = user
|
||||
|
||||
// Check if we have all needed informations
|
||||
if newUser.Password == "" || newUser.Username == "" || newUser.Email == "" {
|
||||
return &User{}, ErrNoUsernamePassword{}
|
||||
}
|
||||
|
||||
// Check if the user already existst with that username
|
||||
exists := true
|
||||
_, err = GetUserByUsername(newUser.Username)
|
||||
if err != nil {
|
||||
if IsErrUserDoesNotExist(err) {
|
||||
exists = false
|
||||
} else {
|
||||
return &User{}, err
|
||||
}
|
||||
}
|
||||
if exists {
|
||||
return &User{}, ErrUsernameExists{newUser.ID, newUser.Username}
|
||||
}
|
||||
|
||||
// Check if the user already existst with that email
|
||||
exists = true
|
||||
_, err = GetUser(&User{Email: newUser.Email})
|
||||
if err != nil {
|
||||
if IsErrUserDoesNotExist(err) {
|
||||
exists = false
|
||||
} else {
|
||||
return &User{}, err
|
||||
}
|
||||
}
|
||||
if exists {
|
||||
return &User{}, ErrUserEmailExists{newUser.ID, newUser.Email}
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
newUser.Password, err = hashPassword(user.Password)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
newUser.IsActive = true
|
||||
if config.MailerEnabled.GetBool() {
|
||||
// The new user should not be activated until it confirms his mail address
|
||||
newUser.IsActive = false
|
||||
// Generate a confirm token
|
||||
newUser.EmailConfirmToken = utils.MakeRandomString(400)
|
||||
}
|
||||
|
||||
// Insert it
|
||||
_, err = x.Insert(newUser)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
// Update the metrics
|
||||
metrics.UpdateCount(1, metrics.ActiveUsersKey)
|
||||
|
||||
// Get the full new User
|
||||
newUserOut, err := GetUser(newUser)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// Send the user a mail with a link to confirm the mail
|
||||
data := map[string]interface{}{
|
||||
"User": newUserOut,
|
||||
}
|
||||
|
||||
mail.SendMailWithTemplate(user.Email, newUserOut.Username+" + Vikunja = <3", "confirm-email", data)
|
||||
|
||||
return newUserOut, err
|
||||
}
|
||||
|
||||
// HashPassword hashes a password
|
||||
func hashPassword(password string) (string, error) {
|
||||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 11)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
// UpdateUser updates a user
|
||||
func UpdateUser(user *User) (updatedUser *User, err error) {
|
||||
|
||||
// Check if it exists
|
||||
theUser, err := GetUserByID(user.ID)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
// Check if we have at least a username
|
||||
if user.Username == "" {
|
||||
//return User{}, ErrNoUsername{user.ID}
|
||||
user.Username = theUser.Username // Dont change the username if we dont have one
|
||||
}
|
||||
|
||||
user.Password = theUser.Password // set the password to the one in the database to not accedently resetting it
|
||||
|
||||
// Update it
|
||||
_, err = x.Id(user.ID).Update(user)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
// Get the newly updated user
|
||||
updatedUser, err = GetUserByID(user.ID)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
return updatedUser, err
|
||||
}
|
||||
|
||||
// UpdateUserPassword updates the password of a user
|
||||
func UpdateUserPassword(user *User, newPassword string) (err error) {
|
||||
|
||||
if newPassword == "" {
|
||||
return ErrEmptyNewPassword{}
|
||||
}
|
||||
|
||||
// Get all user details
|
||||
theUser, err := GetUserByID(user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Hash the new password and set it
|
||||
hashed, err := hashPassword(newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
theUser.Password = hashed
|
||||
|
||||
// Update it
|
||||
_, err = x.Id(user.ID).Update(theUser)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
// EmailConfirm holds the token to confirm a mail address
|
||||
type EmailConfirm struct {
|
||||
// The email confirm token sent via email.
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
// UserEmailConfirm handles the confirmation of an email address
|
||||
func UserEmailConfirm(c *EmailConfirm) (err error) {
|
||||
|
||||
// Check if we have an email confirm token
|
||||
if c.Token == "" {
|
||||
return ErrInvalidEmailConfirmToken{}
|
||||
}
|
||||
|
||||
// Check if the token is valid
|
||||
user := User{}
|
||||
has, err := x.Where("email_confirm_token = ?", c.Token).Get(&user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !has {
|
||||
return ErrInvalidEmailConfirmToken{Token: c.Token}
|
||||
}
|
||||
|
||||
user.IsActive = true
|
||||
user.EmailConfirmToken = ""
|
||||
_, err = x.Where("id = ?", user.ID).Cols("is_active", "email_confirm_token").Update(&user)
|
||||
return
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestUserEmailConfirm(t *testing.T) {
|
||||
type args struct {
|
||||
c *EmailConfirm
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
errType func(error) bool
|
||||
}{
|
||||
{
|
||||
name: "Test Empty token",
|
||||
args: args{
|
||||
c: &EmailConfirm{
|
||||
Token: "",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrInvalidEmailConfirmToken,
|
||||
},
|
||||
{
|
||||
name: "Test invalid token",
|
||||
args: args{
|
||||
c: &EmailConfirm{
|
||||
Token: "invalid",
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
errType: IsErrInvalidEmailConfirmToken,
|
||||
},
|
||||
{
|
||||
name: "Test valid token",
|
||||
args: args{
|
||||
c: &EmailConfirm{
|
||||
Token: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,40 +1,26 @@
|
||||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// This file is part of Vikunja.
|
||||
//
|
||||
// Vikunja is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// Vikunja is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import "github.com/go-xorm/builder"
|
||||
|
||||
// ListUsers returns a list with all users, filtered by an optional searchstring
|
||||
func ListUsers(searchterm string) (users []User, err error) {
|
||||
|
||||
if searchterm == "" {
|
||||
err = x.Find(&users)
|
||||
} else {
|
||||
err = x.
|
||||
Where("username LIKE ?", "%"+searchterm+"%").
|
||||
Find(&users)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return []User{}, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"github.com/go-xorm/builder"
|
||||
)
|
||||
|
||||
// ListUIDs hold all kinds of user IDs from accounts who have somehow access to a list
|
||||
type ListUIDs struct {
|
||||
@ -47,7 +33,7 @@ type ListUIDs struct {
|
||||
}
|
||||
|
||||
// ListUsersFromList returns a list with all users who have access to a list, regardless of the method which gave them access
|
||||
func ListUsersFromList(l *List, search string) (users []*User, err error) {
|
||||
func ListUsersFromList(l *List, search string) (users []*user.User, err error) {
|
||||
|
||||
userids := []*ListUIDs{}
|
||||
|
@ -1,117 +0,0 @@
|
||||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/mail"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
)
|
||||
|
||||
// PasswordReset holds the data to reset a password
|
||||
type PasswordReset struct {
|
||||
// The previously issued reset token.
|
||||
Token string `json:"token"`
|
||||
// The new password for this user.
|
||||
NewPassword string `json:"new_password"`
|
||||
}
|
||||
|
||||
// UserPasswordReset resets a users password
|
||||
func UserPasswordReset(reset *PasswordReset) (err error) {
|
||||
|
||||
// Check if the password is not empty
|
||||
if reset.NewPassword == "" {
|
||||
return ErrNoUsernamePassword{}
|
||||
}
|
||||
|
||||
// Check if we have a token
|
||||
var user User
|
||||
exists, err := x.Where("password_reset_token = ?", reset.Token).Get(&user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return ErrInvalidPasswordResetToken{Token: reset.Token}
|
||||
}
|
||||
|
||||
// Hash the password
|
||||
user.Password, err = hashPassword(reset.NewPassword)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Save it
|
||||
_, err = x.Where("id = ?", user.ID).Update(&user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Dont send a mail if we're testing
|
||||
if !config.MailerEnabled.GetBool() {
|
||||
return
|
||||
}
|
||||
|
||||
// Send a mail to the user to notify it his password was changed.
|
||||
data := map[string]interface{}{
|
||||
"User": user,
|
||||
}
|
||||
|
||||
mail.SendMailWithTemplate(user.Email, "Your password on Vikunja was changed", "password-changed", data)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// PasswordTokenRequest defines the request format for password reset resqest
|
||||
type PasswordTokenRequest struct {
|
||||
Email string `json:"email" valid:"email,length(0|250)" maxLength:"250"`
|
||||
}
|
||||
|
||||
// RequestUserPasswordResetToken inserts a random token to reset a users password into the databsse
|
||||
func RequestUserPasswordResetToken(tr *PasswordTokenRequest) (err error) {
|
||||
if tr.Email == "" {
|
||||
return ErrNoUsernamePassword{}
|
||||
}
|
||||
|
||||
// Check if the user exists
|
||||
user, err := GetUserWithEmail(&User{Email: tr.Email})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Generate a token and save it
|
||||
user.PasswordResetToken = utils.MakeRandomString(400)
|
||||
|
||||
// Save it
|
||||
_, err = x.Where("id = ?", user.ID).Update(user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Dont send a mail if we're testing
|
||||
if !config.MailerEnabled.GetBool() {
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"User": user,
|
||||
}
|
||||
|
||||
// Send the user a mail with the reset token
|
||||
mail.SendMailWithTemplate(user.Email, "Reset your password on Vikunja", "reset-password", data)
|
||||
return
|
||||
}
|
@ -1,178 +0,0 @@
|
||||
// Vikunja is a todo-list application to facilitate your life.
|
||||
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCreateUser(t *testing.T) {
|
||||
// Create test database
|
||||
//assert.NoError(t, LoadFixtures())
|
||||
|
||||
// Get our doer
|
||||
doer, err := GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Our dummy user for testing
|
||||
dummyuser := &User{
|
||||
Username: "testuu",
|
||||
Password: "1234",
|
||||
Email: "noone@example.com",
|
||||
}
|
||||
|
||||
// Create a new user
|
||||
createdUser, err := CreateUser(dummyuser)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Create a second new user
|
||||
_, err = CreateUser(&User{Username: dummyuser.Username + "2", Email: dummyuser.Email + "m", Password: dummyuser.Password})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check if it fails to create the same user again
|
||||
_, err = CreateUser(dummyuser)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Check if it fails to create a user with just the same username
|
||||
_, err = CreateUser(&User{Username: dummyuser.Username, Password: "12345", Email: "email@example.com"})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUsernameExists(err))
|
||||
|
||||
// Check if it fails to create one with the same email
|
||||
_, err = CreateUser(&User{Username: "noone", Password: "1234", Email: dummyuser.Email})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserEmailExists(err))
|
||||
|
||||
// Check if it fails to create a user without password and username
|
||||
_, err = CreateUser(&User{})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrNoUsernamePassword(err))
|
||||
|
||||
// Check if he exists
|
||||
theuser, err := GetUser(createdUser)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get by his ID
|
||||
_, err = GetUserByID(theuser.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Passing 0 as ID should return an error
|
||||
_, err = GetUserByID(0)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
|
||||
// Check the user credentials with an unverified email
|
||||
_, err = CheckUserCredentials(&UserLogin{"user5", "1234"})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrEmailNotConfirmed(err))
|
||||
|
||||
// Update everything and check again
|
||||
_, err = x.Cols("is_active").Where("true").Update(User{IsActive: true})
|
||||
assert.NoError(t, err)
|
||||
user, err := CheckUserCredentials(&UserLogin{"testuu", "1234"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "testuu", user.Username)
|
||||
|
||||
// Check wrong password (should also fail)
|
||||
_, err = CheckUserCredentials(&UserLogin{"testuu", "12345"})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrWrongUsernameOrPassword(err))
|
||||
|
||||
// Check usercredentials for a nonexistent user (should fail)
|
||||
_, err = CheckUserCredentials(&UserLogin{"dfstestuu", "1234"})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrWrongUsernameOrPassword(err))
|
||||
|
||||
// Update the user
|
||||
uuser, err := UpdateUser(&User{ID: theuser.ID, Password: "444444"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, theuser.Password, uuser.Password) // Password should not change
|
||||
assert.Equal(t, theuser.Username, uuser.Username) // Username should not change either
|
||||
|
||||
// Try updating one which does not exist
|
||||
_, err = UpdateUser(&User{ID: 99999, Username: "dg"})
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
|
||||
// Update a users password
|
||||
newpassword := "55555"
|
||||
err = UpdateUserPassword(theuser, newpassword)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check if it was changed
|
||||
_, err = CheckUserCredentials(&UserLogin{theuser.Username, newpassword})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Check if the searchterm works
|
||||
all, err := ListUsers("test")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, len(all) > 0)
|
||||
|
||||
all, err = ListUsers("")
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, len(all) > 0)
|
||||
|
||||
// Try updating the password of a nonexistent user (should fail)
|
||||
err = UpdateUserPassword(&User{ID: 9999}, newpassword)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrUserDoesNotExist(err))
|
||||
|
||||
// Delete it
|
||||
err = DeleteUserByID(theuser.ID, doer)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try deleting one with ID = 0
|
||||
err = DeleteUserByID(0, doer)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrIDCannotBeZero(err))
|
||||
}
|
||||
|
||||
func TestUserPasswordReset(t *testing.T) {
|
||||
// Request a new token
|
||||
tr := &PasswordTokenRequest{
|
||||
Email: "user1@example.com",
|
||||
}
|
||||
err := RequestUserPasswordResetToken(tr)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get the token / inside the user object
|
||||
userWithToken, err := GetUserByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try resetting it
|
||||
reset := &PasswordReset{
|
||||
Token: userWithToken.PasswordResetToken,
|
||||
}
|
||||
|
||||
// Try resetting it without a password
|
||||
reset.NewPassword = ""
|
||||
err = UserPasswordReset(reset)
|
||||
assert.True(t, IsErrNoUsernamePassword(err))
|
||||
|
||||
// Reset it
|
||||
reset.NewPassword = "1234"
|
||||
err = UserPasswordReset(reset)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Try resetting it with a wrong token
|
||||
reset.Token = utils.MakeRandomString(400)
|
||||
err = UserPasswordReset(reset)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrInvalidPasswordResetToken(err))
|
||||
}
|
@ -1,38 +1,51 @@
|
||||
// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved.
|
||||
//
|
||||
// This file is part of Vikunja.
|
||||
//
|
||||
// Vikunja is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vikunja is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListUsersFromList(t *testing.T) {
|
||||
|
||||
err := db.LoadFixtures()
|
||||
assert.NoError(t, err)
|
||||
|
||||
testuser1 := &User{
|
||||
testuser1 := &user.User{
|
||||
ID: 1,
|
||||
Username: "user1",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808",
|
||||
}
|
||||
testuser2 := &User{
|
||||
testuser2 := &user.User{
|
||||
ID: 2,
|
||||
Username: "user2",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
}
|
||||
testuser3 := &User{
|
||||
testuser3 := &user.User{
|
||||
ID: 3,
|
||||
Username: "user3",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
AvatarURL: "97d6d9441ff85fdc730e02a6068d267b",
|
||||
PasswordResetToken: "passwordresettesttoken",
|
||||
}
|
||||
testuser4 := &User{
|
||||
testuser4 := &user.User{
|
||||
ID: 4,
|
||||
Username: "user4",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -40,7 +53,7 @@ func TestListUsersFromList(t *testing.T) {
|
||||
AvatarURL: "7e65550957227bd38fe2d7fbc6fd2f7b",
|
||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||
}
|
||||
testuser5 := &User{
|
||||
testuser5 := &user.User{
|
||||
ID: 5,
|
||||
Username: "user5",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -48,56 +61,56 @@ func TestListUsersFromList(t *testing.T) {
|
||||
AvatarURL: "cfa35b8cd2ec278026357769582fa563",
|
||||
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
|
||||
}
|
||||
testuser6 := &User{
|
||||
testuser6 := &user.User{
|
||||
ID: 6,
|
||||
Username: "user6",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed",
|
||||
}
|
||||
testuser7 := &User{
|
||||
testuser7 := &user.User{
|
||||
ID: 7,
|
||||
Username: "user7",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "e80a711d4de44c30054806ebbd488464",
|
||||
}
|
||||
testuser8 := &User{
|
||||
testuser8 := &user.User{
|
||||
ID: 8,
|
||||
Username: "user8",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "2b9b320416cd31020bb6844c3fadefd1",
|
||||
}
|
||||
testuser9 := &User{
|
||||
testuser9 := &user.User{
|
||||
ID: 9,
|
||||
Username: "user9",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "f784fdb21d26dd2c64f5135f35ec401f",
|
||||
}
|
||||
testuser10 := &User{
|
||||
testuser10 := &user.User{
|
||||
ID: 10,
|
||||
Username: "user10",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "fce8ff4ff56d75ad587d1bbaa5ef0563",
|
||||
}
|
||||
testuser11 := &User{
|
||||
testuser11 := &user.User{
|
||||
ID: 11,
|
||||
Username: "user11",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "ad6d67d0c4495e186010732a7d360028",
|
||||
}
|
||||
testuser12 := &User{
|
||||
testuser12 := &user.User{
|
||||
ID: 12,
|
||||
Username: "user12",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
IsActive: true,
|
||||
AvatarURL: "ef1debc1364806281c42eeedfdeb943b",
|
||||
}
|
||||
testuser13 := &User{
|
||||
testuser13 := &user.User{
|
||||
ID: 13,
|
||||
Username: "user13",
|
||||
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
|
||||
@ -112,19 +125,19 @@ func TestListUsersFromList(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantUsers []*User
|
||||
wantUsers []*user.User
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Check owner only",
|
||||
args: args{l: &List{ID: 18, OwnerID: 7}},
|
||||
wantUsers: []*User{testuser7},
|
||||
wantUsers: []*user.User{testuser7},
|
||||
},
|
||||
{
|
||||
// This list has another different user shared for each possible method
|
||||
name: "Check with owner and other users",
|
||||
args: args{l: &List{ID: 19, OwnerID: 7}},
|
||||
wantUsers: []*User{
|
||||
wantUsers: []*user.User{
|
||||
testuser1, // Shared Via Team readonly
|
||||
testuser2, // Shared Via Team write
|
||||
testuser3, // Shared Via Team admin
|
||||
@ -147,6 +160,8 @@ func TestListUsersFromList(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
|
||||
gotUsers, err := ListUsersFromList(tt.args.l, tt.args.search)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ListUsersFromList() error = %v, wantErr %v", err, tt.wantErr)
|
||||
|
Reference in New Issue
Block a user