Refactor User and DB handling #123

Merged
konrad merged 19 commits from refactor/user into master 2020-01-26 17:08:08 +00:00
69 changed files with 755 additions and 665 deletions
Showing only changes of commit 47d025cf07 - Show all commits

View File

@ -17,7 +17,7 @@
package caldav
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"fmt"
"strconv"
@ -49,7 +49,7 @@ type Todo struct {
Summary string
Description string
CompletedUnix int64
Organizer *models.User
Organizer *user.User
Priority int64 // 0-9, 1 is highest
RelatedToUID string

View File

@ -23,6 +23,7 @@ import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/routes"
v1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"code.vikunja.io/web/handler"
"github.com/dgrijalva/jwt-go"
@ -38,34 +39,34 @@ import (
// These are the test users, the same way they are in the test database
var (
testuser1 = models.User{
testuser1 = user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
Email: "user1@example.com",
IsActive: true,
}
testuser2 = models.User{
testuser2 = user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
Email: "user2@example.com",
}
testuser3 = models.User{
testuser3 = user.User{
ID: 3,
Username: "user3",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
Email: "user3@example.com",
PasswordResetToken: "passwordresettesttoken",
}
testuser4 = models.User{
testuser4 = user.User{
ID: 4,
Username: "user4",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
Email: "user4@example.com",
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
}
testuser5 = models.User{
testuser5 = user.User{
ID: 4,
Username: "user5",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -114,7 +115,7 @@ func newTestRequest(t *testing.T, method string, handler func(ctx echo.Context)
return
}
func addUserTokenToContext(t *testing.T, user *models.User, c echo.Context) {
func addUserTokenToContext(t *testing.T, user *user.User, c echo.Context) {
// Get the token as a string
token, err := v1.NewUserJWTAuthtoken(user)
assert.NoError(t, err)
@ -152,7 +153,7 @@ func testRequestSetup(t *testing.T, method string, payload string, queryParams u
return
}
func newTestRequestWithUser(t *testing.T, method string, handler echo.HandlerFunc, user *models.User, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
func newTestRequestWithUser(t *testing.T, method string, handler echo.HandlerFunc, user *user.User, payload string, queryParams url.Values, urlParams map[string]string) (rec *httptest.ResponseRecorder, err error) {
rec, c := testRequestSetup(t, method, payload, queryParams, urlParams)
addUserTokenToContext(t, user, c)
err = handler(c)
@ -185,7 +186,7 @@ func assertHandlerErrorCode(t *testing.T, err error, expectedErrorCode int) {
}
type webHandlerTest struct {
user *models.User
user *user.User
linkShare *models.LinkSharing
strFunc func() handler.CObject
t *testing.T

View File

@ -1,6 +1,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"testing"
)
@ -9,7 +10,7 @@ func TestBulkTask_Update(t *testing.T) {
IDs []int64
Tasks []*Task
Task Task
User *User
User *user.User
}
tests := []struct {
name string
@ -24,7 +25,7 @@ func TestBulkTask_Update(t *testing.T) {
Task: Task{
Text: "bulkupdated",
},
User: &User{ID: 1},
User: &user.User{ID: 1},
},
},
{
@ -34,7 +35,7 @@ func TestBulkTask_Update(t *testing.T) {
Task: Task{
Text: "bulkupdated",
},
User: &User{ID: 1},
User: &user.User{ID: 1},
},
wantForbidden: true,
},
@ -45,7 +46,7 @@ func TestBulkTask_Update(t *testing.T) {
Task: Task{
Text: "bulkupdated",
},
User: &User{ID: 1},
User: &user.User{ID: 1},
},
wantForbidden: true,
},

View File

@ -46,273 +46,6 @@ func (err ErrGenericForbidden) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusForbidden, Code: ErrorCodeGenericForbidden, Message: "You're not allowed to do this."}
}
// =====================
// User Operation Errors
// =====================
// ErrUsernameExists represents a "UsernameAlreadyExists" kind of error.
type ErrUsernameExists struct {
UserID int64
Username string
}
// IsErrUsernameExists checks if an error is a ErrUsernameExists.
func IsErrUsernameExists(err error) bool {
_, ok := err.(ErrUsernameExists)
return ok
}
func (err ErrUsernameExists) Error() string {
return fmt.Sprintf("User with that username already exists [user id: %d, username: %s]", err.UserID, err.Username)
}
// ErrorCodeUsernameExists holds the unique world-error code of this error
const ErrorCodeUsernameExists = 1001
// HTTPError holds the http error description
func (err ErrUsernameExists) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUsernameExists, Message: "A user with this username already exists."}
}
// ErrUserEmailExists represents a "UserEmailExists" kind of error.
type ErrUserEmailExists struct {
UserID int64
Email string
}
// IsErrUserEmailExists checks if an error is a ErrUserEmailExists.
func IsErrUserEmailExists(err error) bool {
_, ok := err.(ErrUserEmailExists)
return ok
}
func (err ErrUserEmailExists) Error() string {
return fmt.Sprintf("User with that email already exists [user id: %d, email: %s]", err.UserID, err.Email)
}
// ErrorCodeUserEmailExists holds the unique world-error code of this error
const ErrorCodeUserEmailExists = 1002
// HTTPError holds the http error description
func (err ErrUserEmailExists) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUserEmailExists, Message: "A user with this email address already exists."}
}
// ErrNoUsernamePassword represents a "NoUsernamePassword" kind of error.
type ErrNoUsernamePassword struct{}
// IsErrNoUsernamePassword checks if an error is a ErrNoUsernamePassword.
func IsErrNoUsernamePassword(err error) bool {
_, ok := err.(ErrNoUsernamePassword)
return ok
}
func (err ErrNoUsernamePassword) Error() string {
return fmt.Sprintf("No username and password provided")
}
// ErrCodeNoUsernamePassword holds the unique world-error code of this error
const ErrCodeNoUsernamePassword = 1004
// HTTPError holds the http error description
func (err ErrNoUsernamePassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeNoUsernamePassword, Message: "Please specify a username and a password."}
}
// ErrUserDoesNotExist represents a "UserDoesNotExist" kind of error.
type ErrUserDoesNotExist struct {
UserID int64
}
// IsErrUserDoesNotExist checks if an error is a ErrUserDoesNotExist.
func IsErrUserDoesNotExist(err error) bool {
_, ok := err.(ErrUserDoesNotExist)
return ok
}
func (err ErrUserDoesNotExist) Error() string {
return fmt.Sprintf("User does not exist [user id: %d]", err.UserID)
}
// ErrCodeUserDoesNotExist holds the unique world-error code of this error
const ErrCodeUserDoesNotExist = 1005
// HTTPError holds the http error description
func (err ErrUserDoesNotExist) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeUserDoesNotExist, Message: "The user does not exist."}
}
// ErrCouldNotGetUserID represents a "ErrCouldNotGetUserID" kind of error.
type ErrCouldNotGetUserID struct{}
// IsErrCouldNotGetUserID checks if an error is a ErrCouldNotGetUserID.
func IsErrCouldNotGetUserID(err error) bool {
_, ok := err.(ErrCouldNotGetUserID)
return ok
}
func (err ErrCouldNotGetUserID) Error() string {
return fmt.Sprintf("Could not get user ID")
}
// ErrCodeCouldNotGetUserID holds the unique world-error code of this error
const ErrCodeCouldNotGetUserID = 1006
// HTTPError holds the http error description
func (err ErrCouldNotGetUserID) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeCouldNotGetUserID, Message: "Could not get user id."}
}
// ErrNoPasswordResetToken represents an error where no password reset token exists for that user
type ErrNoPasswordResetToken struct {
UserID int64
}
func (err ErrNoPasswordResetToken) Error() string {
return fmt.Sprintf("No token to reset a password [UserID: %d]", err.UserID)
}
// ErrCodeNoPasswordResetToken holds the unique world-error code of this error
const ErrCodeNoPasswordResetToken = 1008
// HTTPError holds the http error description
func (err ErrNoPasswordResetToken) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeNoPasswordResetToken, Message: "No token to reset a user's password provided."}
}
// ErrInvalidPasswordResetToken is an error where the password reset token is invalid
type ErrInvalidPasswordResetToken struct {
Token string
}
func (err ErrInvalidPasswordResetToken) Error() string {
return fmt.Sprintf("Invalid token to reset a password [Token: %s]", err.Token)
}
// ErrCodeInvalidPasswordResetToken holds the unique world-error code of this error
const ErrCodeInvalidPasswordResetToken = 1009
// HTTPError holds the http error description
func (err ErrInvalidPasswordResetToken) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidPasswordResetToken, Message: "Invalid token to reset a user's password."}
}
// IsErrInvalidPasswordResetToken checks if an error is a ErrInvalidPasswordResetToken.
func IsErrInvalidPasswordResetToken(err error) bool {
_, ok := err.(ErrInvalidPasswordResetToken)
return ok
}
// ErrInvalidEmailConfirmToken is an error where the email confirm token is invalid
type ErrInvalidEmailConfirmToken struct {
Token string
}
func (err ErrInvalidEmailConfirmToken) Error() string {
return fmt.Sprintf("Invalid email confirm token [Token: %s]", err.Token)
}
// ErrCodeInvalidEmailConfirmToken holds the unique world-error code of this error
const ErrCodeInvalidEmailConfirmToken = 1010
// HTTPError holds the http error description
func (err ErrInvalidEmailConfirmToken) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidEmailConfirmToken, Message: "Invalid email confirm token."}
}
// IsErrInvalidEmailConfirmToken checks if an error is a ErrInvalidEmailConfirmToken.
func IsErrInvalidEmailConfirmToken(err error) bool {
_, ok := err.(ErrInvalidEmailConfirmToken)
return ok
}
// ErrWrongUsernameOrPassword is an error where the email was not confirmed
type ErrWrongUsernameOrPassword struct {
}
func (err ErrWrongUsernameOrPassword) Error() string {
return fmt.Sprintf("Wrong username or password")
}
// ErrCodeWrongUsernameOrPassword holds the unique world-error code of this error
const ErrCodeWrongUsernameOrPassword = 1011
// HTTPError holds the http error description
func (err ErrWrongUsernameOrPassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeWrongUsernameOrPassword, Message: "Wrong username or password."}
}
// IsErrWrongUsernameOrPassword checks if an error is a IsErrEmailNotConfirmed.
func IsErrWrongUsernameOrPassword(err error) bool {
_, ok := err.(ErrWrongUsernameOrPassword)
return ok
}
// ErrEmailNotConfirmed is an error where the email was not confirmed
type ErrEmailNotConfirmed struct {
UserID int64
}
func (err ErrEmailNotConfirmed) Error() string {
return fmt.Sprintf("Email is not confirmed [UserID: %d]", err.UserID)
}
// ErrCodeEmailNotConfirmed holds the unique world-error code of this error
const ErrCodeEmailNotConfirmed = 1012
// HTTPError holds the http error description
func (err ErrEmailNotConfirmed) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmailNotConfirmed, Message: "Please confirm your email address."}
}
// IsErrEmailNotConfirmed checks if an error is a IsErrEmailNotConfirmed.
func IsErrEmailNotConfirmed(err error) bool {
_, ok := err.(ErrEmailNotConfirmed)
return ok
}
// ErrEmptyNewPassword represents a "EmptyNewPassword" kind of error.
type ErrEmptyNewPassword struct{}
// IsErrEmptyNewPassword checks if an error is a ErrEmptyNewPassword.
func IsErrEmptyNewPassword(err error) bool {
_, ok := err.(ErrEmptyNewPassword)
return ok
}
func (err ErrEmptyNewPassword) Error() string {
return fmt.Sprintf("New password is empty")
}
// ErrCodeEmptyNewPassword holds the unique world-error code of this error
const ErrCodeEmptyNewPassword = 1013
// HTTPError holds the http error description
func (err ErrEmptyNewPassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyNewPassword, Message: "Please specify new password."}
}
// ErrEmptyOldPassword represents a "EmptyOldPassword" kind of error.
type ErrEmptyOldPassword struct{}
// IsErrEmptyOldPassword checks if an error is a ErrEmptyOldPassword.
func IsErrEmptyOldPassword(err error) bool {
_, ok := err.(ErrEmptyOldPassword)
return ok
}
func (err ErrEmptyOldPassword) Error() string {
return fmt.Sprintf("Old password is empty")
}
// ErrCodeEmptyOldPassword holds the unique world-error code of this error
const ErrCodeEmptyOldPassword = 1014
// HTTPError holds the http error description
func (err ErrEmptyOldPassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyOldPassword, Message: "Please specify old password."}
}
// ===================
// Empty things errors
// ===================

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"time"
)
@ -34,7 +35,7 @@ type Label struct {
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
// The user who created this label
CreatedBy *User `xorm:"-" json:"created_by"`
CreatedBy *user.User `xorm:"-" json:"created_by"`
// A unix timestamp when this label was created. You cannot change this value.
Created int64 `xorm:"created not null" json:"created"`
@ -63,7 +64,7 @@ func (Label) TableName() string {
// @Failure 500 {object} models.Message "Internal error"
// @Router /labels [put]
func (l *Label) Create(a web.Auth) (err error) {
u, err := getUserWithError(a)
u, err := user.GetFromAuth(a)
if err != nil {
return
}
@ -136,7 +137,7 @@ func (l *Label) ReadAll(a web.Auth, search string, page int, perPage int) (ls in
return nil, 0, 0, ErrGenericForbidden{}
}
u := &User{ID: a.GetID()}
u := &user.User{ID: a.GetID()}
// Get all tasks
taskIDs, err := getUserTaskIDs(u)
@ -175,7 +176,7 @@ func (l *Label) ReadOne() (err error) {
}
*l = *label
user, err := GetUserByID(l.CreatedByID)
user, err := user.GetUserByID(l.CreatedByID)
if err != nil {
return err
}
@ -198,7 +199,7 @@ func getLabelByIDSimple(labelID int64) (*Label, error) {
}
// Helper method to get all task ids a user has
func getUserTaskIDs(u *User) (taskIDs []int64, err error) {
func getUserTaskIDs(u *user.User) (taskIDs []int64, err error) {
// Get all lists
lists, _, _, err := getRawListsForUser("", u, -1, 0)

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/go-xorm/builder"
)
@ -65,7 +66,7 @@ func (l *Label) hasAccessToLabel(a web.Auth) (bool, error) {
// TODO: add an extra check for link share handling
// Get all tasks
taskIDs, err := getUserTaskIDs(&User{ID: a.GetID()})
taskIDs, err := getUserTaskIDs(&user.User{ID: a.GetID()})
if err != nil {
return false, err
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/go-xorm/builder"
)
@ -120,7 +121,7 @@ func (lt *LabelTask) ReadAll(a web.Auth, search string, page int, perPage int) (
}
return getLabelsByTaskIDs(&LabelByTaskIDsOptions{
User: &User{ID: a.GetID()},
User: &user.User{ID: a.GetID()},
Search: search,
Page: page,
TaskIDs: []int64{lt.TaskID},
@ -135,7 +136,7 @@ type labelWithTaskID struct {
// LabelByTaskIDsOptions is a struct to not clutter the function with too many optional parameters.
type LabelByTaskIDsOptions struct {
User *User
User *user.User
Search string
Page int
PerPage int
@ -185,7 +186,7 @@ func getLabelsByTaskIDs(opts *LabelByTaskIDsOptions) (ls []*labelWithTaskID, res
for _, l := range labels {
userids = append(userids, l.CreatedByID)
}
users := make(map[int64]*User)
users := make(map[int64]*user.User)
err = x.In("id", userids).Find(&users)
if err != nil {
return nil, 0, 0, err
@ -290,7 +291,7 @@ func (t *Task) updateTaskLabels(creator web.Auth, labels []*Label) (err error) {
return err
}
if !hasAccessToLabel {
user, _ := creator.(*User)
user, _ := creator.(*user.User)
return ErrUserHasNoAccessToLabel{LabelID: l.ID, UserID: user.ID}
}

View File

@ -1,6 +1,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"reflect"
"runtime"
@ -37,7 +38,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
TaskID: 1,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantLabels: []*labelWithTaskID{
{
@ -46,7 +47,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
ID: 4,
Title: "Label #4 - visible via other task",
CreatedByID: 2,
CreatedBy: &User{
CreatedBy: &user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -62,7 +63,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
TaskID: 14,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantErr: true,
errType: IsErrNoRightToSeeTask,
@ -73,7 +74,7 @@ func TestLabelTask_ReadAll(t *testing.T) {
TaskID: 9999,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantErr: true,
errType: IsErrTaskDoesNotExist,
@ -131,7 +132,7 @@ func TestLabelTask_Create(t *testing.T) {
LabelID: 1,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
},
{
@ -141,7 +142,7 @@ func TestLabelTask_Create(t *testing.T) {
LabelID: 1,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantErr: true,
errType: IsErrLabelIsAlreadyOnTask,
@ -153,7 +154,7 @@ func TestLabelTask_Create(t *testing.T) {
LabelID: 9999,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantForbidden: true,
},
@ -164,7 +165,7 @@ func TestLabelTask_Create(t *testing.T) {
LabelID: 1,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantForbidden: true,
wantErr: true,
@ -219,7 +220,7 @@ func TestLabelTask_Delete(t *testing.T) {
TaskID: 1,
LabelID: 1,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
{
name: "delete nonexistant",
@ -227,7 +228,7 @@ func TestLabelTask_Delete(t *testing.T) {
TaskID: 1,
LabelID: 1,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
{
@ -236,7 +237,7 @@ func TestLabelTask_Delete(t *testing.T) {
TaskID: 1,
LabelID: 9999,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
{
@ -245,7 +246,7 @@ func TestLabelTask_Delete(t *testing.T) {
TaskID: 9999,
LabelID: 1,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
{
@ -254,7 +255,7 @@ func TestLabelTask_Delete(t *testing.T) {
TaskID: 14,
LabelID: 1,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"reflect"
"runtime"
@ -32,7 +33,7 @@ func TestLabel_ReadAll(t *testing.T) {
Description string
HexColor string
CreatedByID int64
CreatedBy *User
CreatedBy *user.User
Created int64
Updated int64
CRUDable web.CRUDable
@ -43,7 +44,7 @@ func TestLabel_ReadAll(t *testing.T) {
a web.Auth
page int
}
user1 := &User{
user1 := &user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -60,7 +61,7 @@ func TestLabel_ReadAll(t *testing.T) {
{
name: "normal",
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
wantLs: []*labelWithTaskID{
{
@ -85,7 +86,7 @@ func TestLabel_ReadAll(t *testing.T) {
ID: 4,
Title: "Label #4 - visible via other task",
CreatedByID: 2,
CreatedBy: &User{
CreatedBy: &user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -98,7 +99,7 @@ func TestLabel_ReadAll(t *testing.T) {
{
name: "invalid user",
args: args{
a: &User{ID: -1},
a: &user.User{ID: -1},
},
wantErr: true,
},
@ -136,13 +137,13 @@ func TestLabel_ReadOne(t *testing.T) {
Description string
HexColor string
CreatedByID int64
CreatedBy *User
CreatedBy *user.User
Created int64
Updated int64
CRUDable web.CRUDable
Rights web.Rights
}
user1 := &User{
user1 := &user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -169,7 +170,7 @@ func TestLabel_ReadOne(t *testing.T) {
CreatedByID: 1,
CreatedBy: user1,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
{
name: "Get nonexistant label",
@ -179,7 +180,7 @@ func TestLabel_ReadOne(t *testing.T) {
wantErr: true,
errType: IsErrLabelDoesNotExist,
wantForbidden: true,
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
{
name: "no rights",
@ -187,7 +188,7 @@ func TestLabel_ReadOne(t *testing.T) {
ID: 3,
},
wantForbidden: true,
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
{
name: "Get label #4 - other user",
@ -198,14 +199,14 @@ func TestLabel_ReadOne(t *testing.T) {
ID: 4,
Title: "Label #4 - visible via other task",
CreatedByID: 2,
CreatedBy: &User{
CreatedBy: &user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
},
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
}
for _, tt := range tests {
@ -248,7 +249,7 @@ func TestLabel_Create(t *testing.T) {
Description string
HexColor string
CreatedByID int64
CreatedBy *User
CreatedBy *user.User
Created int64
Updated int64
CRUDable web.CRUDable
@ -272,7 +273,7 @@ func TestLabel_Create(t *testing.T) {
HexColor: "ffccff",
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
},
}
@ -308,7 +309,7 @@ func TestLabel_Update(t *testing.T) {
Description string
HexColor string
CreatedByID int64
CreatedBy *User
CreatedBy *user.User
Created int64
Updated int64
CRUDable web.CRUDable
@ -327,7 +328,7 @@ func TestLabel_Update(t *testing.T) {
ID: 1,
Title: "new and better",
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
{
name: "nonexisting",
@ -335,7 +336,7 @@ func TestLabel_Update(t *testing.T) {
ID: 99999,
Title: "new and better",
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
wantErr: true,
},
@ -345,7 +346,7 @@ func TestLabel_Update(t *testing.T) {
ID: 3,
Title: "new and better",
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
{
@ -354,7 +355,7 @@ func TestLabel_Update(t *testing.T) {
ID: 4,
Title: "new and better",
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
}
@ -390,7 +391,7 @@ func TestLabel_Delete(t *testing.T) {
Description string
HexColor string
CreatedByID int64
CreatedBy *User
CreatedBy *user.User
Created int64
Updated int64
CRUDable web.CRUDable
@ -409,14 +410,14 @@ func TestLabel_Delete(t *testing.T) {
fields: fields{
ID: 1,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
},
{
name: "nonexisting",
fields: fields{
ID: 99999,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true, // When the label does not exist, it is forbidden. We should fix this, but for everything.
},
{
@ -424,7 +425,7 @@ func TestLabel_Delete(t *testing.T) {
fields: fields{
ID: 3,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
{
@ -432,7 +433,7 @@ func TestLabel_Delete(t *testing.T) {
fields: fields{
ID: 4,
},
auth: &User{ID: 1},
auth: &user.User{ID: 1},
wantForbidden: true,
},
}

View File

@ -18,6 +18,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"code.vikunja.io/web"
"github.com/dgrijalva/jwt-go"
@ -48,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

View File

@ -18,6 +18,7 @@ package models
import (
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
@ -36,7 +37,7 @@ type List struct {
NamespaceID int64 `xorm:"int(11) INDEX not null" json:"-" param:"namespace"`
// The user who created this list.
Owner *User `xorm:"-" json:"owner" valid:"-"`
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
// An array of tasks which belong to the list.
// Deprecated: you should use the dedicated task list endpoint because it has support for pagination and filtering
Tasks []*Task `xorm:"-" json:"-"`
@ -51,7 +52,7 @@ type List struct {
}
// GetListsByNamespaceID gets all lists in a namespace
func GetListsByNamespaceID(nID int64, doer *User) (lists []*List, err error) {
func GetListsByNamespaceID(nID int64, doer *user.User) (lists []*List, err error) {
if nID == -1 {
err = x.Select("l.*").
Table("list").
@ -103,7 +104,7 @@ func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result
return lists, 0, 0, err
}
lists, resultCount, totalItems, err := getRawListsForUser(search, &User{ID: a.GetID()}, page, perPage)
lists, resultCount, totalItems, err := getRawListsForUser(search, &user.User{ID: a.GetID()}, page, perPage)
if err != nil {
return nil, 0, 0, err
}
@ -127,7 +128,7 @@ func (l *List) ReadAll(a web.Auth, search string, page int, perPage int) (result
// @Router /lists/{id} [get]
func (l *List) ReadOne() (err error) {
// Get list owner
l.Owner, err = GetUserByID(l.OwnerID)
l.Owner, err = user.GetUserByID(l.OwnerID)
return
}
@ -176,8 +177,8 @@ func GetListSimplByTaskID(taskID int64) (l *List, err error) {
}
// Gets the lists only, without any tasks or so
func getRawListsForUser(search string, u *User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
fullUser, err := GetUserByID(u.ID)
func getRawListsForUser(search string, u *user.User, page int, perPage int) (lists []*List, resultCount int, totalItems int64, err error) {
fullUser, err := user.GetUserByID(u.ID)
if err != nil {
return nil, 0, 0, err
}
@ -237,7 +238,7 @@ func AddListDetails(lists []*List) (err error) {
}
// Get all list owners
owners := []*User{}
owners := []*user.User{}
err = x.In("id", ownerIDs).Find(&owners)
if err != nil {
return
@ -348,7 +349,7 @@ func updateListByTaskID(taskID int64) (err error) {
// @Failure 500 {object} models.Message "Internal error"
// @Router /namespaces/{namespaceID}/lists [put]
func (l *List) Create(a web.Auth) (err error) {
doer, err := getUserWithError(a)
doer, err := user.GetFromAuth(a)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/go-xorm/builder"
)
@ -39,7 +40,7 @@ func (l *List) CanWrite(a web.Auth) (bool, error) {
}
// Check if the user is either owner or can write to the list
if originalList.isOwner(&User{ID: a.GetID()}) {
if originalList.isOwner(&user.User{ID: a.GetID()}) {
return true, nil
}
@ -60,7 +61,7 @@ func (l *List) CanRead(a web.Auth) (bool, error) {
(shareAuth.Right == RightRead || shareAuth.Right == RightWrite || shareAuth.Right == RightAdmin), nil
}
if l.isOwner(&User{ID: a.GetID()}) {
if l.isOwner(&user.User{ID: a.GetID()}) {
return true, nil
}
return l.checkRight(a, RightRead, RightWrite, RightAdmin)
@ -100,14 +101,14 @@ func (l *List) IsAdmin(a web.Auth) (bool, error) {
// Check all the things
// Check if the user is either owner or can write to the list
// Owners are always admins
if originalList.isOwner(&User{ID: a.GetID()}) {
if originalList.isOwner(&user.User{ID: a.GetID()}) {
return true, nil
}
return originalList.checkRight(a, RightAdmin)
}
// Little helper function to check if a user is list owner
func (l *List) isOwner(u *User) bool {
func (l *List) isOwner(u *user.User) bool {
return l.OwnerID == u.ID
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/stretchr/testify/assert"
"reflect"
@ -33,7 +34,7 @@ func TestTeamList(t *testing.T) {
}
// Dummyuser
u, err := GetUserByID(1)
u, err := user.GetUserByID(1)
assert.NoError(t, err)
// Check normal creation

View File

@ -17,13 +17,14 @@
package models
import (
user2 "code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
)
func TestList_CreateOrUpdate(t *testing.T) {
user := &User{
user := &user2.User{
ID: 1,
Username: "user1",
Email: "user1@example.com",
@ -54,7 +55,7 @@ func TestList_CreateOrUpdate(t *testing.T) {
})
t.Run("nonexistant owner", func(t *testing.T) {
initFixtures(t)
user := &User{ID: 9482385}
user := &user2.User{ID: 9482385}
list := List{
Title: "test",
Description: "Lorem Ipsum",
@ -133,12 +134,12 @@ func TestList_ReadAll(t *testing.T) {
t.Run("all in namespace", func(t *testing.T) {
initFixtures(t)
// Get all lists for our namespace
lists, err := GetListsByNamespaceID(1, &User{})
lists, err := GetListsByNamespaceID(1, &user2.User{})
assert.NoError(t, err)
assert.Equal(t, len(lists), 2)
})
t.Run("all lists for user", func(t *testing.T) {
u := &User{ID: 1}
u := &user2.User{ID: 1}
list := List{}
lists3, _, _, err := list.ReadAll(u, "", 1, 50)
@ -148,7 +149,7 @@ func TestList_ReadAll(t *testing.T) {
assert.Equal(t, 16, s.Len())
})
t.Run("lists for nonexistant user", func(t *testing.T) {
user := &User{ID: 999999}
user := &user2.User{ID: 999999}
list := List{}
_, _, _, err := list.ReadAll(user, "", 1, 50)
assert.Error(t, err)

View File

@ -16,7 +16,10 @@
package models
import "code.vikunja.io/web"
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
// ListUser represents a list <-> user relation
type ListUser struct {
@ -47,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
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"testing"
"code.vikunja.io/web"
@ -48,7 +49,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
ListID: 3,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
},
@ -58,7 +59,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
ListID: 300,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
},
@ -68,7 +69,7 @@ func TestListUser_CanDoSomething(t *testing.T) {
ListID: 3,
},
args: args{
a: &User{ID: 4},
a: &user.User{ID: 4},
},
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
},

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"gopkg.in/d4l3k/messagediff.v1"
"reflect"
"runtime"
@ -155,11 +156,11 @@ func TestListUser_ReadAll(t *testing.T) {
ListID: 3,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: []*UserWithRight{
{
User: User{
User: user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -169,7 +170,7 @@ func TestListUser_ReadAll(t *testing.T) {
Right: RightRead,
},
{
User: User{
User: user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -185,7 +186,7 @@ func TestListUser_ReadAll(t *testing.T) {
ListID: 3,
},
args: args{
a: &User{ID: 4},
a: &user.User{ID: 4},
},
wantErr: true,
errType: IsErrNeedToHaveListReadAccess,

View File

@ -20,6 +20,7 @@ import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/user"
_ "github.com/go-sql-driver/mysql" // Because.
"github.com/go-xorm/xorm"
@ -33,7 +34,7 @@ var (
// GetTables returns all structs which are also a table.
func GetTables() []interface{} {
return []interface{}{
&User{},
&user.User{},
&List{},
&Task{},
&Team{},

View File

@ -18,6 +18,7 @@ package models
import (
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/imdario/mergo"
"time"
@ -34,7 +35,7 @@ type Namespace struct {
OwnerID int64 `xorm:"int(11) not null INDEX" json:"-"`
// The user who owns this namespace
Owner *User `xorm:"-" json:"owner" valid:"-"`
Owner *user.User `xorm:"-" json:"owner" valid:"-"`
// A unix timestamp when this namespace was created. You cannot change this value.
Created int64 `xorm:"created not null" json:"created"`
@ -97,7 +98,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
}
// Get the namespace Owner
namespace.Owner, err = GetUserByID(namespace.OwnerID)
namespace.Owner, err = user.GetUserByID(namespace.OwnerID)
return
}
@ -115,7 +116,7 @@ func GetNamespaceByID(id int64) (namespace Namespace, err error) {
// @Router /namespaces/{id} [get]
func (n *Namespace) ReadOne() (err error) {
// Get the namespace Owner
n.Owner, err = GetUserByID(n.OwnerID)
n.Owner, err = user.GetUserByID(n.OwnerID)
return
}
@ -143,7 +144,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
return nil, 0, 0, ErrGenericForbidden{}
}
doer, err := getUserWithError(a)
doer, err := user.GetFromAuth(a)
if err != nil {
return nil, 0, 0, err
}
@ -176,7 +177,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
}
// Get all users
users := []*User{}
users := []*user.User{}
err = x.Select("users.*").
Table("namespaces").
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
@ -301,7 +302,7 @@ func (n *Namespace) Create(a web.Auth) (err error) {
n.ID = 0 // This would otherwise prevent the creation of new lists after one was created
// Check if the User exists
n.Owner, err = GetUserByID(a.GetID())
n.Owner, err = user.GetUserByID(a.GetID())
if err != nil {
return
}
@ -343,7 +344,7 @@ func (n *Namespace) Delete() (err error) {
}
// Delete all lists with their tasks
lists, err := GetListsByNamespaceID(n.ID, &User{})
lists, err := GetListsByNamespaceID(n.ID, &user.User{})
if err != nil {
return
}
@ -401,7 +402,7 @@ func (n *Namespace) Update() (err error) {
// Check if the (new) owner exists
n.OwnerID = n.Owner.ID
if currentNamespace.OwnerID != n.OwnerID {
n.Owner, err = GetUserByID(n.OwnerID)
n.Owner, err = user.GetUserByID(n.OwnerID)
if err != nil {
return
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"testing"
"code.vikunja.io/web"
@ -48,7 +49,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
NamespaceID: 3,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
},
@ -58,7 +59,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
NamespaceID: 300,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
},
@ -68,7 +69,7 @@ func TestTeamNamespace_CanDoSomething(t *testing.T) {
NamespaceID: 3,
},
args: args{
a: &User{ID: 4},
a: &user.User{ID: 4},
},
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
},

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/stretchr/testify/assert"
"reflect"
@ -32,7 +33,7 @@ func TestTeamNamespace(t *testing.T) {
Right: RightAdmin,
}
dummyuser, err := GetUserByID(1)
dummyuser, err := user.GetUserByID(1)
assert.NoError(t, err)
// Test normal creation
@ -80,7 +81,7 @@ func TestTeamNamespace(t *testing.T) {
assert.True(t, IsErrNamespaceDoesNotExist(err))
// Check with no right to read the namespace
nouser := &User{ID: 393}
nouser := &user.User{ID: 393}
_, _, _, err = tn.ReadAll(nouser, "", 1, 50)
assert.Error(t, err)
assert.True(t, IsErrNeedToHaveNamespaceReadAccess(err))

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
@ -33,7 +34,7 @@ func TestNamespace_Create(t *testing.T) {
}
// Doer
doer, err := GetUserByID(1)
doer, err := user.GetUserByID(1)
assert.NoError(t, err)
// Try creating it
@ -57,7 +58,7 @@ func TestNamespace_Create(t *testing.T) {
assert.True(t, IsErrNamespaceNameCannotBeEmpty(err))
// Try inserting one with a nonexistant user
nUser := &User{ID: 9482385}
nUser := &user.User{ID: 9482385}
dnsp2 := dummynamespace
err = dnsp2.Create(nUser)
assert.Error(t, err)

View File

@ -16,7 +16,10 @@
package models
import "code.vikunja.io/web"
import (
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
// NamespaceUser represents a namespace <-> user relation
type NamespaceUser struct {
@ -75,7 +78,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
}
// Check if the user exists
user, err := GetUserByUsername(nu.Username)
user, err := user2.GetUserByUsername(nu.Username)
if err != nil {
return err
}
@ -117,7 +120,7 @@ func (nu *NamespaceUser) Create(a web.Auth) (err error) {
func (nu *NamespaceUser) Delete() (err error) {
// Check if the user exists
user, err := GetUserByUsername(nu.Username)
user, err := user2.GetUserByUsername(nu.Username)
if err != nil {
return
}
@ -213,7 +216,7 @@ func (nu *NamespaceUser) Update() (err error) {
}
// Check if the user exists
user, err := GetUserByUsername(nu.Username)
user, err := user2.GetUserByUsername(nu.Username)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"testing"
"code.vikunja.io/web"
@ -48,7 +49,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
NamespaceID: 3,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: map[string]bool{"CanCreate": true, "CanDelete": true, "CanUpdate": true},
},
@ -58,7 +59,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
NamespaceID: 300,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
},
@ -68,7 +69,7 @@ func TestNamespaceUser_CanDoSomething(t *testing.T) {
NamespaceID: 3,
},
args: args{
a: &User{ID: 4},
a: &user.User{ID: 4},
},
want: map[string]bool{"CanCreate": false, "CanDelete": false, "CanUpdate": false},
},

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"gopkg.in/d4l3k/messagediff.v1"
"reflect"
@ -152,11 +153,11 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
NamespaceID: 3,
},
args: args{
a: &User{ID: 3},
a: &user.User{ID: 3},
},
want: []*UserWithRight{
{
User: User{
User: user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -166,7 +167,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
Right: RightRead,
},
{
User: User{
User: user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -182,7 +183,7 @@ func TestNamespaceUser_ReadAll(t *testing.T) {
NamespaceID: 3,
},
args: args{
a: &User{ID: 4},
a: &user.User{ID: 4},
},
wantErr: true,
errType: IsErrNeedToHaveNamespaceReadAccess,

View File

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

View File

@ -18,6 +18,7 @@ package models
import (
"code.vikunja.io/api/pkg/files"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"io"
"time"
@ -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

View File

@ -20,6 +20,7 @@ package models
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/files"
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"io"
"os"
@ -95,7 +96,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
tf := &testfile{
content: []byte("testingstuff"),
}
testuser := &User{ID: 1}
testuser := &user.User{ID: 1}
err := ta.NewAttachment(tf, "testfile", 100, testuser)
assert.NoError(t, err)
@ -119,7 +120,7 @@ func TestTaskAttachment_NewAttachment(t *testing.T) {
func TestTaskAttachment_ReadAll(t *testing.T) {
files.InitTestFileFixtures(t)
ta := &TaskAttachment{TaskID: 1}
as, _, _, err := ta.ReadAll(&User{ID: 1}, "", 0, 50)
as, _, _, err := ta.ReadAll(&user.User{ID: 1}, "", 0, 50)
attachments, _ := as.([]*TaskAttachment)
assert.NoError(t, err)
assert.Len(t, attachments, 3)
@ -152,7 +153,7 @@ func TestTaskAttachment_Delete(t *testing.T) {
}
func TestTaskAttachment_Rights(t *testing.T) {
u := &User{ID: 1}
u := &user.User{ID: 1}
t.Run("Can Read", func(t *testing.T) {
t.Run("Allowed", func(t *testing.T) {
ta := &TaskAttachment{TaskID: 1}

View File

@ -18,6 +18,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"time"
)
@ -108,7 +109,7 @@ func (tf *TaskCollection) ReadAll(a web.Auth, search string, page int, perPage i
// If the list ID is not set, we get all tasks for the user.
// This allows to use this function in Task.ReadAll with a possibility to deprecate the latter at some point.
if tf.ListID == 0 {
tf.Lists, _, _, err = getRawListsForUser("", &User{ID: a.GetID()}, -1, 0)
tf.Lists, _, _, err = getRawListsForUser("", &user.User{ID: a.GetID()}, -1, 0)
if err != nil {
return nil, 0, 0, err
}

View File

@ -19,6 +19,7 @@ package models
import (
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/files"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/stretchr/testify/assert"
"gopkg.in/d4l3k/messagediff.v1"
@ -29,20 +30,20 @@ func TestTaskCollection_ReadAll(t *testing.T) {
assert.NoError(t, db.LoadFixtures())
// Dummy users
user1 := &User{
user1 := &user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808", // hash for ""
}
user2 := &User{
user2 := &user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f", // hash for ""
}
user6 := &User{
user6 := &user.User{
ID: 6,
Username: "user6",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -463,7 +464,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
CreatedByID: 1,
CreatedBy: user1,
ListID: 1,
Assignees: []*User{
Assignees: []*user.User{
user1,
user2,
},
@ -538,7 +539,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
fields: fields{},
args: args{
search: "",
a: &User{ID: 1},
a: &user.User{ID: 1},
page: 0,
},
want: []*Task{
@ -585,7 +586,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
},
args: args{
search: "",
a: &User{ID: 1},
a: &user.User{ID: 1},
page: 0,
},
want: []*Task{
@ -631,7 +632,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
},
args: args{
search: "",
a: &User{ID: 1},
a: &user.User{ID: 1},
page: 0,
},
want: []*Task{
@ -648,7 +649,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
},
args: args{
search: "",
a: &User{ID: 1},
a: &user.User{ID: 1},
page: 0,
},
want: []*Task{
@ -664,7 +665,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
},
args: args{
search: "",
a: &User{ID: 1},
a: &user.User{ID: 1},
page: 0,
},
want: []*Task{

View File

@ -18,6 +18,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
@ -83,7 +84,7 @@ type TaskRelation struct {
CreatedByID int64 `xorm:"int(11) not null" json:"-"`
// The user who created this relation
CreatedBy *User `xorm:"-" json:"created_by"`
CreatedBy *user.User `xorm:"-" json:"created_by"`
// A unix timestamp when this label was created. You cannot change this value.
Created int64 `xorm:"created not null" json:"created"`

View File

@ -18,6 +18,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"testing"
)
@ -29,7 +30,7 @@ func TestTaskRelation_Create(t *testing.T) {
OtherTaskID: 2,
RelationKind: RelationKindSubtask,
}
err := rel.Create(&User{ID: 1})
err := rel.Create(&user.User{ID: 1})
assert.NoError(t, err)
})
t.Run("Two Tasks In Different Lists", func(t *testing.T) {
@ -38,7 +39,7 @@ func TestTaskRelation_Create(t *testing.T) {
OtherTaskID: 13,
RelationKind: RelationKindSubtask,
}
err := rel.Create(&User{ID: 1})
err := rel.Create(&user.User{ID: 1})
assert.NoError(t, err)
})
t.Run("Already Existing", func(t *testing.T) {
@ -47,7 +48,7 @@ func TestTaskRelation_Create(t *testing.T) {
OtherTaskID: 29,
RelationKind: RelationKindSubtask,
}
err := rel.Create(&User{ID: 1})
err := rel.Create(&user.User{ID: 1})
assert.Error(t, err)
assert.True(t, IsErrRelationAlreadyExists(err))
})
@ -56,7 +57,7 @@ func TestTaskRelation_Create(t *testing.T) {
TaskID: 1,
OtherTaskID: 1,
}
err := rel.Create(&User{ID: 1})
err := rel.Create(&user.User{ID: 1})
assert.Error(t, err)
assert.True(t, IsErrRelationTasksCannotBeTheSame(err))
})
@ -91,7 +92,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 2,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.NoError(t, err)
assert.True(t, can)
})
@ -101,7 +102,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 13,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.NoError(t, err)
assert.True(t, can)
})
@ -111,7 +112,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 1,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.NoError(t, err)
assert.False(t, can)
})
@ -121,7 +122,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 1,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.NoError(t, err)
assert.False(t, can)
})
@ -131,7 +132,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 14,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.NoError(t, err)
assert.False(t, can)
})
@ -141,7 +142,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 1,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.Error(t, err)
assert.True(t, IsErrTaskDoesNotExist(err))
assert.False(t, can)
@ -152,7 +153,7 @@ func TestTaskRelation_CanCreate(t *testing.T) {
OtherTaskID: 999999,
RelationKind: RelationKindSubtask,
}
can, err := rel.CanCreate(&User{ID: 1})
can, err := rel.CanCreate(&user.User{ID: 1})
assert.Error(t, err)
assert.True(t, IsErrTaskDoesNotExist(err))
assert.False(t, can)

View File

@ -19,6 +19,7 @@ package models
import (
"code.vikunja.io/api/pkg/files"
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"code.vikunja.io/web"
"github.com/imdario/mergo"
@ -55,7 +56,7 @@ type Task struct {
// When this task ends.
EndDateUnix int64 `xorm:"int(11) INDEX null" json:"endDate" query:"-"`
// An array of users who are assigned to this task
Assignees []*User `xorm:"-" json:"assignees"`
Assignees []*user.User `xorm:"-" json:"assignees"`
// An array of labels which are associated with this task.
Labels []*Label `xorm:"-" json:"labels"`
// The task color in hex
@ -87,7 +88,7 @@ type Task struct {
Updated int64 `xorm:"updated not null" json:"updated"`
// The user who initially created the task.
CreatedBy *User `xorm:"-" json:"createdBy" valid:"-"`
CreatedBy *user.User `xorm:"-" json:"createdBy" valid:"-"`
web.CRUDable `xorm:"-" json:"-"`
web.Rights `xorm:"-" json:"-"`
@ -365,7 +366,7 @@ func addMoreInfoToTasks(taskMap map[int64]*Task) (tasks []*Task, err error) {
// Get all users of a task
// aka the ones who created a task
users := make(map[int64]*User)
users := make(map[int64]*user.User)
err = x.In("id", userIDs).Find(&users)
if err != nil {
return
@ -487,7 +488,7 @@ func (t *Task) Create(a web.Auth) (err error) {
return
}
u, err := GetUserByID(a.GetID())
u, err := user.GetUserByID(a.GetID())
if err != nil {
return err
}

View File

@ -17,12 +17,13 @@
package models
import (
user2 "code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"testing"
)
func TestTask_Create(t *testing.T) {
user := &User{
user := &user2.User{
ID: 1,
Username: "user1",
Email: "user1@example.com",
@ -70,7 +71,7 @@ func TestTask_Create(t *testing.T) {
})
t.Run("noneixtant user", func(t *testing.T) {
initFixtures(t)
nUser := &User{ID: 99999999}
nUser := &user2.User{ID: 99999999}
task := &Task{
Text: "Test",
Description: "Lorem Ipsum Dolor",

View File

@ -16,7 +16,10 @@
package models
import "code.vikunja.io/web"
import (
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
// Create implements the create method to assign a user to a team
// @Summary Add a user to a team
@ -41,7 +44,7 @@ func (tm *TeamMember) Create(a web.Auth) (err error) {
}
// Check if the user exists
user, err := GetUserByUsername(tm.Username)
user, err := user2.GetUserByUsername(tm.Username)
if err != nil {
return
}
@ -84,7 +87,7 @@ func (tm *TeamMember) Delete() (err error) {
}
// Find the numeric user id
user, err := GetUserByUsername(tm.Username)
user, err := user2.GetUserByUsername(tm.Username)
if err != nil {
return
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"testing"
)
@ -30,7 +31,7 @@ func TestTeamMember_Create(t *testing.T) {
}
// Doer
doer, err := GetUserByID(1)
doer, err := user.GetUserByID(1)
assert.NoError(t, err)
// Insert a new team member

View File

@ -18,6 +18,7 @@ package models
import (
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
)
@ -32,7 +33,7 @@ type Team struct {
CreatedByID int64 `xorm:"int(11) not null INDEX" json:"-"`
// The user who created this team.
CreatedBy *User `xorm:"-" json:"createdBy"`
CreatedBy *user.User `xorm:"-" json:"createdBy"`
// An array of all members in this team.
Members []*TeamUser `xorm:"-" json:"members"`
@ -53,7 +54,7 @@ func (Team) TableName() string {
// AfterLoad gets the created by user object
func (t *Team) AfterLoad() {
// Get the owner
t.CreatedBy, _ = GetUserByID(t.CreatedByID)
t.CreatedBy, _ = user.GetUserByID(t.CreatedByID)
// Get all members
x.Select("*").
@ -90,7 +91,7 @@ func (TeamMember) TableName() string {
// TeamUser is the team member type
type TeamUser struct {
User `xorm:"extends"`
user.User `xorm:"extends"`
// Whether or not the member is an admin of the team. See the docs for more about what a team admin can do
Admin bool `json:"admin"`
}
@ -181,7 +182,7 @@ func (t *Team) ReadAll(a web.Auth, search string, page int, perPage int) (result
// @Failure 500 {object} models.Message "Internal error"
// @Router /teams [put]
func (t *Team) Create(a web.Auth) (err error) {
doer, err := getUserWithError(a)
doer, err := user.GetFromAuth(a)
if err != nil {
return err
}

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"testing"
"code.vikunja.io/web"
@ -28,7 +29,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
Name string
Description string
CreatedByID int64
CreatedBy *User
CreatedBy *user.User
Members []*TeamUser
Created int64
Updated int64
@ -50,7 +51,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
ID: 1,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
want: map[string]bool{"CanCreate": true, "IsAdmin": true, "CanRead": true, "CanDelete": true, "CanUpdate": true},
},
@ -60,7 +61,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
ID: 300,
},
args: args{
a: &User{ID: 1},
a: &user.User{ID: 1},
},
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
},
@ -70,7 +71,7 @@ func TestTeam_CanDoSomething(t *testing.T) {
ID: 1,
},
args: args{
a: &User{ID: 4},
a: &user.User{ID: 4},
},
want: map[string]bool{"CanCreate": true, "IsAdmin": false, "CanRead": false, "CanDelete": false, "CanUpdate": false},
},

View File

@ -17,6 +17,7 @@
package models
import (
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"reflect"
"testing"
@ -30,7 +31,7 @@ func TestTeam_Create(t *testing.T) {
}
// Doer
doer, err := GetUserByID(1)
doer, err := user.GetUserByID(1)
assert.NoError(t, err)
// Insert it

View File

@ -1,40 +1,26 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
import "github.com/go-xorm/builder"
// ListUsers returns a list with all users, filtered by an optional searchstring
func ListUsers(searchterm string) (users []User, err error) {
if searchterm == "" {
err = x.Find(&users)
} else {
err = x.
Where("username LIKE ?", "%"+searchterm+"%").
Find(&users)
}
if err != nil {
return []User{}, err
}
return users, nil
}
import (
"code.vikunja.io/api/pkg/user"
"github.com/go-xorm/builder"
)
// ListUIDs hold all kinds of user IDs from accounts who have somehow access to a list
type ListUIDs struct {
@ -47,7 +33,7 @@ type ListUIDs struct {
}
// ListUsersFromList returns a list with all users who have access to a list, regardless of the method which gave them access
func ListUsersFromList(l *List, search string) (users []*User, err error) {
func ListUsersFromList(l *List, search string) (users []*user.User, err error) {
userids := []*ListUIDs{}

View File

@ -1,7 +1,25 @@
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
import (
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/user"
"github.com/stretchr/testify/assert"
"gopkg.in/d4l3k/messagediff.v1"
"testing"
@ -12,27 +30,27 @@ func TestListUsersFromList(t *testing.T) {
err := db.LoadFixtures()
assert.NoError(t, err)
testuser1 := &User{
testuser1 := &user.User{
ID: 1,
Username: "user1",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "111d68d06e2d317b5a59c2c6c5bad808",
}
testuser2 := &User{
testuser2 := &user.User{
ID: 2,
Username: "user2",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
AvatarURL: "ab53a2911ddf9b4817ac01ddcd3d975f",
}
testuser3 := &User{
testuser3 := &user.User{
ID: 3,
Username: "user3",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
AvatarURL: "97d6d9441ff85fdc730e02a6068d267b",
PasswordResetToken: "passwordresettesttoken",
}
testuser4 := &User{
testuser4 := &user.User{
ID: 4,
Username: "user4",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -40,7 +58,7 @@ func TestListUsersFromList(t *testing.T) {
AvatarURL: "7e65550957227bd38fe2d7fbc6fd2f7b",
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
}
testuser5 := &User{
testuser5 := &user.User{
ID: 5,
Username: "user5",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -48,56 +66,56 @@ func TestListUsersFromList(t *testing.T) {
AvatarURL: "cfa35b8cd2ec278026357769582fa563",
EmailConfirmToken: "tiepiQueed8ahc7zeeFe1eveiy4Ein8osooxegiephauph2Ael",
}
testuser6 := &User{
testuser6 := &user.User{
ID: 6,
Username: "user6",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "3efbe51f864c6666bc27caf4c6ff90ed",
}
testuser7 := &User{
testuser7 := &user.User{
ID: 7,
Username: "user7",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "e80a711d4de44c30054806ebbd488464",
}
testuser8 := &User{
testuser8 := &user.User{
ID: 8,
Username: "user8",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "2b9b320416cd31020bb6844c3fadefd1",
}
testuser9 := &User{
testuser9 := &user.User{
ID: 9,
Username: "user9",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "f784fdb21d26dd2c64f5135f35ec401f",
}
testuser10 := &User{
testuser10 := &user.User{
ID: 10,
Username: "user10",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "fce8ff4ff56d75ad587d1bbaa5ef0563",
}
testuser11 := &User{
testuser11 := &user.User{
ID: 11,
Username: "user11",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "ad6d67d0c4495e186010732a7d360028",
}
testuser12 := &User{
testuser12 := &user.User{
ID: 12,
Username: "user12",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
IsActive: true,
AvatarURL: "ef1debc1364806281c42eeedfdeb943b",
}
testuser13 := &User{
testuser13 := &user.User{
ID: 13,
Username: "user13",
Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.",
@ -112,19 +130,19 @@ func TestListUsersFromList(t *testing.T) {
tests := []struct {
name string
args args
wantUsers []*User
wantUsers []*user.User
wantErr bool
}{
{
name: "Check owner only",
args: args{l: &List{ID: 18, OwnerID: 7}},
wantUsers: []*User{testuser7},
wantUsers: []*user.User{testuser7},
},
{
// This list has another different user shared for each possible method
name: "Check with owner and other users",
args: args{l: &List{ID: 19, OwnerID: 7}},
wantUsers: []*User{
wantUsers: []*user.User{
testuser1, // Shared Via Team readonly
testuser2, // Shared Via Team write
testuser3, // Shared Via Team admin

View File

@ -19,12 +19,13 @@ package migration
import (
"bytes"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"io/ioutil"
)
// InsertFromStructure takes a fully nested Vikunja data structure and a user and then creates everything for this user
// (Namespaces, tasks, etc. Even attachments and relations.)
func InsertFromStructure(str []*models.NamespaceWithLists, user *models.User) (err error) {
func InsertFromStructure(str []*models.NamespaceWithLists, user *user.User) (err error) {
// Create all namespaces
for _, n := range str {

View File

@ -19,6 +19,7 @@ package handler
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/modules/migration"
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -53,7 +54,7 @@ func (mw *MigrationWeb) Migrate(c echo.Context) error {
ms := mw.MigrationStruct()
// Get the user from context
user, err := models.GetCurrentUser(c)
user, err := user2.GetCurrentUser(c)
if err != nil {
return handler.HandleHTTPError(err, c)
}
@ -82,7 +83,7 @@ func (mw *MigrationWeb) Migrate(c echo.Context) error {
func (mw *MigrationWeb) Status(c echo.Context) error {
ms := mw.MigrationStruct()
user, err := models.GetCurrentUser(c)
user, err := user2.GetCurrentUser(c)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -16,7 +16,9 @@
package migration
import "code.vikunja.io/api/pkg/models"
import (
"code.vikunja.io/api/pkg/user"
)
// Status represents this migration status
type Status struct {
@ -32,7 +34,7 @@ func (s *Status) TableName() string {
}
// SetMigrationStatus sets the migration status for a user
func SetMigrationStatus(m Migrator, u *models.User) (err error) {
func SetMigrationStatus(m Migrator, u *user.User) (err error) {
status := &Status{
UserID: u.ID,
MigratorName: m.Name(),
@ -42,7 +44,7 @@ func SetMigrationStatus(m Migrator, u *models.User) (err error) {
}
// GetMigrationStatus returns the migration status for a migration and a user
func GetMigrationStatus(m Migrator, u *models.User) (status *Status, err error) {
func GetMigrationStatus(m Migrator, u *user.User) (status *Status, err error) {
status = &Status{}
_, err = x.Where("user_id = ? and migrator_name = ?", u.ID, m.Name()).Desc("id").Get(status)
return

View File

@ -17,13 +17,15 @@
package migration
import "code.vikunja.io/api/pkg/models"
import (
"code.vikunja.io/api/pkg/user"
)
// Migrator is the basic migrator interface which is shared among all migrators
type Migrator interface {
// Migrate is the interface used to migrate a user's tasks from another platform to vikunja.
// The user object is the user who's tasks will be migrated.
Migrate(user *models.User) error
Migrate(user *user.User) error
// AuthURL returns a url for clients to authenticate against.
// The use case for this are Oauth flows, where the server token should remain hidden and not
// known to the frontend.

View File

@ -23,6 +23,7 @@ import (
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/modules/migration"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/utils"
"encoding/json"
"fmt"
@ -341,7 +342,7 @@ func makeAuthGetRequest(token *wunderlistAuthToken, urlPart string, v interface{
// @Success 200 {object} models.Message "A message telling you everything was migrated successfully."
// @Failure 500 {object} models.Message "Internal server error"
// @Router /migration/wunderlist/migrate [post]
func (w *Migration) Migrate(user *models.User) (err error) {
func (w *Migration) Migrate(user *user.User) (err error) {
log.Debugf("[Wunderlist migration] Starting wunderlist migration for user %d", user.ID)

View File

@ -19,6 +19,7 @@ package v1
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo/v4"
@ -34,7 +35,7 @@ const (
)
// NewUserJWTAuthtoken generates and signes a new jwt token for a user. This is a global function to be able to call it from integration tests.
func NewUserJWTAuthtoken(user *models.User) (token string, err error) {
func NewUserJWTAuthtoken(user *user.User) (token string, err error) {
t := jwt.New(jwt.SigningMethodHS256)
// Set claims
@ -78,7 +79,7 @@ func GetAuthFromClaims(c echo.Context) (a web.Auth, err error) {
return models.GetLinkShareFromClaims(claims)
}
if typ == AuthTypeUser {
return models.GetUserFromClaims(claims)
return user.GetUserFromClaims(claims)
}
return nil, echo.NewHTTPError(http.StatusBadRequest, models.Message{Message: "Invalid JWT token."})
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -46,7 +47,7 @@ func GetListsByNamespaceID(c echo.Context) error {
}
// Get the lists
doer, err := models.GetCurrentUser(c)
doer, err := user.GetCurrentUser(c)
if err != nil {
return handler.HandleHTTPError(err, c)
}
@ -73,7 +74,7 @@ func getNamespace(c echo.Context) (namespace *models.Namespace, err error) {
}
// Check if the user has acces to that namespace
user, err := models.GetCurrentUser(c)
user, err := user.GetCurrentUser(c)
if err != nil {
return
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/dgrijalva/jwt-go"
"github.com/labstack/echo/v4"
@ -41,13 +42,13 @@ type Token struct {
// @Failure 403 {object} models.Message "Invalid username or password."
// @Router /login [post]
func Login(c echo.Context) error {
u := models.UserLogin{}
u := user2.UserLogin{}
if err := c.Bind(&u); err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"Please provide a username and password."})
}
// Check user
user, err := models.CheckUserCredentials(&u)
user, err := user2.CheckUserCredentials(&u)
if err != nil {
return handler.HandleHTTPError(err, c)
}
@ -80,7 +81,7 @@ func RenewToken(c echo.Context) error {
return echo.ErrBadRequest
}
user, err := models.GetUserFromClaims(claims)
user, err := user2.GetUserFromClaims(claims)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -45,7 +46,7 @@ func UploadTaskAttachment(c echo.Context) error {
}
// Rights check
user, err := models.GetCurrentUser(c)
user, err := user2.GetCurrentUser(c)
if err != nil {
return handler.HandleHTTPError(err, c)
}
@ -114,7 +115,7 @@ func GetTaskAttachment(c echo.Context) error {
}
// Rights check
user, err := models.GetCurrentUser(c)
user, err := user2.GetCurrentUser(c)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -19,6 +19,7 @@ package v1
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -40,13 +41,20 @@ func RegisterUser(c echo.Context) error {
return echo.ErrNotFound
}
// Check for Request Content
var datUser *models.APIUserPassword
var datUser *user.APIUserPassword
if err := c.Bind(&datUser); err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"No or invalid user model provided."})
}
// Insert the user
newUser, err := models.CreateUser(datUser.APIFormat())
newUser, err := user.CreateUser(datUser.APIFormat())
if err != nil {
return handler.HandleHTTPError(err, c)
}
// Add its namespace
newN := &models.Namespace{Name: newUser.Username, Description: newUser.Username + "'s namespace.", Owner: newUser}
err = newN.Create(newUser)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -36,12 +37,12 @@ import (
// @Router /user/confirm [post]
func UserConfirmEmail(c echo.Context) error {
// Check for Request Content
var emailConfirm models.EmailConfirm
var emailConfirm user.EmailConfirm
if err := c.Bind(&emailConfirm); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "No token provided.")
}
err := models.UserEmailConfirm(&emailConfirm)
err := user.UserEmailConfirm(&emailConfirm)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -1,65 +0,0 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package v1
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
"strconv"
)
// UserDelete is the handler to delete a user
func UserDelete(c echo.Context) error {
// TODO: only allow users to allow itself
id := c.Param("id")
// Make int
userID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return c.JSON(http.StatusBadRequest, models.Message{"User ID is invalid."})
}
// Check if the user exists
_, err = models.GetUserByID(userID)
if err != nil {
if models.IsErrUserDoesNotExist(err) {
return c.JSON(http.StatusNotFound, models.Message{"The user does not exist."})
}
return c.JSON(http.StatusInternalServerError, models.Message{"Could not get user."})
}
// Get the doer options
doer, err := models.GetCurrentUser(c)
if err != nil {
return err
}
// Delete it
err = models.DeleteUserByID(userID, doer)
if err != nil {
return handler.HandleHTTPError(err, c)
}
return c.JSON(http.StatusOK, models.Message{"success"})
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -38,7 +39,7 @@ import (
// @Router /users [get]
func UserList(c echo.Context) error {
s := c.QueryParam("s")
users, err := models.ListUsers(s)
users, err := user.ListUsers(s)
if err != nil {
return handler.HandleHTTPError(err, c)
}
@ -72,7 +73,7 @@ func ListUsersForList(c echo.Context) error {
}
list := models.List{ID: listID}
currentUser, err := models.GetCurrentUser(c)
currentUser, err := user.GetCurrentUser(c)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -36,12 +37,12 @@ import (
// @Router /user/password/reset [post]
func UserResetPassword(c echo.Context) error {
// Check for Request Content
var pwReset models.PasswordReset
var pwReset user.PasswordReset
if err := c.Bind(&pwReset); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "No password provided.")
}
err := models.UserPasswordReset(&pwReset)
err := user.UserPasswordReset(&pwReset)
if err != nil {
return handler.HandleHTTPError(err, c)
}
@ -62,7 +63,7 @@ func UserResetPassword(c echo.Context) error {
// @Router /user/password/token [post]
func UserRequestResetPasswordToken(c echo.Context) error {
// Check for Request Content
var pwTokenReset models.PasswordTokenRequest
var pwTokenReset user.PasswordTokenRequest
if err := c.Bind(&pwTokenReset); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "No username provided.")
}
@ -71,7 +72,7 @@ func UserRequestResetPasswordToken(c echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, err)
}
err := models.RequestUserPasswordResetToken(&pwTokenReset)
err := user.RequestUserPasswordResetToken(&pwTokenReset)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -17,7 +17,7 @@
package v1
import (
"code.vikunja.io/api/pkg/models"
user2 "code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -35,12 +35,12 @@ import (
// @Failure 500 {object} models.Message "Internal server error."
// @Router /user [get]
func UserShow(c echo.Context) error {
userInfos, err := models.GetCurrentUser(c)
userInfos, err := user2.GetCurrentUser(c)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
}
user, err := models.GetUserByID(userInfos.ID)
user, err := user2.GetUserByID(userInfos.ID)
if err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -18,6 +18,7 @@ package v1
import (
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"github.com/labstack/echo/v4"
"net/http"
@ -44,7 +45,7 @@ type UserPassword struct {
// @Router /user/password [post]
func UserChangePassword(c echo.Context) error {
// Check if the user is itself
doer, err := models.GetCurrentUser(c)
doer, err := user.GetCurrentUser(c)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Error getting current user.")
}
@ -56,16 +57,16 @@ func UserChangePassword(c echo.Context) error {
}
if newPW.OldPassword == "" {
return handler.HandleHTTPError(models.ErrEmptyOldPassword{}, c)
return handler.HandleHTTPError(user.ErrEmptyOldPassword{}, c)
}
// Check the current password
if _, err = models.CheckUserCredentials(&models.UserLogin{Username: doer.Username, Password: newPW.OldPassword}); err != nil {
if _, err = user.CheckUserCredentials(&user.UserLogin{Username: doer.Username, Password: newPW.OldPassword}); err != nil {
return handler.HandleHTTPError(err, c)
}
// Update the password
if err = models.UpdateUserPassword(doer, newPW.NewPassword); err != nil {
if err = user.UpdateUserPassword(doer, newPW.NewPassword); err != nil {
return handler.HandleHTTPError(err, c)
}

View File

@ -20,6 +20,7 @@ import (
"bytes"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web/handler"
"fmt"
"github.com/labstack/echo/v4"
@ -31,10 +32,10 @@ import (
"strings"
)
func getBasicAuthUserFromContext(c echo.Context) (user models.User, err error) {
u, is := c.Get("userBasicAuth").(models.User)
func getBasicAuthUserFromContext(c echo.Context) (user.User, error) {
u, is := c.Get("userBasicAuth").(user.User)
if !is {
return models.User{}, fmt.Errorf("user is not user element, is %s", reflect.TypeOf(c.Get("userBasicAuth")))
return user.User{}, fmt.Errorf("user is not user element, is %s", reflect.TypeOf(c.Get("userBasicAuth")))
}
return u, nil
}

View File

@ -19,6 +19,7 @@ package caldav
import (
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/models"
user2 "code.vikunja.io/api/pkg/user"
"github.com/samedi/caldav-go/data"
"github.com/samedi/caldav-go/errs"
"strconv"
@ -39,7 +40,7 @@ type VikunjaCaldavListStorage struct {
// Used when handling a single task, like updating
task *models.Task
// The current user
user *models.User
user *user2.User
isPrincipal bool
isEntry bool // Entry level handling should only return a link to the principal url
}

View File

@ -23,6 +23,7 @@ import (
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/models"
v1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/user"
"github.com/labstack/echo/v4"
"github.com/prometheus/client_golang/prometheus/promhttp"
"time"
@ -51,7 +52,7 @@ func setupMetrics(a *echo.Group) {
},
{
metrics.UserCountKey,
models.User{},
user.User{},
},
{
metrics.NamespaceCountKey,

View File

@ -53,6 +53,7 @@ import (
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/routes/caldav"
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
"code.vikunja.io/web/handler"
"github.com/asaskevich/govalidator"
@ -407,11 +408,11 @@ func registerCalDavRoutes(c *echo.Group) {
}
func caldavBasicAuth(username, password string, c echo.Context) (bool, error) {
creds := &models.UserLogin{
creds := &user.UserLogin{
Username: username,
Password: password,
}
u, err := models.CheckUserCredentials(creds)
u, err := user.CheckUserCredentials(creds)
if err != nil {
log.Errorf("Error during basic auth for caldav: %v", err)
return false, nil

50
pkg/user/db.go Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2018-2020 Vikunja and contriubtors. All rights reserved.
//
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package user
import (
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/log"
"github.com/go-xorm/xorm"
)
var x *xorm.Engine
// InitDB sets up the database connection to use in this module
func InitDB() (err error) {
x, err = db.CreateDBEngine()
if err != nil {
log.Criticalf("Could not connect to db: %v", err.Error())
return
}
// Cache
if config.CacheEnabled.GetBool() && config.CacheType.GetString() == "redis" {
db.RegisterTableStructsForCache(GetTables())
}
return nil
}
// GetTables returns all structs which are also a table.
func GetTables() []interface{} {
return []interface{}{
&User{},
}
}

291
pkg/user/error.go Normal file
View File

@ -0,0 +1,291 @@
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package user
import (
"code.vikunja.io/web"
"fmt"
"net/http"
)
// =====================
// User Operation Errors
// =====================
// ErrUsernameExists represents a "UsernameAlreadyExists" kind of error.
type ErrUsernameExists struct {
UserID int64
Username string
}
// IsErrUsernameExists checks if an error is a ErrUsernameExists.
func IsErrUsernameExists(err error) bool {
_, ok := err.(ErrUsernameExists)
return ok
}
func (err ErrUsernameExists) Error() string {
return fmt.Sprintf("User with that username already exists [user id: %d, username: %s]", err.UserID, err.Username)
}
// ErrorCodeUsernameExists holds the unique world-error code of this error
const ErrorCodeUsernameExists = 1001
// HTTPError holds the http error description
func (err ErrUsernameExists) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUsernameExists, Message: "A user with this username already exists."}
}
// ErrUserEmailExists represents a "UserEmailExists" kind of error.
type ErrUserEmailExists struct {
UserID int64
Email string
}
// IsErrUserEmailExists checks if an error is a ErrUserEmailExists.
func IsErrUserEmailExists(err error) bool {
_, ok := err.(ErrUserEmailExists)
return ok
}
func (err ErrUserEmailExists) Error() string {
return fmt.Sprintf("User with that email already exists [user id: %d, email: %s]", err.UserID, err.Email)
}
// ErrorCodeUserEmailExists holds the unique world-error code of this error
const ErrorCodeUserEmailExists = 1002
// HTTPError holds the http error description
func (err ErrUserEmailExists) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrorCodeUserEmailExists, Message: "A user with this email address already exists."}
}
// ErrNoUsernamePassword represents a "NoUsernamePassword" kind of error.
type ErrNoUsernamePassword struct{}
// IsErrNoUsernamePassword checks if an error is a ErrNoUsernamePassword.
func IsErrNoUsernamePassword(err error) bool {
_, ok := err.(ErrNoUsernamePassword)
return ok
}
func (err ErrNoUsernamePassword) Error() string {
return fmt.Sprintf("No username and password provided")
}
// ErrCodeNoUsernamePassword holds the unique world-error code of this error
const ErrCodeNoUsernamePassword = 1004
// HTTPError holds the http error description
func (err ErrNoUsernamePassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeNoUsernamePassword, Message: "Please specify a username and a password."}
}
// ErrUserDoesNotExist represents a "UserDoesNotExist" kind of error.
type ErrUserDoesNotExist struct {
UserID int64
}
// IsErrUserDoesNotExist checks if an error is a ErrUserDoesNotExist.
func IsErrUserDoesNotExist(err error) bool {
_, ok := err.(ErrUserDoesNotExist)
return ok
}
func (err ErrUserDoesNotExist) Error() string {
return fmt.Sprintf("User does not exist [user id: %d]", err.UserID)
}
// ErrCodeUserDoesNotExist holds the unique world-error code of this error
const ErrCodeUserDoesNotExist = 1005
// HTTPError holds the http error description
func (err ErrUserDoesNotExist) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusNotFound, Code: ErrCodeUserDoesNotExist, Message: "The user does not exist."}
}
// ErrCouldNotGetUserID represents a "ErrCouldNotGetUserID" kind of error.
type ErrCouldNotGetUserID struct{}
// IsErrCouldNotGetUserID checks if an error is a ErrCouldNotGetUserID.
func IsErrCouldNotGetUserID(err error) bool {
_, ok := err.(ErrCouldNotGetUserID)
return ok
}
func (err ErrCouldNotGetUserID) Error() string {
return fmt.Sprintf("Could not get user ID")
}
// ErrCodeCouldNotGetUserID holds the unique world-error code of this error
const ErrCodeCouldNotGetUserID = 1006
// HTTPError holds the http error description
func (err ErrCouldNotGetUserID) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusBadRequest, Code: ErrCodeCouldNotGetUserID, Message: "Could not get user id."}
}
// ErrNoPasswordResetToken represents an error where no password reset token exists for that user
type ErrNoPasswordResetToken struct {
UserID int64
}
func (err ErrNoPasswordResetToken) Error() string {
return fmt.Sprintf("No token to reset a password [UserID: %d]", err.UserID)
}
// ErrCodeNoPasswordResetToken holds the unique world-error code of this error
const ErrCodeNoPasswordResetToken = 1008
// HTTPError holds the http error description
func (err ErrNoPasswordResetToken) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeNoPasswordResetToken, Message: "No token to reset a user's password provided."}
}
// ErrInvalidPasswordResetToken is an error where the password reset token is invalid
type ErrInvalidPasswordResetToken struct {
Token string
}
func (err ErrInvalidPasswordResetToken) Error() string {
return fmt.Sprintf("Invalid token to reset a password [Token: %s]", err.Token)
}
// ErrCodeInvalidPasswordResetToken holds the unique world-error code of this error
const ErrCodeInvalidPasswordResetToken = 1009
// HTTPError holds the http error description
func (err ErrInvalidPasswordResetToken) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidPasswordResetToken, Message: "Invalid token to reset a user's password."}
}
// IsErrInvalidPasswordResetToken checks if an error is a ErrInvalidPasswordResetToken.
func IsErrInvalidPasswordResetToken(err error) bool {
_, ok := err.(ErrInvalidPasswordResetToken)
return ok
}
// ErrInvalidEmailConfirmToken is an error where the email confirm token is invalid
type ErrInvalidEmailConfirmToken struct {
Token string
}
func (err ErrInvalidEmailConfirmToken) Error() string {
return fmt.Sprintf("Invalid email confirm token [Token: %s]", err.Token)
}
// ErrCodeInvalidEmailConfirmToken holds the unique world-error code of this error
const ErrCodeInvalidEmailConfirmToken = 1010
// HTTPError holds the http error description
func (err ErrInvalidEmailConfirmToken) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeInvalidEmailConfirmToken, Message: "Invalid email confirm token."}
}
// IsErrInvalidEmailConfirmToken checks if an error is a ErrInvalidEmailConfirmToken.
func IsErrInvalidEmailConfirmToken(err error) bool {
_, ok := err.(ErrInvalidEmailConfirmToken)
return ok
}
// ErrWrongUsernameOrPassword is an error where the email was not confirmed
type ErrWrongUsernameOrPassword struct {
}
func (err ErrWrongUsernameOrPassword) Error() string {
return fmt.Sprintf("Wrong username or password")
}
// ErrCodeWrongUsernameOrPassword holds the unique world-error code of this error
const ErrCodeWrongUsernameOrPassword = 1011
// HTTPError holds the http error description
func (err ErrWrongUsernameOrPassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeWrongUsernameOrPassword, Message: "Wrong username or password."}
}
// IsErrWrongUsernameOrPassword checks if an error is a IsErrEmailNotConfirmed.
func IsErrWrongUsernameOrPassword(err error) bool {
_, ok := err.(ErrWrongUsernameOrPassword)
return ok
}
// ErrEmailNotConfirmed is an error where the email was not confirmed
type ErrEmailNotConfirmed struct {
UserID int64
}
func (err ErrEmailNotConfirmed) Error() string {
return fmt.Sprintf("Email is not confirmed [UserID: %d]", err.UserID)
}
// ErrCodeEmailNotConfirmed holds the unique world-error code of this error
const ErrCodeEmailNotConfirmed = 1012
// HTTPError holds the http error description
func (err ErrEmailNotConfirmed) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmailNotConfirmed, Message: "Please confirm your email address."}
}
// IsErrEmailNotConfirmed checks if an error is a IsErrEmailNotConfirmed.
func IsErrEmailNotConfirmed(err error) bool {
_, ok := err.(ErrEmailNotConfirmed)
return ok
}
// ErrEmptyNewPassword represents a "EmptyNewPassword" kind of error.
type ErrEmptyNewPassword struct{}
// IsErrEmptyNewPassword checks if an error is a ErrEmptyNewPassword.
func IsErrEmptyNewPassword(err error) bool {
_, ok := err.(ErrEmptyNewPassword)
return ok
}
func (err ErrEmptyNewPassword) Error() string {
return fmt.Sprintf("New password is empty")
}
// ErrCodeEmptyNewPassword holds the unique world-error code of this error
const ErrCodeEmptyNewPassword = 1013
// HTTPError holds the http error description
func (err ErrEmptyNewPassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyNewPassword, Message: "Please specify new password."}
}
// ErrEmptyOldPassword represents a "EmptyOldPassword" kind of error.
type ErrEmptyOldPassword struct{}
// IsErrEmptyOldPassword checks if an error is a ErrEmptyOldPassword.
func IsErrEmptyOldPassword(err error) bool {
_, ok := err.(ErrEmptyOldPassword)
return ok
}
func (err ErrEmptyOldPassword) Error() string {
return fmt.Sprintf("Old password is empty")
}
// ErrCodeEmptyOldPassword holds the unique world-error code of this error
const ErrCodeEmptyOldPassword = 1014
// HTTPError holds the http error description
func (err ErrEmptyOldPassword) HTTPError() web.HTTPError {
return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeEmptyOldPassword, Message: "Please specify old password."}
}

View File

@ -1,20 +1,21 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
package user
import (
"code.vikunja.io/api/pkg/config"
@ -76,7 +77,7 @@ func (User) TableName() string {
return "users"
}
func getUserWithError(a web.Auth) (*User, error) {
func GetFromAuth(a web.Auth) (*User, error) {
u, is := a.(*User)
if !is {
return &User{}, fmt.Errorf("user is not user element, is %s", reflect.TypeOf(a))
@ -273,13 +274,6 @@ func CreateUser(user *User) (newUser *User, err error) {
return &User{}, err
}
// Create the user's namespace
newN := &Namespace{Name: newUserOut.Username, Description: newUserOut.Username + "'s namespace.", Owner: newUserOut}
err = newN.Create(newUserOut)
if err != nil {
return &User{}, err
}
// Dont send a mail if we're testing
if !config.MailerEnabled.GetBool() {
return newUserOut, err
@ -361,23 +355,3 @@ func UpdateUserPassword(user *User, newPassword string) (err error) {
return err
}
// DeleteUserByID deletes a user by its ID
func DeleteUserByID(id int64, doer *User) error {
// Check if the id is 0
if id == 0 {
return ErrIDCannotBeZero{}
}
// Delete the user
_, err := x.Id(id).Delete(&User{})
if err != nil {
return err
}
// Update the metrics
metrics.UpdateCount(-1, metrics.ActiveUsersKey)
return err
}

View File

@ -1,20 +1,21 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
package user
// EmailConfirm holds the token to confirm a mail address
type EmailConfirm struct {

View File

@ -1,22 +1,25 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
package user
import "testing"
import (
"testing"
)
func TestUserEmailConfirm(t *testing.T) {
type args struct {

View File

@ -1,20 +1,21 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
package user
import (
"code.vikunja.io/api/pkg/config"

View File

@ -1,20 +1,21 @@
// Vikunja is a todo-list application to facilitate your life.
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package models
package user
import (
"code.vikunja.io/api/pkg/utils"
@ -132,15 +133,6 @@ func TestCreateUser(t *testing.T) {
err = UpdateUserPassword(&User{ID: 9999}, newpassword)
assert.Error(t, err)
assert.True(t, IsErrUserDoesNotExist(err))
// Delete it
err = DeleteUserByID(theuser.ID, doer)
assert.NoError(t, err)
// Try deleting one with ID = 0
err = DeleteUserByID(0, doer)
assert.Error(t, err)
assert.True(t, IsErrIDCannotBeZero(err))
}
func TestUserPasswordReset(t *testing.T) {

36
pkg/user/users_list.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2020 Vikunja and contriubtors. All rights reserved.
//
// This file is part of Vikunja.
//
// Vikunja is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vikunja is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vikunja. If not, see <https://www.gnu.org/licenses/>.
package user
// ListUsers returns a list with all users, filtered by an optional searchstring
func ListUsers(searchterm string) (users []User, err error) {
if searchterm == "" {
err = x.Find(&users)
} else {
err = x.
Where("username LIKE ?", "%"+searchterm+"%").
Find(&users)
}
if err != nil {
return []User{}, err
}
return users, nil
}