V3-1307 combine first and last name to full name (#1569)

* V3-1307 combine first and last name to full name
This commit is contained in:
Yehor Butko 2019-03-27 14:33:32 +02:00 committed by GitHub
parent bfdfebbde2
commit 86bf3dee9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 602 additions and 325 deletions

View File

@ -131,7 +131,7 @@ func addExampleProjectWithKey(key *string, createRegistrationTokenAddress, activ
} }
{ {
createUserQuery := fmt.Sprintf( createUserQuery := fmt.Sprintf(
"mutation {createUser(input:{email:\"%s\",password:\"%s\",firstName:\"%s\",lastName:\"\"}, secret:\"%s\" ){id,email,createdAt}}", "mutation {createUser(input:{email:\"%s\",password:\"%s\",fullName:\"%s\", shortName:\"\"}, secret:\"%s\" ){id,email,createdAt}}",
"example@mail.com", "example@mail.com",
"123a123", "123a123",
"Alice", "Alice",

View File

@ -4,8 +4,6 @@
package consoleql package consoleql
import ( import (
"fmt"
"github.com/graphql-go/graphql" "github.com/graphql-go/graphql"
"github.com/skyrings/skyring-common/tools/uuid" "github.com/skyrings/skyring-common/tools/uuid"
"go.uber.org/zap" "go.uber.org/zap"
@ -98,12 +96,16 @@ func rootMutation(log *zap.Logger, service *console.Service, mailService *mailse
rootObject := p.Info.RootValue.(map[string]interface{}) rootObject := p.Info.RootValue.(map[string]interface{})
origin := rootObject["origin"].(string) origin := rootObject["origin"].(string)
link := origin + rootObject[ActivationPath].(string) + token link := origin + rootObject[ActivationPath].(string) + token
userName := user.ShortName
if user.ShortName == "" {
userName = user.FullName
}
// TODO: think of a better solution // TODO: think of a better solution
go func() { go func() {
_ = mailService.SendRendered( _ = mailService.SendRendered(
p.Context, p.Context,
[]post.Address{{Address: user.Email, Name: user.FirstName}}, []post.Address{{Address: user.Email, Name: userName}},
&AccountActivationEmail{ &AccountActivationEmail{
Origin: origin, Origin: origin,
ActivationLink: link, ActivationLink: link,
@ -295,12 +297,17 @@ func rootMutation(log *zap.Logger, service *console.Service, mailService *mailse
// TODO: think of a better solution // TODO: think of a better solution
go func() { go func() {
for _, user := range users { for _, user := range users {
userName := user.ShortName
if user.ShortName == "" {
userName = user.FullName
}
_ = mailService.SendRendered( _ = mailService.SendRendered(
p.Context, p.Context,
[]post.Address{{Address: user.Email, Name: fmt.Sprintf("%s %s", user.FirstName, user.LastName)}}, []post.Address{{Address: user.Email, Name: userName}},
&ProjectInvitationEmail{ &ProjectInvitationEmail{
Origin: origin, Origin: origin,
UserName: user.FirstName, UserName: userName,
ProjectName: project.Name, ProjectName: project.Name,
SignInLink: signIn, SignInLink: signIn,
}, },

View File

@ -73,8 +73,8 @@ func TestGrapqhlMutation(t *testing.T) {
createUser := console.CreateUser{ createUser := console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "John", FullName: "John Roll",
LastName: "Roll", ShortName: "Roll",
Email: "test@email.com", Email: "test@email.com",
}, },
Password: "123a123", Password: "123a123",
@ -115,8 +115,8 @@ func TestGrapqhlMutation(t *testing.T) {
t.Run("Create user mutation", func(t *testing.T) { t.Run("Create user mutation", func(t *testing.T) {
newUser := console.CreateUser{ newUser := console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "Mickey", FullName: "Green Mickey",
LastName: "Green", ShortName: "Green",
Email: "u1@email.com", Email: "u1@email.com",
}, },
Password: "123a123", Password: "123a123",
@ -128,11 +128,11 @@ func TestGrapqhlMutation(t *testing.T) {
} }
query := fmt.Sprintf( query := fmt.Sprintf(
"mutation {createUser(input:{email:\"%s\",password:\"%s\",firstName:\"%s\",lastName:\"%s\"}, secret: \"%s\"){id,lastName,firstName,email,createdAt}}", "mutation {createUser(input:{email:\"%s\",password:\"%s\", fullName:\"%s\", shortName:\"%s\"}, secret: \"%s\"){id,shortName,fullName,email,createdAt}}",
newUser.Email, newUser.Email,
newUser.Password, newUser.Password,
newUser.FirstName, newUser.FullName,
newUser.LastName, newUser.ShortName,
regTokenTest.Secret, regTokenTest.Secret,
) )
@ -161,8 +161,8 @@ func TestGrapqhlMutation(t *testing.T) {
user, err := service.GetUser(authCtx, *uID) user, err := service.GetUser(authCtx, *uID)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, newUser.FirstName, user.FirstName) assert.Equal(t, newUser.FullName, user.FullName)
assert.Equal(t, newUser.LastName, user.LastName) assert.Equal(t, newUser.ShortName, user.ShortName)
}) })
testQuery := func(t *testing.T, query string) interface{} { testQuery := func(t *testing.T, query string) interface{} {
@ -187,7 +187,7 @@ func TestGrapqhlMutation(t *testing.T) {
t.Run("Update account mutation email only", func(t *testing.T) { t.Run("Update account mutation email only", func(t *testing.T) {
email := "new@email.com" email := "new@email.com"
query := fmt.Sprintf( query := fmt.Sprintf(
"mutation {updateAccount(input:{email:\"%s\"}){id,email,firstName,lastName,createdAt}}", "mutation {updateAccount(input:{email:\"%s\"}){id,email,fullName,shortName,createdAt}}",
email, email,
) )
@ -198,15 +198,15 @@ func TestGrapqhlMutation(t *testing.T) {
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID]) assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, email, user[consoleql.FieldEmail]) assert.Equal(t, email, user[consoleql.FieldEmail])
assert.Equal(t, rootUser.FirstName, user[consoleql.FieldFirstName]) assert.Equal(t, rootUser.FullName, user[consoleql.FieldFullName])
assert.Equal(t, rootUser.LastName, user[consoleql.FieldLastName]) assert.Equal(t, rootUser.ShortName, user[consoleql.FieldShortName])
}) })
t.Run("Update account mutation firstName only", func(t *testing.T) { t.Run("Update account mutation fullName only", func(t *testing.T) {
firstName := "George" fullName := "George"
query := fmt.Sprintf( query := fmt.Sprintf(
"mutation {updateAccount(input:{firstName:\"%s\"}){id,email,firstName,lastName,createdAt}}", "mutation {updateAccount(input:{fullName:\"%s\"}){id,email,fullName,shortName,createdAt}}",
firstName, fullName,
) )
result := testQuery(t, query) result := testQuery(t, query)
@ -216,15 +216,15 @@ func TestGrapqhlMutation(t *testing.T) {
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID]) assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail]) assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail])
assert.Equal(t, firstName, user[consoleql.FieldFirstName]) assert.Equal(t, fullName, user[consoleql.FieldFullName])
assert.Equal(t, rootUser.LastName, user[consoleql.FieldLastName]) assert.Equal(t, rootUser.ShortName, user[consoleql.FieldShortName])
}) })
t.Run("Update account mutation lastName only", func(t *testing.T) { t.Run("Update account mutation shortName only", func(t *testing.T) {
lastName := "Yellow" shortName := "Yellow"
query := fmt.Sprintf( query := fmt.Sprintf(
"mutation {updateAccount(input:{lastName:\"%s\"}){id,email,firstName,lastName,createdAt}}", "mutation {updateAccount(input:{shortName:\"%s\"}){id,email,fullName,shortName,createdAt}}",
lastName, shortName,
) )
result := testQuery(t, query) result := testQuery(t, query)
@ -234,20 +234,20 @@ func TestGrapqhlMutation(t *testing.T) {
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID]) assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail]) assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail])
assert.Equal(t, rootUser.FirstName, user[consoleql.FieldFirstName]) assert.Equal(t, rootUser.FullName, user[consoleql.FieldFullName])
assert.Equal(t, lastName, user[consoleql.FieldLastName]) assert.Equal(t, shortName, user[consoleql.FieldShortName])
}) })
t.Run("Update account mutation all info", func(t *testing.T) { t.Run("Update account mutation all info", func(t *testing.T) {
email := "test@newmail.com" email := "test@newmail.com"
firstName := "Fill" fullName := "Fill Goal"
lastName := "Goal" shortName := "Goal"
query := fmt.Sprintf( query := fmt.Sprintf(
"mutation {updateAccount(input:{email:\"%s\",firstName:\"%s\",lastName:\"%s\"}){id,email,firstName,lastName,createdAt}}", "mutation {updateAccount(input:{email:\"%s\",fullName:\"%s\",shortName:\"%s\"}){id,email,fullName,shortName,createdAt}}",
email, email,
firstName, fullName,
lastName, shortName,
) )
result := testQuery(t, query) result := testQuery(t, query)
@ -257,8 +257,8 @@ func TestGrapqhlMutation(t *testing.T) {
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID]) assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, email, user[consoleql.FieldEmail]) assert.Equal(t, email, user[consoleql.FieldEmail])
assert.Equal(t, firstName, user[consoleql.FieldFirstName]) assert.Equal(t, fullName, user[consoleql.FieldFullName])
assert.Equal(t, lastName, user[consoleql.FieldLastName]) assert.Equal(t, shortName, user[consoleql.FieldShortName])
createdAt := time.Time{} createdAt := time.Time{}
err := createdAt.UnmarshalText([]byte(user[consoleql.FieldCreatedAt].(string))) err := createdAt.UnmarshalText([]byte(user[consoleql.FieldCreatedAt].(string)))
@ -271,7 +271,7 @@ func TestGrapqhlMutation(t *testing.T) {
newPassword := "145a145a" newPassword := "145a145a"
query := fmt.Sprintf( query := fmt.Sprintf(
"mutation {changePassword(password:\"%s\",newPassword:\"%s\"){id,email,firstName,lastName,createdAt}}", "mutation {changePassword(password:\"%s\",newPassword:\"%s\"){id,email,fullName,shortName,createdAt}}",
createUser.Password, createUser.Password,
newPassword, newPassword,
) )
@ -283,8 +283,8 @@ func TestGrapqhlMutation(t *testing.T) {
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID]) assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail]) assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail])
assert.Equal(t, rootUser.FirstName, user[consoleql.FieldFirstName]) assert.Equal(t, rootUser.FullName, user[consoleql.FieldFullName])
assert.Equal(t, rootUser.LastName, user[consoleql.FieldLastName]) assert.Equal(t, rootUser.ShortName, user[consoleql.FieldShortName])
createdAt := time.Time{} createdAt := time.Time{}
err := createdAt.UnmarshalText([]byte(user[consoleql.FieldCreatedAt].(string))) err := createdAt.UnmarshalText([]byte(user[consoleql.FieldCreatedAt].(string)))
@ -374,8 +374,8 @@ func TestGrapqhlMutation(t *testing.T) {
user1, err := service.CreateUser(authCtx, console.CreateUser{ user1, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "User1", FullName: "User1",
Email: "u1@email.net", Email: "u1@email.net",
}, },
Password: "123a123", Password: "123a123",
}, regTokenUser1.Secret) }, regTokenUser1.Secret)
@ -406,8 +406,8 @@ func TestGrapqhlMutation(t *testing.T) {
user2, err := service.CreateUser(authCtx, console.CreateUser{ user2, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "User1", FullName: "User1",
Email: "u2@email.net", Email: "u2@email.net",
}, },
Password: "123a123", Password: "123a123",
}, regTokenUser2.Secret) }, regTokenUser2.Secret)

View File

@ -65,8 +65,8 @@ func TestGraphqlQuery(t *testing.T) {
createUser := console.CreateUser{ createUser := console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "John", FullName: "John",
LastName: "", ShortName: "",
Email: "mtest@email.com", Email: "mtest@email.com",
}, },
Password: "123a123", Password: "123a123",
@ -133,8 +133,8 @@ func TestGraphqlQuery(t *testing.T) {
testUser := func(t *testing.T, actual map[string]interface{}, expected *console.User) { testUser := func(t *testing.T, actual map[string]interface{}, expected *console.User) {
assert.Equal(t, expected.ID.String(), actual[consoleql.FieldID]) assert.Equal(t, expected.ID.String(), actual[consoleql.FieldID])
assert.Equal(t, expected.Email, actual[consoleql.FieldEmail]) assert.Equal(t, expected.Email, actual[consoleql.FieldEmail])
assert.Equal(t, expected.FirstName, actual[consoleql.FieldFirstName]) assert.Equal(t, expected.FullName, actual[consoleql.FieldFullName])
assert.Equal(t, expected.LastName, actual[consoleql.FieldLastName]) assert.Equal(t, expected.ShortName, actual[consoleql.FieldShortName])
createdAt := time.Time{} createdAt := time.Time{}
err := createdAt.UnmarshalText([]byte(actual[consoleql.FieldCreatedAt].(string))) err := createdAt.UnmarshalText([]byte(actual[consoleql.FieldCreatedAt].(string)))
@ -145,7 +145,7 @@ func TestGraphqlQuery(t *testing.T) {
t.Run("With ID", func(t *testing.T) { t.Run("With ID", func(t *testing.T) {
query := fmt.Sprintf( query := fmt.Sprintf(
"query {user(id:\"%s\"){id,email,firstName,lastName,createdAt}}", "query {user(id:\"%s\"){id,email,fullName,shortName,createdAt}}",
rootUser.ID.String(), rootUser.ID.String(),
) )
@ -158,7 +158,7 @@ func TestGraphqlQuery(t *testing.T) {
}) })
t.Run("With AuthFallback", func(t *testing.T) { t.Run("With AuthFallback", func(t *testing.T) {
query := "query {user{id,email,firstName,lastName,createdAt}}" query := "query {user{id,email,fullName,shortName,createdAt}}"
result := testQuery(t, query) result := testQuery(t, query)
@ -177,7 +177,7 @@ func TestGraphqlQuery(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// "query {project(id:\"%s\"){id,name,members(offset:0, limit:50){user{firstName,lastName,email}},apiKeys{name,id,createdAt,projectID}}}" // "query {project(id:\"%s\"){id,name,members(offset:0, limit:50){user{fullName,shortName,email}},apiKeys{name,id,createdAt,projectID}}}"
t.Run("Project query base info", func(t *testing.T) { t.Run("Project query base info", func(t *testing.T) {
query := fmt.Sprintf( query := fmt.Sprintf(
"query {project(id:\"%s\"){id,name,description,createdAt}}", "query {project(id:\"%s\"){id,name,description,createdAt}}",
@ -207,8 +207,8 @@ func TestGraphqlQuery(t *testing.T) {
user1, err := service.CreateUser(authCtx, console.CreateUser{ user1, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "Mickey", FullName: "Mickey Last",
LastName: "Last", ShortName: "Last",
Email: "muu1@email.com", Email: "muu1@email.com",
}, },
Password: "123a123", Password: "123a123",
@ -242,8 +242,8 @@ func TestGraphqlQuery(t *testing.T) {
user2, err := service.CreateUser(authCtx, console.CreateUser{ user2, err := service.CreateUser(authCtx, console.CreateUser{
UserInfo: console.UserInfo{ UserInfo: console.UserInfo{
FirstName: "Dubas", FullName: "Dubas Name",
LastName: "Name", ShortName: "Name",
Email: "muu2@email.com", Email: "muu2@email.com",
}, },
Password: "123a123", Password: "123a123",
@ -280,7 +280,7 @@ func TestGraphqlQuery(t *testing.T) {
t.Run("Project query team members", func(t *testing.T) { t.Run("Project query team members", func(t *testing.T) {
query := fmt.Sprintf( query := fmt.Sprintf(
"query {project(id:\"%s\"){members(offset:0, limit:50){user{id,firstName,lastName,email,createdAt}}}}", "query {project(id:\"%s\"){members(offset:0, limit:50){user{id,fullName,shortName,email,createdAt}}}}",
createdProject.ID.String(), createdProject.ID.String(),
) )
@ -294,8 +294,8 @@ func TestGraphqlQuery(t *testing.T) {
testUser := func(t *testing.T, actual map[string]interface{}, expected *console.User) { testUser := func(t *testing.T, actual map[string]interface{}, expected *console.User) {
assert.Equal(t, expected.Email, actual[consoleql.FieldEmail]) assert.Equal(t, expected.Email, actual[consoleql.FieldEmail])
assert.Equal(t, expected.FirstName, actual[consoleql.FieldFirstName]) assert.Equal(t, expected.FullName, actual[consoleql.FieldFullName])
assert.Equal(t, expected.LastName, actual[consoleql.FieldLastName]) assert.Equal(t, expected.ShortName, actual[consoleql.FieldShortName])
createdAt := time.Time{} createdAt := time.Time{}
err := createdAt.UnmarshalText([]byte(actual[consoleql.FieldCreatedAt].(string))) err := createdAt.UnmarshalText([]byte(actual[consoleql.FieldCreatedAt].(string)))
@ -436,7 +436,7 @@ func TestGraphqlQuery(t *testing.T) {
t.Run("Token query", func(t *testing.T) { t.Run("Token query", func(t *testing.T) {
query := fmt.Sprintf( query := fmt.Sprintf(
"query {token(email: \"%s\", password: \"%s\"){token,user{id,email,firstName,lastName,createdAt}}}", "query {token(email: \"%s\", password: \"%s\"){token,user{id,email,fullName,shortName,createdAt}}}",
createUser.Email, createUser.Email,
createUser.Password, createUser.Password,
) )
@ -457,8 +457,8 @@ func TestGraphqlQuery(t *testing.T) {
assert.Equal(t, rootUser.ID, tauth.User.ID) assert.Equal(t, rootUser.ID, tauth.User.ID)
assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID]) assert.Equal(t, rootUser.ID.String(), user[consoleql.FieldID])
assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail]) assert.Equal(t, rootUser.Email, user[consoleql.FieldEmail])
assert.Equal(t, rootUser.FirstName, user[consoleql.FieldFirstName]) assert.Equal(t, rootUser.FullName, user[consoleql.FieldFullName])
assert.Equal(t, rootUser.LastName, user[consoleql.FieldLastName]) assert.Equal(t, rootUser.ShortName, user[consoleql.FieldShortName])
createdAt := time.Time{} createdAt := time.Time{}
err = createdAt.UnmarshalText([]byte(user[consoleql.FieldCreatedAt].(string))) err = createdAt.UnmarshalText([]byte(user[consoleql.FieldCreatedAt].(string)))

View File

@ -20,10 +20,10 @@ const (
FieldEmail = "email" FieldEmail = "email"
// FieldPassword is a field name for password // FieldPassword is a field name for password
FieldPassword = "password" FieldPassword = "password"
// FieldFirstName is a field name for "first name" // FieldFullName is a field name for "first name"
FieldFirstName = "firstName" FieldFullName = "fullName"
// FieldLastName is a field name for "last name" // FieldShortName is a field name for "last name"
FieldLastName = "lastName" FieldShortName = "shortName"
// FieldCreatedAt is a field name for created at timestamp // FieldCreatedAt is a field name for created at timestamp
FieldCreatedAt = "createdAt" FieldCreatedAt = "createdAt"
) )
@ -39,10 +39,10 @@ func baseUserConfig() graphql.ObjectConfig {
FieldEmail: &graphql.Field{ FieldEmail: &graphql.Field{
Type: graphql.String, Type: graphql.String,
}, },
FieldFirstName: &graphql.Field{ FieldFullName: &graphql.Field{
Type: graphql.String, Type: graphql.String,
}, },
FieldLastName: &graphql.Field{ FieldShortName: &graphql.Field{
Type: graphql.String, Type: graphql.String,
}, },
FieldCreatedAt: &graphql.Field{ FieldCreatedAt: &graphql.Field{
@ -66,10 +66,10 @@ func graphqlUserInput(types Types) *graphql.InputObject {
FieldEmail: &graphql.InputObjectFieldConfig{ FieldEmail: &graphql.InputObjectFieldConfig{
Type: graphql.String, Type: graphql.String,
}, },
FieldFirstName: &graphql.InputObjectFieldConfig{ FieldFullName: &graphql.InputObjectFieldConfig{
Type: graphql.String, Type: graphql.String,
}, },
FieldLastName: &graphql.InputObjectFieldConfig{ FieldShortName: &graphql.InputObjectFieldConfig{
Type: graphql.String, Type: graphql.String,
}, },
FieldPassword: &graphql.InputObjectFieldConfig{ FieldPassword: &graphql.InputObjectFieldConfig{
@ -82,8 +82,8 @@ func graphqlUserInput(types Types) *graphql.InputObject {
// fromMapUserInfo creates UserInput from input args // fromMapUserInfo creates UserInput from input args
func fromMapUserInfo(args map[string]interface{}) (user console.UserInfo) { func fromMapUserInfo(args map[string]interface{}) (user console.UserInfo) {
user.Email, _ = args[FieldEmail].(string) user.Email, _ = args[FieldEmail].(string)
user.FirstName, _ = args[FieldFirstName].(string) user.FullName, _ = args[FieldFullName].(string)
user.LastName, _ = args[FieldLastName].(string) user.ShortName, _ = args[FieldShortName].(string)
return return
} }
@ -97,8 +97,8 @@ func fromMapCreateUser(args map[string]interface{}) (user console.CreateUser) {
func fillUserInfo(user *console.User, args map[string]interface{}) console.UserInfo { func fillUserInfo(user *console.User, args map[string]interface{}) console.UserInfo {
info := console.UserInfo{ info := console.UserInfo{
Email: user.Email, Email: user.Email,
FirstName: user.FirstName, FullName: user.FullName,
LastName: user.LastName, ShortName: user.ShortName,
} }
for fieldName, fieldValue := range args { for fieldName, fieldValue := range args {
@ -111,12 +111,12 @@ func fillUserInfo(user *console.User, args map[string]interface{}) console.UserI
case FieldEmail: case FieldEmail:
info.Email = value info.Email = value
user.Email = value user.Email = value
case FieldFirstName: case FieldFullName:
info.FirstName = value info.FullName = value
user.FirstName = value user.FullName = value
case FieldLastName: case FieldShortName:
info.LastName = value info.ShortName = value
user.LastName = value user.ShortName = value
} }
} }

View File

@ -107,7 +107,6 @@ func (s *Server) appHandler(w http.ResponseWriter, req *http.Request) {
} }
// accountActivationHandler is web app http handler function // accountActivationHandler is web app http handler function
// TODO: add some auth token in request header to prevent unauthorized token creation
func (s *Server) createRegistrationTokenHandler(w http.ResponseWriter, req *http.Request) { func (s *Server) createRegistrationTokenHandler(w http.ResponseWriter, req *http.Request) {
w.Header().Set(contentType, applicationJSON) w.Header().Set(contentType, applicationJSON)

View File

@ -44,7 +44,7 @@ type Pagination struct {
type ProjectMemberOrder int8 type ProjectMemberOrder int8
const ( const (
// Name indicates that we should order by first name // Name indicates that we should order by full name
Name ProjectMemberOrder = 1 Name ProjectMemberOrder = 1
// Email indicates that we should order by email // Email indicates that we should order by email
Email ProjectMemberOrder = 2 Email ProjectMemberOrder = 2

View File

@ -158,33 +158,33 @@ func prepareUsersAndProjects(ctx context.Context, t *testing.T, users console.Us
usersList := []*console.User{{ usersList := []*console.User{{
Email: "2email2@ukr.net", Email: "2email2@ukr.net",
PasswordHash: []byte("some_readable_hash"), PasswordHash: []byte("some_readable_hash"),
LastName: "Liam", ShortName: "Liam",
FirstName: "Jameson", FullName: "Liam Jameson",
}, { }, {
Email: "1email1@ukr.net", Email: "1email1@ukr.net",
PasswordHash: []byte("some_readable_hash"), PasswordHash: []byte("some_readable_hash"),
LastName: "William", ShortName: "William",
FirstName: "Noahson", FullName: "Noahson William",
}, { }, {
Email: "email3@ukr.net", Email: "email3@ukr.net",
PasswordHash: []byte("some_readable_hash"), PasswordHash: []byte("some_readable_hash"),
LastName: "Mason", ShortName: "Mason",
FirstName: "Elijahson", FullName: "Mason Elijahson",
}, { }, {
Email: "email4@ukr.net", Email: "email4@ukr.net",
PasswordHash: []byte("some_readable_hash"), PasswordHash: []byte("some_readable_hash"),
LastName: "Oliver", ShortName: "Oliver",
FirstName: "Jacobson", FullName: "Oliver Jacobson",
}, { }, {
Email: "email5@ukr.net", Email: "email5@ukr.net",
PasswordHash: []byte("some_readable_hash"), PasswordHash: []byte("some_readable_hash"),
LastName: "Lucas", ShortName: "Lucas",
FirstName: "Michaelson", FullName: "Michaelson Lucas",
}, { }, {
Email: "email6@ukr.net", Email: "email6@ukr.net",
PasswordHash: []byte("some_readable_hash"), PasswordHash: []byte("some_readable_hash"),
LastName: "Alexander", ShortName: "Alexander",
FirstName: "Ethanson", FullName: "Alexander Ethanson",
}, },
} }

View File

@ -18,10 +18,10 @@ func TestProjectsRepository(t *testing.T) {
//testing constants //testing constants
const ( const (
// for user // for user
lastName = "lastName" shortName = "lastName"
email = "email@ukr.net" email = "email@ukr.net"
pass = "123456" pass = "123456"
userName = "name" userFullName = "name"
// for project // for project
name = "Project" name = "Project"
@ -44,8 +44,8 @@ func TestProjectsRepository(t *testing.T) {
t.Run("Insert project successfully", func(t *testing.T) { t.Run("Insert project successfully", func(t *testing.T) {
var err error var err error
owner, err = users.Insert(ctx, &console.User{ owner, err = users.Insert(ctx, &console.User{
FirstName: userName, FullName: userFullName,
LastName: lastName, ShortName: shortName,
Email: email, Email: email,
PasswordHash: []byte(pass), PasswordHash: []byte(pass),
}) })

View File

@ -102,8 +102,8 @@ func (s *Service) CreateUser(ctx context.Context, user CreateUser, tokenSecret R
u, err = s.store.Users().Insert(ctx, &User{ u, err = s.store.Users().Insert(ctx, &User{
Email: user.Email, Email: user.Email,
FirstName: user.FirstName, FullName: user.FullName,
LastName: user.LastName, ShortName: user.ShortName,
PasswordHash: hash, PasswordHash: hash,
}) })
@ -222,8 +222,8 @@ func (s *Service) UpdateAccount(ctx context.Context, info UserInfo) (err error)
return s.store.Users().Update(ctx, &User{ return s.store.Users().Update(ctx, &User{
ID: auth.User.ID, ID: auth.User.ID,
FirstName: info.FirstName, FullName: info.FullName,
LastName: info.LastName, ShortName: info.ShortName,
Email: email, Email: email,
PasswordHash: nil, PasswordHash: nil,
}) })

View File

@ -27,8 +27,8 @@ type Users interface {
// UserInfo holds User updatable data. // UserInfo holds User updatable data.
type UserInfo struct { type UserInfo struct {
FirstName string `json:"firstName"` FullName string `json:"fullName"`
LastName string `json:"lastName"` ShortName string `json:"shortName"`
Email string `json:"email"` Email string `json:"email"`
} }
@ -40,9 +40,9 @@ func (user *UserInfo) IsValid() error {
_, err := mail.ParseAddress(user.Email) _, err := mail.ParseAddress(user.Email)
errs.AddWrap(err) errs.AddWrap(err)
// validate firstName // validate fullName
if user.FirstName == "" { if user.FullName == "" {
errs.Add("firstName can't be empty") errs.Add("fullName can't be empty")
} }
return errs.Combine() return errs.Combine()
@ -80,8 +80,8 @@ const (
type User struct { type User struct {
ID uuid.UUID `json:"id"` ID uuid.UUID `json:"id"`
FirstName string `json:"firstName"` FullName string `json:"fullName"`
LastName string `json:"lastName"` ShortName string `json:"shortName"`
Email string `json:"email"` Email string `json:"email"`
PasswordHash []byte `json:"passwordHash"` PasswordHash []byte `json:"passwordHash"`

View File

@ -41,8 +41,8 @@ func TestUserRepository(t *testing.T) {
user := &console.User{ user := &console.User{
ID: *id, ID: *id,
FirstName: name, FullName: name,
LastName: lastName, ShortName: lastName,
Email: email, Email: email,
PasswordHash: []byte(passValid), PasswordHash: []byte(passValid),
CreatedAt: time.Now(), CreatedAt: time.Now(),
@ -59,18 +59,18 @@ func TestUserRepository(t *testing.T) {
t.Run("Get user success", func(t *testing.T) { t.Run("Get user success", func(t *testing.T) {
userByEmail, err := repository.GetByEmail(ctx, email) userByEmail, err := repository.GetByEmail(ctx, email)
assert.Equal(t, userByEmail.FirstName, name) assert.Equal(t, userByEmail.FullName, name)
assert.Equal(t, userByEmail.LastName, lastName) assert.Equal(t, userByEmail.ShortName, lastName)
assert.NoError(t, err) assert.NoError(t, err)
userByID, err := repository.Get(ctx, userByEmail.ID) userByID, err := repository.Get(ctx, userByEmail.ID)
assert.Equal(t, userByID.FirstName, name) assert.Equal(t, userByID.FullName, name)
assert.Equal(t, userByID.LastName, lastName) assert.Equal(t, userByID.ShortName, lastName)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, userByID.ID, userByEmail.ID) assert.Equal(t, userByID.ID, userByEmail.ID)
assert.Equal(t, userByID.FirstName, userByEmail.FirstName) assert.Equal(t, userByID.FullName, userByEmail.FullName)
assert.Equal(t, userByID.LastName, userByEmail.LastName) assert.Equal(t, userByID.ShortName, userByEmail.ShortName)
assert.Equal(t, userByID.Email, userByEmail.Email) assert.Equal(t, userByID.Email, userByEmail.Email)
assert.Equal(t, userByID.PasswordHash, userByEmail.PasswordHash) assert.Equal(t, userByID.PasswordHash, userByEmail.PasswordHash)
assert.Equal(t, userByID.CreatedAt, userByEmail.CreatedAt) assert.Equal(t, userByID.CreatedAt, userByEmail.CreatedAt)
@ -82,8 +82,8 @@ func TestUserRepository(t *testing.T) {
newUser := &console.User{ newUser := &console.User{
ID: oldUser.ID, ID: oldUser.ID,
FirstName: newName, FullName: newName,
LastName: newLastName, ShortName: newLastName,
Email: newEmail, Email: newEmail,
Status: console.Active, Status: console.Active,
PasswordHash: []byte(newPass), PasswordHash: []byte(newPass),
@ -95,8 +95,8 @@ func TestUserRepository(t *testing.T) {
newUser, err = repository.Get(ctx, oldUser.ID) newUser, err = repository.Get(ctx, oldUser.ID)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, newUser.ID, oldUser.ID) assert.Equal(t, newUser.ID, oldUser.ID)
assert.Equal(t, newUser.FirstName, newName) assert.Equal(t, newUser.FullName, newName)
assert.Equal(t, newUser.LastName, newLastName) assert.Equal(t, newUser.ShortName, newLastName)
assert.Equal(t, newUser.Email, newEmail) assert.Equal(t, newUser.Email, newEmail)
assert.Equal(t, newUser.PasswordHash, []byte(newPass)) assert.Equal(t, newUser.PasswordHash, []byte(newPass))
assert.Equal(t, newUser.CreatedAt, oldUser.CreatedAt) assert.Equal(t, newUser.CreatedAt, oldUser.CreatedAt)

View File

@ -225,8 +225,8 @@ model user (
key id key id
field id blob field id blob
field first_name text ( updatable ) field full_name text ( updatable )
field last_name text ( updatable ) field short_name text ( updatable, nullable )
field email text ( updatable ) field email text ( updatable )
field password_hash blob ( updatable ) field password_hash blob ( updatable )

View File

@ -432,8 +432,8 @@ CREATE TABLE storagenode_storage_rollups (
); );
CREATE TABLE users ( CREATE TABLE users (
id bytea NOT NULL, id bytea NOT NULL,
first_name text NOT NULL, full_name text NOT NULL,
last_name text NOT NULL, short_name text,
email text NOT NULL, email text NOT NULL,
password_hash bytea NOT NULL, password_hash bytea NOT NULL,
status integer NOT NULL, status integer NOT NULL,
@ -690,8 +690,8 @@ CREATE TABLE storagenode_storage_rollups (
); );
CREATE TABLE users ( CREATE TABLE users (
id BLOB NOT NULL, id BLOB NOT NULL,
first_name TEXT NOT NULL, full_name TEXT NOT NULL,
last_name TEXT NOT NULL, short_name TEXT,
email TEXT NOT NULL, email TEXT NOT NULL,
password_hash BLOB NOT NULL, password_hash BLOB NOT NULL,
status INTEGER NOT NULL, status INTEGER NOT NULL,
@ -3094,8 +3094,8 @@ func (StoragenodeStorageRollup_Total_Field) _Column() string { return "total" }
type User struct { type User struct {
Id []byte Id []byte
FirstName string FullName string
LastName string ShortName *string
Email string Email string
PasswordHash []byte PasswordHash []byte
Status int Status int
@ -3104,9 +3104,13 @@ type User struct {
func (User) _Table() string { return "users" } func (User) _Table() string { return "users" }
type User_Create_Fields struct {
ShortName User_ShortName_Field
}
type User_Update_Fields struct { type User_Update_Fields struct {
FirstName User_FirstName_Field FullName User_FullName_Field
LastName User_LastName_Field ShortName User_ShortName_Field
Email User_Email_Field Email User_Email_Field
PasswordHash User_PasswordHash_Field PasswordHash User_PasswordHash_Field
Status User_Status_Field Status User_Status_Field
@ -3131,43 +3135,56 @@ func (f User_Id_Field) value() interface{} {
func (User_Id_Field) _Column() string { return "id" } func (User_Id_Field) _Column() string { return "id" }
type User_FirstName_Field struct { type User_FullName_Field struct {
_set bool _set bool
_null bool _null bool
_value string _value string
} }
func User_FirstName(v string) User_FirstName_Field { func User_FullName(v string) User_FullName_Field {
return User_FirstName_Field{_set: true, _value: v} return User_FullName_Field{_set: true, _value: v}
} }
func (f User_FirstName_Field) value() interface{} { func (f User_FullName_Field) value() interface{} {
if !f._set || f._null { if !f._set || f._null {
return nil return nil
} }
return f._value return f._value
} }
func (User_FirstName_Field) _Column() string { return "first_name" } func (User_FullName_Field) _Column() string { return "full_name" }
type User_LastName_Field struct { type User_ShortName_Field struct {
_set bool _set bool
_null bool _null bool
_value string _value *string
} }
func User_LastName(v string) User_LastName_Field { func User_ShortName(v string) User_ShortName_Field {
return User_LastName_Field{_set: true, _value: v} return User_ShortName_Field{_set: true, _value: &v}
} }
func (f User_LastName_Field) value() interface{} { func User_ShortName_Raw(v *string) User_ShortName_Field {
if v == nil {
return User_ShortName_Null()
}
return User_ShortName(*v)
}
func User_ShortName_Null() User_ShortName_Field {
return User_ShortName_Field{_set: true, _null: true}
}
func (f User_ShortName_Field) isnull() bool { return !f._set || f._null || f._value == nil }
func (f User_ShortName_Field) value() interface{} {
if !f._set || f._null { if !f._set || f._null {
return nil return nil
} }
return f._value return f._value
} }
func (User_LastName_Field) _Column() string { return "last_name" } func (User_ShortName_Field) _Column() string { return "short_name" }
type User_Email_Field struct { type User_Email_Field struct {
_set bool _set bool
@ -3907,28 +3924,28 @@ func (obj *postgresImpl) Create_Injuredsegment(ctx context.Context,
func (obj *postgresImpl) Create_User(ctx context.Context, func (obj *postgresImpl) Create_User(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
user_first_name User_FirstName_Field, user_full_name User_FullName_Field,
user_last_name User_LastName_Field,
user_email User_Email_Field, user_email User_Email_Field,
user_password_hash User_PasswordHash_Field) ( user_password_hash User_PasswordHash_Field,
optional User_Create_Fields) (
user *User, err error) { user *User, err error) {
__now := obj.db.Hooks.Now().UTC() __now := obj.db.Hooks.Now().UTC()
__id_val := user_id.value() __id_val := user_id.value()
__first_name_val := user_first_name.value() __full_name_val := user_full_name.value()
__last_name_val := user_last_name.value() __short_name_val := optional.ShortName.value()
__email_val := user_email.value() __email_val := user_email.value()
__password_hash_val := user_password_hash.value() __password_hash_val := user_password_hash.value()
__status_val := int(0) __status_val := int(0)
__created_at_val := __now __created_at_val := __now
var __embed_stmt = __sqlbundle_Literal("INSERT INTO users ( id, first_name, last_name, email, password_hash, status, created_at ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) RETURNING users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at") var __embed_stmt = __sqlbundle_Literal("INSERT INTO users ( id, full_name, short_name, email, password_hash, status, created_at ) VALUES ( ?, ?, ?, ?, ?, ?, ? ) RETURNING users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at")
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt) var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __id_val, __first_name_val, __last_name_val, __email_val, __password_hash_val, __status_val, __created_at_val) obj.logStmt(__stmt, __id_val, __full_name_val, __short_name_val, __email_val, __password_hash_val, __status_val, __created_at_val)
user = &User{} user = &User{}
err = obj.driver.QueryRow(__stmt, __id_val, __first_name_val, __last_name_val, __email_val, __password_hash_val, __status_val, __created_at_val).Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = obj.driver.QueryRow(__stmt, __id_val, __full_name_val, __short_name_val, __email_val, __password_hash_val, __status_val, __created_at_val).Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -4576,7 +4593,7 @@ func (obj *postgresImpl) Get_User_By_Email_And_Status_Not_Number(ctx context.Con
user_email User_Email_Field) ( user_email User_Email_Field) (
user *User, err error) { user *User, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.email = ? AND users.status != 0 LIMIT 2") var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.email = ? AND users.status != 0 LIMIT 2")
var __values []interface{} var __values []interface{}
__values = append(__values, user_email.value()) __values = append(__values, user_email.value())
@ -4598,7 +4615,7 @@ func (obj *postgresImpl) Get_User_By_Email_And_Status_Not_Number(ctx context.Con
} }
user = &User{} user = &User{}
err = __rows.Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = __rows.Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -4619,7 +4636,7 @@ func (obj *postgresImpl) Get_User_By_Id(ctx context.Context,
user_id User_Id_Field) ( user_id User_Id_Field) (
user *User, err error) { user *User, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.id = ?") var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.id = ?")
var __values []interface{} var __values []interface{}
__values = append(__values, user_id.value()) __values = append(__values, user_id.value())
@ -4628,7 +4645,7 @@ func (obj *postgresImpl) Get_User_By_Id(ctx context.Context,
obj.logStmt(__stmt, __values...) obj.logStmt(__stmt, __values...)
user = &User{} user = &User{}
err = obj.driver.QueryRow(__stmt, __values...).Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = obj.driver.QueryRow(__stmt, __values...).Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -5353,20 +5370,20 @@ func (obj *postgresImpl) Update_User_By_Id(ctx context.Context,
user *User, err error) { user *User, err error) {
var __sets = &__sqlbundle_Hole{} var __sets = &__sqlbundle_Hole{}
var __embed_stmt = __sqlbundle_Literals{Join: "", SQLs: []__sqlbundle_SQL{__sqlbundle_Literal("UPDATE users SET "), __sets, __sqlbundle_Literal(" WHERE users.id = ? RETURNING users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at")}} var __embed_stmt = __sqlbundle_Literals{Join: "", SQLs: []__sqlbundle_SQL{__sqlbundle_Literal("UPDATE users SET "), __sets, __sqlbundle_Literal(" WHERE users.id = ? RETURNING users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at")}}
__sets_sql := __sqlbundle_Literals{Join: ", "} __sets_sql := __sqlbundle_Literals{Join: ", "}
var __values []interface{} var __values []interface{}
var __args []interface{} var __args []interface{}
if update.FirstName._set { if update.FullName._set {
__values = append(__values, update.FirstName.value()) __values = append(__values, update.FullName.value())
__sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("first_name = ?")) __sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("full_name = ?"))
} }
if update.LastName._set { if update.ShortName._set {
__values = append(__values, update.LastName.value()) __values = append(__values, update.ShortName.value())
__sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("last_name = ?")) __sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("short_name = ?"))
} }
if update.Email._set { if update.Email._set {
@ -5397,7 +5414,7 @@ func (obj *postgresImpl) Update_User_By_Id(ctx context.Context,
obj.logStmt(__stmt, __values...) obj.logStmt(__stmt, __values...)
user = &User{} user = &User{}
err = obj.driver.QueryRow(__stmt, __values...).Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = obj.driver.QueryRow(__stmt, __values...).Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
} }
@ -6366,27 +6383,27 @@ func (obj *sqlite3Impl) Create_Injuredsegment(ctx context.Context,
func (obj *sqlite3Impl) Create_User(ctx context.Context, func (obj *sqlite3Impl) Create_User(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
user_first_name User_FirstName_Field, user_full_name User_FullName_Field,
user_last_name User_LastName_Field,
user_email User_Email_Field, user_email User_Email_Field,
user_password_hash User_PasswordHash_Field) ( user_password_hash User_PasswordHash_Field,
optional User_Create_Fields) (
user *User, err error) { user *User, err error) {
__now := obj.db.Hooks.Now().UTC() __now := obj.db.Hooks.Now().UTC()
__id_val := user_id.value() __id_val := user_id.value()
__first_name_val := user_first_name.value() __full_name_val := user_full_name.value()
__last_name_val := user_last_name.value() __short_name_val := optional.ShortName.value()
__email_val := user_email.value() __email_val := user_email.value()
__password_hash_val := user_password_hash.value() __password_hash_val := user_password_hash.value()
__status_val := int(0) __status_val := int(0)
__created_at_val := __now __created_at_val := __now
var __embed_stmt = __sqlbundle_Literal("INSERT INTO users ( id, first_name, last_name, email, password_hash, status, created_at ) VALUES ( ?, ?, ?, ?, ?, ?, ? )") var __embed_stmt = __sqlbundle_Literal("INSERT INTO users ( id, full_name, short_name, email, password_hash, status, created_at ) VALUES ( ?, ?, ?, ?, ?, ?, ? )")
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt) var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, __id_val, __first_name_val, __last_name_val, __email_val, __password_hash_val, __status_val, __created_at_val) obj.logStmt(__stmt, __id_val, __full_name_val, __short_name_val, __email_val, __password_hash_val, __status_val, __created_at_val)
__res, err := obj.driver.Exec(__stmt, __id_val, __first_name_val, __last_name_val, __email_val, __password_hash_val, __status_val, __created_at_val) __res, err := obj.driver.Exec(__stmt, __id_val, __full_name_val, __short_name_val, __email_val, __password_hash_val, __status_val, __created_at_val)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -7062,7 +7079,7 @@ func (obj *sqlite3Impl) Get_User_By_Email_And_Status_Not_Number(ctx context.Cont
user_email User_Email_Field) ( user_email User_Email_Field) (
user *User, err error) { user *User, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.email = ? AND users.status != 0 LIMIT 2") var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.email = ? AND users.status != 0 LIMIT 2")
var __values []interface{} var __values []interface{}
__values = append(__values, user_email.value()) __values = append(__values, user_email.value())
@ -7084,7 +7101,7 @@ func (obj *sqlite3Impl) Get_User_By_Email_And_Status_Not_Number(ctx context.Cont
} }
user = &User{} user = &User{}
err = __rows.Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = __rows.Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -7105,7 +7122,7 @@ func (obj *sqlite3Impl) Get_User_By_Id(ctx context.Context,
user_id User_Id_Field) ( user_id User_Id_Field) (
user *User, err error) { user *User, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.id = ?") var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.id = ?")
var __values []interface{} var __values []interface{}
__values = append(__values, user_id.value()) __values = append(__values, user_id.value())
@ -7114,7 +7131,7 @@ func (obj *sqlite3Impl) Get_User_By_Id(ctx context.Context,
obj.logStmt(__stmt, __values...) obj.logStmt(__stmt, __values...)
user = &User{} user = &User{}
err = obj.driver.QueryRow(__stmt, __values...).Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = obj.driver.QueryRow(__stmt, __values...).Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -7885,14 +7902,14 @@ func (obj *sqlite3Impl) Update_User_By_Id(ctx context.Context,
var __values []interface{} var __values []interface{}
var __args []interface{} var __args []interface{}
if update.FirstName._set { if update.FullName._set {
__values = append(__values, update.FirstName.value()) __values = append(__values, update.FullName.value())
__sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("first_name = ?")) __sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("full_name = ?"))
} }
if update.LastName._set { if update.ShortName._set {
__values = append(__values, update.LastName.value()) __values = append(__values, update.ShortName.value())
__sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("last_name = ?")) __sets_sql.SQLs = append(__sets_sql.SQLs, __sqlbundle_Literal("short_name = ?"))
} }
if update.Email._set { if update.Email._set {
@ -7928,12 +7945,12 @@ func (obj *sqlite3Impl) Update_User_By_Id(ctx context.Context,
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
var __embed_stmt_get = __sqlbundle_Literal("SELECT users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.id = ?") var __embed_stmt_get = __sqlbundle_Literal("SELECT users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE users.id = ?")
var __stmt_get = __sqlbundle_Render(obj.dialect, __embed_stmt_get) var __stmt_get = __sqlbundle_Render(obj.dialect, __embed_stmt_get)
obj.logStmt("(IMPLIED) "+__stmt_get, __args...) obj.logStmt("(IMPLIED) "+__stmt_get, __args...)
err = obj.driver.QueryRow(__stmt_get, __args...).Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = obj.driver.QueryRow(__stmt_get, __args...).Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
} }
@ -8608,13 +8625,13 @@ func (obj *sqlite3Impl) getLastUser(ctx context.Context,
pk int64) ( pk int64) (
user *User, err error) { user *User, err error) {
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.first_name, users.last_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE _rowid_ = ?") var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.full_name, users.short_name, users.email, users.password_hash, users.status, users.created_at FROM users WHERE _rowid_ = ?")
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt) var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
obj.logStmt(__stmt, pk) obj.logStmt(__stmt, pk)
user = &User{} user = &User{}
err = obj.driver.QueryRow(__stmt, pk).Scan(&user.Id, &user.FirstName, &user.LastName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt) err = obj.driver.QueryRow(__stmt, pk).Scan(&user.Id, &user.FullName, &user.ShortName, &user.Email, &user.PasswordHash, &user.Status, &user.CreatedAt)
if err != nil { if err != nil {
return nil, obj.makeErr(err) return nil, obj.makeErr(err)
} }
@ -9346,16 +9363,16 @@ func (rx *Rx) Create_UsedSerial(ctx context.Context,
func (rx *Rx) Create_User(ctx context.Context, func (rx *Rx) Create_User(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
user_first_name User_FirstName_Field, user_full_name User_FullName_Field,
user_last_name User_LastName_Field,
user_email User_Email_Field, user_email User_Email_Field,
user_password_hash User_PasswordHash_Field) ( user_password_hash User_PasswordHash_Field,
optional User_Create_Fields) (
user *User, err error) { user *User, err error) {
var tx *Tx var tx *Tx
if tx, err = rx.getTx(ctx); err != nil { if tx, err = rx.getTx(ctx); err != nil {
return return
} }
return tx.Create_User(ctx, user_id, user_first_name, user_last_name, user_email, user_password_hash) return tx.Create_User(ctx, user_id, user_full_name, user_email, user_password_hash, optional)
} }
@ -9990,10 +10007,10 @@ type Methods interface {
Create_User(ctx context.Context, Create_User(ctx context.Context,
user_id User_Id_Field, user_id User_Id_Field,
user_first_name User_FirstName_Field, user_full_name User_FullName_Field,
user_last_name User_LastName_Field,
user_email User_Email_Field, user_email User_Email_Field,
user_password_hash User_PasswordHash_Field) ( user_password_hash User_PasswordHash_Field,
optional User_Create_Fields) (
user *User, err error) user *User, err error)
Delete_AccountingRaw_By_Id(ctx context.Context, Delete_AccountingRaw_By_Id(ctx context.Context,

View File

@ -161,8 +161,8 @@ CREATE TABLE storagenode_storage_rollups (
); );
CREATE TABLE users ( CREATE TABLE users (
id bytea NOT NULL, id bytea NOT NULL,
first_name text NOT NULL, full_name text NOT NULL,
last_name text NOT NULL, short_name text,
email text NOT NULL, email text NOT NULL,
password_hash bytea NOT NULL, password_hash bytea NOT NULL,
status integer NOT NULL, status integer NOT NULL,

View File

@ -161,8 +161,8 @@ CREATE TABLE storagenode_storage_rollups (
); );
CREATE TABLE users ( CREATE TABLE users (
id BLOB NOT NULL, id BLOB NOT NULL,
first_name TEXT NOT NULL, full_name TEXT NOT NULL,
last_name TEXT NOT NULL, short_name TEXT,
email TEXT NOT NULL, email TEXT NOT NULL,
password_hash BLOB NOT NULL, password_hash BLOB NOT NULL,
status INTEGER NOT NULL, status INTEGER NOT NULL,

View File

@ -430,6 +430,15 @@ func (db *DB) PostgresMigration() *migrate.Migration {
rollup_end_time )`, rollup_end_time )`,
}, },
}, },
{
Description: "users first_name to full_name, last_name to short_name",
Version: 10,
Action: migrate.SQL{
`ALTER TABLE users RENAME COLUMN first_name TO full_name;
ALTER TABLE users ALTER COLUMN last_name DROP NOT NULL;
ALTER TABLE users RENAME COLUMN last_name TO short_name;`,
},
},
}, },
} }
} }

View File

@ -48,8 +48,8 @@ func (pm *projectMembers) GetByProjectID(ctx context.Context, projectID uuid.UUI
INNER JOIN users u ON pm.member_id = u.id INNER JOIN users u ON pm.member_id = u.id
WHERE pm.project_id = ? WHERE pm.project_id = ?
AND ( u.email LIKE ? OR AND ( u.email LIKE ? OR
u.first_name || u.last_name LIKE ? OR u.full_name LIKE ? OR
u.last_name || u.first_name LIKE ? ) u.short_name LIKE ? )
ORDER BY ` + sanitizedOrderColumnName(pagination.Order) + ` ASC ORDER BY ` + sanitizedOrderColumnName(pagination.Order) + ` ASC
LIMIT ? OFFSET ? LIMIT ? OFFSET ?
`) `)
@ -150,7 +150,7 @@ func sanitizedOrderColumnName(pmo console.ProjectMemberOrder) string {
case 3: case 3:
return "u.created_at" return "u.created_at"
default: default:
return "u.first_name" return "u.full_name"
} }
} }

View File

@ -16,11 +16,11 @@ func TestSanitizedOrderColumnName(t *testing.T) {
orderNumber int8 orderNumber int8
orderColumn string orderColumn string
}{ }{
0: {0, "u.first_name"}, 0: {0, "u.full_name"},
1: {1, "u.first_name"}, 1: {1, "u.full_name"},
2: {2, "u.email"}, 2: {2, "u.email"},
3: {3, "u.created_at"}, 3: {3, "u.created_at"},
4: {4, "u.first_name"}, 4: {4, "u.full_name"},
} }
for _, tc := range testCases { for _, tc := range testCases {

View File

@ -0,0 +1,235 @@
-- Copied from the corresponding version of dbx generated schema
CREATE TABLE accounting_raws (
id bigserial NOT NULL,
node_id bytea NOT NULL,
interval_end_time timestamp with time zone NOT NULL,
data_total double precision NOT NULL,
data_type integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE accounting_rollups (
id bigserial NOT NULL,
node_id bytea NOT NULL,
start_time timestamp with time zone NOT NULL,
put_total bigint NOT NULL,
get_total bigint NOT NULL,
get_audit_total bigint NOT NULL,
get_repair_total bigint NOT NULL,
put_repair_total bigint NOT NULL,
at_rest_total double precision NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE accounting_timestamps (
name text NOT NULL,
value timestamp with time zone NOT NULL,
PRIMARY KEY ( name )
);
CREATE TABLE bucket_bandwidth_rollups (
bucket_id bytea NOT NULL,
interval_start timestamp NOT NULL,
interval_seconds integer NOT NULL,
action integer NOT NULL,
inline bigint NOT NULL,
allocated bigint NOT NULL,
settled bigint NOT NULL,
PRIMARY KEY ( bucket_id, interval_start, action )
);
CREATE TABLE bucket_storage_rollups (
bucket_id bytea NOT NULL,
interval_start timestamp NOT NULL,
interval_seconds integer NOT NULL,
inline bigint NOT NULL,
remote bigint NOT NULL,
PRIMARY KEY ( bucket_id, interval_start )
);
CREATE TABLE bucket_usages (
id bytea NOT NULL,
bucket_id bytea NOT NULL,
rollup_end_time timestamp with time zone NOT NULL,
remote_stored_data bigint NOT NULL,
inline_stored_data bigint NOT NULL,
remote_segments integer NOT NULL,
inline_segments integer NOT NULL,
objects integer NOT NULL,
metadata_size bigint NOT NULL,
repair_egress bigint NOT NULL,
get_egress bigint NOT NULL,
audit_egress bigint NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE bwagreements (
serialnum text NOT NULL,
storage_node_id bytea NOT NULL,
uplink_id bytea NOT NULL,
action bigint NOT NULL,
total bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
expires_at timestamp with time zone NOT NULL,
PRIMARY KEY ( serialnum )
);
CREATE TABLE certRecords (
publickey bytea NOT NULL,
id bytea NOT NULL,
update_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE injuredsegments (
id bigserial NOT NULL,
info bytea NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE irreparabledbs (
segmentpath bytea NOT NULL,
segmentdetail bytea NOT NULL,
pieces_lost_count bigint NOT NULL,
seg_damaged_unix_sec bigint NOT NULL,
repair_attempt_count bigint NOT NULL,
PRIMARY KEY ( segmentpath )
);
CREATE TABLE nodes (
id bytea NOT NULL,
audit_success_count bigint NOT NULL,
total_audit_count bigint NOT NULL,
audit_success_ratio double precision NOT NULL,
uptime_success_count bigint NOT NULL,
total_uptime_count bigint NOT NULL,
uptime_ratio double precision NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
wallet text NOT NULL,
email text NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE overlay_cache_nodes (
node_id bytea NOT NULL,
node_type integer NOT NULL,
address text NOT NULL,
protocol integer NOT NULL,
operator_email text NOT NULL,
operator_wallet text NOT NULL,
free_bandwidth bigint NOT NULL,
free_disk bigint NOT NULL,
latency_90 bigint NOT NULL,
audit_success_ratio double precision NOT NULL,
audit_uptime_ratio double precision NOT NULL,
audit_count bigint NOT NULL,
audit_success_count bigint NOT NULL,
uptime_count bigint NOT NULL,
uptime_success_count bigint NOT NULL,
PRIMARY KEY ( node_id ),
UNIQUE ( node_id )
);
CREATE TABLE projects (
id bytea NOT NULL,
name text NOT NULL,
description text NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE registration_tokens (
secret bytea NOT NULL,
owner_id bytea,
project_limit integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( secret ),
UNIQUE ( owner_id )
);
CREATE TABLE serial_numbers (
id serial NOT NULL,
serial_number bytea NOT NULL,
bucket_id bytea NOT NULL,
expires_at timestamp NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE storagenode_bandwidth_rollups (
storagenode_id bytea NOT NULL,
interval_start timestamp NOT NULL,
interval_seconds integer NOT NULL,
action integer NOT NULL,
allocated bigint NOT NULL,
settled bigint NOT NULL,
PRIMARY KEY ( storagenode_id, interval_start, action )
);
CREATE TABLE storagenode_storage_rollups (
storagenode_id bytea NOT NULL,
interval_start timestamp NOT NULL,
interval_seconds integer NOT NULL,
total bigint NOT NULL,
PRIMARY KEY ( storagenode_id, interval_start )
);
CREATE TABLE users (
id bytea NOT NULL,
full_name text NOT NULL,
short_name text,
email text NOT NULL,
password_hash bytea NOT NULL,
status integer NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id )
);
CREATE TABLE api_keys (
id bytea NOT NULL,
project_id bytea NOT NULL REFERENCES projects( id ) ON DELETE CASCADE,
key bytea NOT NULL,
name text NOT NULL,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( id ),
UNIQUE ( key ),
UNIQUE ( name, project_id )
);
CREATE TABLE project_members (
member_id bytea NOT NULL REFERENCES users( id ) ON DELETE CASCADE,
project_id bytea NOT NULL REFERENCES projects( id ) ON DELETE CASCADE,
created_at timestamp with time zone NOT NULL,
PRIMARY KEY ( member_id, project_id )
);
CREATE TABLE used_serials (
serial_number_id integer NOT NULL REFERENCES serial_numbers( id ) ON DELETE CASCADE,
storage_node_id bytea NOT NULL,
PRIMARY KEY ( serial_number_id, storage_node_id )
);
CREATE INDEX bucket_id_interval_start_interval_seconds ON bucket_bandwidth_rollups ( bucket_id, interval_start, interval_seconds );
CREATE UNIQUE INDEX bucket_id_rollup ON bucket_usages ( bucket_id, rollup_end_time );
CREATE UNIQUE INDEX serial_number ON serial_numbers ( serial_number );
CREATE INDEX serial_numbers_expires_at_index ON serial_numbers ( expires_at );
CREATE INDEX storagenode_id_interval_start_interval_seconds ON storagenode_bandwidth_rollups ( storagenode_id, interval_start, interval_seconds );
---
INSERT INTO "accounting_raws" VALUES (1, E'\\3510\\323\\225"~\\036<\\342\\330m\\0253Jhr\\246\\233K\\246#\\2303\\351\\256\\275j\\212UM\\362\\207', '2019-02-14 08:16:57.812849+00', 1000, 0, '2019-02-14 08:16:57.844849+00');
INSERT INTO "accounting_rollups"("id", "node_id", "start_time", "put_total", "get_total", "get_audit_total", "get_repair_total", "put_repair_total", "at_rest_total") VALUES (1, E'\\367M\\177\\251]t/\\022\\256\\214\\265\\025\\224\\204:\\217\\212\\0102<\\321\\374\\020&\\271Qc\\325\\261\\354\\246\\233'::bytea, '2019-02-09 00:00:00+00', 1000, 2000, 3000, 4000, 0, 5000);
INSERT INTO "accounting_timestamps" VALUES ('LastAtRestTally', '0001-01-01 00:00:00+00');
INSERT INTO "accounting_timestamps" VALUES ('LastRollup', '0001-01-01 00:00:00+00');
INSERT INTO "accounting_timestamps" VALUES ('LastBandwidthTally', '0001-01-01 00:00:00+00');
INSERT INTO "nodes" VALUES (E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n', 0, 0, 0, 3, 3, 1, '2019-02-14 08:07:31.028103+00', '2019-02-14 08:07:31.108963+00', '', '');
INSERT INTO "overlay_cache_nodes" VALUES (E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n', 4, '127.0.0.1:55518', 0, 'bootstrap@example.com', '0x0000000000000000000000000000000000000000', -1, -1, 0, 0, 1, 0, 0, 2, 2);
INSERT INTO "projects"("id", "name", "description", "created_at") VALUES (E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, 'ProjectName', 'projects description', '2019-02-14 08:28:24.254934+00');
INSERT INTO "api_keys"("id", "project_id", "key", "name", "created_at") VALUES (E'\\334/\\302;\\225\\355O\\323\\276f\\247\\354/6\\241\\033'::bytea, E'\\022\\217/\\014\\376!K\\023\\276\\031\\311}m\\236\\205\\300'::bytea, E'\\000]\\326N \\343\\270L\\327\\027\\337\\242\\240\\322mOl\\0318\\251.P I'::bytea, 'key 2', '2019-02-14 08:28:24.267934+00');
INSERT INTO "users"("id", "full_name", "short_name", "email", "password_hash", "status", "created_at") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, 'Noahson', 'William', '1email1@ukr.net', E'some_readable_hash'::bytea, 1, '2019-02-14 08:28:24.614594+00');
INSERT INTO "projects"("id", "name", "description", "created_at") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea, 'projName1', 'Test project 1', '2019-02-14 08:28:24.636949+00');
INSERT INTO "project_members"("member_id", "project_id", "created_at") VALUES (E'\\363\\311\\033w\\222\\303Ci\\265\\343U\\303\\312\\204",'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014'::bytea, '2019-02-14 08:28:24.677953+00');
INSERT INTO "bwagreements"("serialnum", "storage_node_id", "action", "total", "created_at", "expires_at", "uplink_id") VALUES ('8fc0ceaa-984c-4d52-bcf4-b5429e1e35e812FpiifDbcJkePa12jxjDEutKrfLmwzT7sz2jfVwpYqgtM8B74c', E'\\245Z[/\\333\\022\\011\\001\\036\\003\\204\\005\\032.\\206\\333E\\261\\342\\227=y,}aRaH6\\240\\370\\000'::bytea, 1, 666, '2019-02-14 15:09:54.420181+00', '2019-02-14 16:09:54+00', E'\\253Z+\\374eFm\\245$\\036\\206\\335\\247\\263\\350x\\\\\\304+\\364\\343\\364+\\276fIJQ\\361\\014\\232\\000'::bytea);
INSERT INTO "irreparabledbs" ("segmentpath", "segmentdetail", "pieces_lost_count", "seg_damaged_unix_sec", "repair_attempt_count") VALUES ('\x49616d5365676d656e746b6579696e666f30', '\x49616d5365676d656e7464657461696c696e666f30', 10, 1550159554, 10);
INSERT INTO "injuredsegments" ("id", "info") VALUES (1, '\x0a0130120100');
INSERT INTO "certrecords" VALUES (E'0Y0\\023\\006\\007*\\206H\\316=\\002\\001\\006\\010*\\206H\\316=\\003\\001\\007\\003B\\000\\004\\360\\267\\227\\377\\253u\\222\\337Y\\324C:GQ\\010\\277v\\010\\315D\\271\\333\\337.\\203\\023=C\\343\\014T%6\\027\\362?\\214\\326\\017U\\334\\000\\260\\224\\260J\\221\\304\\331F\\304\\221\\236zF,\\325\\326l\\215\\306\\365\\200\\022', E'L\\301|\\200\\247}F|1\\320\\232\\037n\\335\\241\\206\\244\\242\\207\\204.\\253\\357\\326\\352\\033Dt\\202`\\022\\325', '2019-02-14 08:07:31.335028+00');
INSERT INTO "bucket_usages" ("id", "bucket_id", "rollup_end_time", "remote_stored_data", "inline_stored_data", "remote_segments", "inline_segments", "objects", "metadata_size", "repair_egress", "get_egress", "audit_egress") VALUES (E'\\153\\313\\233\\074\\327\\177\\136\\070\\346\\001",'::bytea, E'\\366\\146\\032\\321\\316\\161\\070\\133\\302\\271",'::bytea, '2019-03-06 08:28:24.677953+00', 10, 11, 12, 13, 14, 15, 16, 17, 18);
INSERT INTO "registration_tokens" ("secret", "owner_id", "project_limit", "created_at") VALUES (E'\\070\\127\\144\\013\\332\\344\\102\\376\\306\\056\\303\\130\\106\\132\\321\\276\\321\\274\\170\\264\\054\\333\\221\\116\\154\\221\\335\\070\\220\\146\\344\\216'::bytea, null, 1, '2019-02-14 08:28:24.677953+00');
INSERT INTO "serial_numbers" ("id", "serial_number", "bucket_id", "expires_at") VALUES (1, E'0123456701234567'::bytea, E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014/testbucket'::bytea, '2019-03-06 08:28:24.677953+00');
INSERT INTO "used_serials" ("serial_number_id", "storage_node_id") VALUES (1, E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n');
INSERT INTO "storagenode_bandwidth_rollups" ("storagenode_id", "interval_start", "interval_seconds", "action", "allocated", "settled") VALUES (E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n', '2019-03-06 08:00:00.000000+00', 3600, 1, 1024, 2024);
INSERT INTO "storagenode_storage_rollups" ("storagenode_id", "interval_start", "interval_seconds", "total") VALUES (E'\\006\\223\\250R\\221\\005\\365\\377v>0\\266\\365\\216\\255?\\347\\244\\371?2\\264\\262\\230\\007<\\001\\262\\263\\237\\247n', '2019-03-06 08:00:00.000000+00', 3600, 4024);
INSERT INTO "bucket_bandwidth_rollups" ("bucket_id", "interval_start", "interval_seconds", "action", "inline", "allocated", "settled") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014/testbucket'::bytea, '2019-03-06 08:00:00.000000+00', 3600, 1, 1024, 2024, 3024);
INSERT INTO "bucket_storage_rollups" ("bucket_id", "interval_start", "interval_seconds", "inline", "remote") VALUES (E'\\363\\342\\363\\371>+F\\256\\263\\300\\273|\\342N\\347\\014/testbucket'::bytea, '2019-03-06 08:00:00.000000+00', 3600, 4024, 5024);

View File

@ -48,10 +48,12 @@ func (users *users) Insert(ctx context.Context, user *console.User) (*console.Us
createdUser, err := users.db.Create_User(ctx, createdUser, err := users.db.Create_User(ctx,
dbx.User_Id(userID[:]), dbx.User_Id(userID[:]),
dbx.User_FirstName(user.FirstName), dbx.User_FullName(user.FullName),
dbx.User_LastName(user.LastName),
dbx.User_Email(user.Email), dbx.User_Email(user.Email),
dbx.User_PasswordHash(user.PasswordHash), dbx.User_PasswordHash(user.PasswordHash),
dbx.User_Create_Fields{
ShortName: dbx.User_ShortName(user.ShortName),
},
) )
if err != nil { if err != nil {
@ -82,8 +84,8 @@ func (users *users) Update(ctx context.Context, user *console.User) error {
// toUpdateUser creates dbx.User_Update_Fields with only non-empty fields as updatable // toUpdateUser creates dbx.User_Update_Fields with only non-empty fields as updatable
func toUpdateUser(user *console.User) dbx.User_Update_Fields { func toUpdateUser(user *console.User) dbx.User_Update_Fields {
update := dbx.User_Update_Fields{ update := dbx.User_Update_Fields{
FirstName: dbx.User_FirstName(user.FirstName), FullName: dbx.User_FullName(user.FullName),
LastName: dbx.User_LastName(user.LastName), ShortName: dbx.User_ShortName(user.ShortName),
Email: dbx.User_Email(user.Email), Email: dbx.User_Email(user.Email),
Status: dbx.User_Status(int(user.Status)), Status: dbx.User_Status(int(user.Status)),
} }
@ -109,13 +111,16 @@ func userFromDBX(user *dbx.User) (*console.User, error) {
result := console.User{ result := console.User{
ID: id, ID: id,
FirstName: user.FirstName, FullName: user.FullName,
LastName: user.LastName,
Email: user.Email, Email: user.Email,
PasswordHash: user.PasswordHash, PasswordHash: user.PasswordHash,
Status: console.UserStatus(user.Status), Status: console.UserStatus(user.Status),
CreatedAt: user.CreatedAt, CreatedAt: user.CreatedAt,
} }
if user.ShortName != nil {
result.ShortName = *user.ShortName
}
return &result, nil return &result, nil
} }

View File

@ -22,8 +22,8 @@ func TestUserFromDbx(t *testing.T) {
t.Run("can't create dbo from dbx model with invalid ID", func(t *testing.T) { t.Run("can't create dbo from dbx model with invalid ID", func(t *testing.T) {
dbxUser := dbx.User{ dbxUser := dbx.User{
Id: []byte("qweqwe"), Id: []byte("qweqwe"),
FirstName: "FirstName", FullName: "Very long full name",
LastName: "LastName", ShortName: nil,
Email: "some@email.com", Email: "some@email.com",
PasswordHash: []byte("ihqerfgnu238723huagsd"), PasswordHash: []byte("ihqerfgnu238723huagsd"),
CreatedAt: time.Now(), CreatedAt: time.Now(),

View File

@ -97,8 +97,8 @@ export async function fetchProjectMembersRequest(projectID: string, limit: strin
members(limit: ${limit}, offset: ${offset}, order: ${sortBy}, search: "${searchQuery}") { members(limit: ${limit}, offset: ${offset}, order: ${sortBy}, search: "${searchQuery}") {
user { user {
id, id,
firstName, fullName,
lastName, shortName,
email email
}, },
joinedAt joinedAt

View File

@ -11,8 +11,8 @@ export async function updateAccountRequest(user: User): Promise<RequestResponse<
errorMessage: '', errorMessage: '',
isSuccess: false, isSuccess: false,
data: { data: {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
} }
}; };
@ -25,13 +25,13 @@ export async function updateAccountRequest(user: User): Promise<RequestResponse<
updateAccount ( updateAccount (
input: { input: {
email: "${user.email}", email: "${user.email}",
firstName: "${user.firstName}", fullName: "${user.fullName}",
lastName: "${user.lastName}" shortName: "${user.shortName}"
} }
) { ) {
email, email,
firstName, fullName,
lastName shortName
} }
}` }`
), ),
@ -109,8 +109,8 @@ export async function createUserRequest(user: User, password: string, secret: st
input:{ input:{
email: "${user.email}", email: "${user.email}",
password: "${password}", password: "${password}",
firstName: "${user.firstName}", fullName: "${user.fullName}",
lastName: "${user.lastName}", shortName: "${user.shortName}",
}, },
secret: "${secret}", secret: "${secret}",
){email} ){email}
@ -178,8 +178,8 @@ export async function getUserRequest(): Promise<RequestResponse<User>> {
errorMessage: '', errorMessage: '',
isSuccess: false, isSuccess: false,
data: { data: {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
} }
}; };
@ -190,8 +190,8 @@ export async function getUserRequest(): Promise<RequestResponse<User>> {
query: gql(` query: gql(`
query { query {
user { user {
firstName, fullName,
lastName, shortName,
email, email,
} }
}` }`

View File

@ -17,21 +17,21 @@
</div> </div>
<HeaderedInput <HeaderedInput
class="full-input" class="full-input"
label="First name" label="Full name"
placeholder ="Enter First Name" placeholder="Enter Full Name"
width="100%" width="100%"
ref="firstNameInput" ref="fullNameInput"
:error="firstNameError" :error="fullNameError"
:initValue="user.firstName" :initValue="user.fullName"
@setData="setFirstName" /> @setData="setFullName" />
<HeaderedInput <HeaderedInput
class="full-input" class="full-input"
label="Last Name" label="Short Name"
placeholder="Enter Last Name" placeholder="Enter Short Name"
width="100%" width="100%"
ref="lastNameInput" ref="shortNameInput"
:initValue="user.lastName" :initValue="user.shortName"
@setData="setLastName"/> @setData="setShortName"/>
<HeaderedInput <HeaderedInput
class="full-input" class="full-input"
label="Email" label="Email"
@ -134,15 +134,15 @@ import { validateEmail, validatePassword } from '@/utils/validation';
{ {
data: function () { data: function () {
return { return {
originalFirstName: this.$store.getters.user.firstName, originalFullName: this.$store.getters.user.fullName,
originalLastName: this.$store.getters.user.lastName, originalShortName: this.$store.getters.user.shortName,
originalEmail: this.$store.getters.user.email, originalEmail: this.$store.getters.user.email,
firstName: this.$store.getters.user.firstName, fullName: this.$store.getters.user.fullName,
lastName: this.$store.getters.user.lastName, shortName: this.$store.getters.user.shortName,
email: this.$store.getters.user.email, email: this.$store.getters.user.email,
firstNameError: '', fullNameError: '',
emailError: '', emailError: '',
isAccountSettingsEditing: false, isAccountSettingsEditing: false,
@ -158,13 +158,13 @@ import { validateEmail, validatePassword } from '@/utils/validation';
}; };
}, },
methods: { methods: {
setFirstName: function (value: string) { setFullName: function (value: string) {
this.$data.firstName = value; this.$data.fullName = value;
this.$data.firstNameError = ''; this.$data.fullNameError = '';
this.$data.isAccountSettingsEditing = true; this.$data.isAccountSettingsEditing = true;
}, },
setLastName: function (value: string) { setShortName: function (value: string) {
this.$data.lastName = value; this.$data.shortName = value;
this.$data.isAccountSettingsEditing = true; this.$data.isAccountSettingsEditing = true;
}, },
setEmail: function (value: string) { setEmail: function (value: string) {
@ -173,17 +173,17 @@ import { validateEmail, validatePassword } from '@/utils/validation';
this.$data.isAccountSettingsEditing = true; this.$data.isAccountSettingsEditing = true;
}, },
cancelAccountSettings: function () { cancelAccountSettings: function () {
this.$data.firstName = this.$data.originalFirstName; this.$data.fullName = this.$data.originalFullName;
this.$data.firstNameError = ''; this.$data.fullNameError = '';
this.$data.lastName = this.$data.originalLastName; this.$data.shortName = this.$data.originalShortName;
this.$data.email = this.$data.originalEmail; this.$data.email = this.$data.originalEmail;
this.$data.emailError = ''; this.$data.emailError = '';
let firstNameInput: any = this.$refs['firstNameInput']; let fullNameInput: any = this.$refs['fullNameInput'];
firstNameInput.setValue(this.$data.originalFirstName); fullNameInput.setValue(this.$data.originalFullName);
let lastNameInput: any = this.$refs['lastNameInput']; let shortNameInput: any = this.$refs['shortNameInput'];
lastNameInput.setValue(this.$data.originalLastName); shortNameInput.setValue(this.$data.originalShortName);
let emailInput: any = this.$refs['emailInput']; let emailInput: any = this.$refs['emailInput'];
emailInput.setValue(this.$data.originalEmail); emailInput.setValue(this.$data.originalEmail);
@ -193,8 +193,8 @@ import { validateEmail, validatePassword } from '@/utils/validation';
onSaveAccountSettingsButtonClick: async function () { onSaveAccountSettingsButtonClick: async function () {
let hasError = false; let hasError = false;
if (!this.$data.firstName) { if (!this.$data.fullName) {
this.$data.firstNameError = 'First name expected'; this.$data.fullNameError = 'Full name expected';
hasError = true; hasError = true;
} }
@ -209,8 +209,8 @@ import { validateEmail, validatePassword } from '@/utils/validation';
let user = { let user = {
email: this.$data.email, email: this.$data.email,
firstName: this.$data.firstName, fullName: this.$data.fullName,
lastName: this.$data.lastName, shortName: this.$data.shortName,
}; };
let response = await this.$store.dispatch(USER_ACTIONS.UPDATE, user); let response = await this.$store.dispatch(USER_ACTIONS.UPDATE, user);
@ -222,8 +222,8 @@ import { validateEmail, validatePassword } from '@/utils/validation';
this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Account info successfully updated!'); this.$store.dispatch(NOTIFICATION_ACTIONS.SUCCESS, 'Account info successfully updated!');
this.$data.originalFirstName = this.$store.getters.user.firstName; this.$data.originalFullName = this.$store.getters.user.fullName;
this.$data.originalLastName = this.$store.getters.user.lastName; this.$data.originalShortName = this.$store.getters.user.shortName;
this.$data.originalEmail = this.$store.getters.user.email; this.$data.originalEmail = this.$store.getters.user.email;
this.$data.isAccountSettingsEditing = false; this.$data.isAccountSettingsEditing = false;
@ -331,8 +331,8 @@ import { validateEmail, validatePassword } from '@/utils/validation';
computed: { computed: {
user: function() { user: function() {
return { return {
firstName: this.$store.getters.user.firstName, fullName: this.$store.getters.user.fullName,
lastName: this.$store.getters.user.lastName, shortName: this.$store.getters.user.shortName,
email: this.$store.getters.user.email, email: this.$store.getters.user.email,
}; };
}, },
@ -341,7 +341,6 @@ import { validateEmail, validatePassword } from '@/utils/validation';
return this.$store.getters.userName.slice(0, 1).toUpperCase(); return this.$store.getters.userName.slice(0, 1).toUpperCase();
}, },
isPopupShown: function (): boolean { isPopupShown: function (): boolean {
return this.$store.state.appStateModule.appState.isDeleteAccountPopupShown; return this.$store.state.appStateModule.appState.isDeleteAccountPopupShown;
} }
}, },

View File

@ -32,7 +32,7 @@ import { Component, Vue } from 'vue-property-decorator';
return name; return name;
} }
return name.slice(0,12) + '...'; return name.slice(0, 12) + '...';
} }
} }
} }

View File

@ -22,12 +22,12 @@ import { getColor } from '@/utils/avatarColorManager';
}, },
computed: { computed: {
userInfo: function (): object { userInfo: function (): object {
let fullName: string = this.$props.projectMember.user.firstName + ' ' + this.$props.projectMember.user.lastName; let fullName = getFullName(this.$props.projectMember.user);
let email: string = this.$props.projectMember.user.email; let email: string = this.$props.projectMember.user.email;
if (fullName.length > 16) { if (fullName.length > 16) {
fullName = this.$props.projectMember.user.firstName.slice(0, 1).toUpperCase() + fullName = fullName.slice(0, 13) + '...';
'. ' + this.$props.projectMember.user.lastName.slice(0, 1).toUpperCase() + '.';
} }
if (email.length > 16) { if (email.length > 16) {
@ -37,7 +37,9 @@ import { getColor } from '@/utils/avatarColorManager';
return { fullName, email }; return { fullName, email };
}, },
avatarData: function (): object { avatarData: function (): object {
const letter = this.$props.projectMember.user.firstName.slice(0, 1).toLocaleUpperCase(); let fullName = getFullName(this.$props.projectMember.user);
const letter = fullName.slice(0, 1).toLocaleUpperCase();
const style = { const style = {
background: getColor(letter) background: getColor(letter)
@ -53,6 +55,10 @@ import { getColor } from '@/utils/avatarColorManager';
export default class TeamMemberItem extends Vue { export default class TeamMemberItem extends Vue {
} }
function getFullName(user: any): string {
return user.shortName === '' ? user.fullName : user.shortName;
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@ -12,8 +12,8 @@ import {
export const usersModule = { export const usersModule = {
state: { state: {
user: { user: {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '' email: ''
} }
}, },
@ -24,8 +24,8 @@ export const usersModule = {
}, },
[USER_MUTATIONS.REVERT_TO_DEFAULT_USER_INFO](state: any): void { [USER_MUTATIONS.REVERT_TO_DEFAULT_USER_INFO](state: any): void {
state.user.firstName = ''; state.user.fullName = '';
state.user.lastName = ''; state.user.shortName = '';
state.user.email = ''; state.user.email = '';
}, },
@ -35,8 +35,8 @@ export const usersModule = {
[USER_MUTATIONS.CLEAR](state: any): void { [USER_MUTATIONS.CLEAR](state: any): void {
state.user = { state.user = {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '' email: ''
}; };
}, },
@ -76,6 +76,6 @@ export const usersModule = {
user: (state: any) => { user: (state: any) => {
return state.user; return state.user;
}, },
userName: (state: any) => `${state.user.firstName} ${state.user.lastName}` userName: (state: any) => state.user.shortName == '' ? state.user.fullName : state.user.shortName
}, },
}; };

View File

@ -2,8 +2,8 @@
// See LICENSE for copying information. // See LICENSE for copying information.
declare type User = { declare type User = {
firstName: string, fullName: string,
lastName: string, shortName: string,
email: string, email: string,
}; };

View File

@ -22,19 +22,19 @@
</div> </div>
<HeaderlessInput <HeaderlessInput
class="full-input" class="full-input"
label="First name" label="Full name"
placeholder="Enter First Name" placeholder="Enter Full Name"
:error="firstNameError" :error="fullNameError"
@setData="setFirstName" @setData="setFullName"
width="100%" width="100%"
height="46px" height="46px"
isWhite> isWhite>
</HeaderlessInput> </HeaderlessInput>
<HeaderlessInput <HeaderlessInput
class="full-input" class="full-input"
label="Last Name" label="Short Name"
placeholder="Enter Short Name" placeholder="Enter Short Name"
@setData="setLastName" @setData="setShortName"
width="100%" width="100%"
height="46px" height="46px"
isWhite> isWhite>
@ -113,9 +113,9 @@ import { createUserRequest } from '@/api/users';
{ {
data: function () { data: function () {
return { return {
firstName: '', fullName: '',
firstNameError: '', fullNameError: '',
lastName: '', shortName: '',
email: '', email: '',
emailError: '', emailError: '',
password: '', password: '',
@ -133,12 +133,12 @@ import { createUserRequest } from '@/api/users';
this.$data.email = value; this.$data.email = value;
this.$data.emailError = ''; this.$data.emailError = '';
}, },
setFirstName: function (value: string): void { setFullName: function (value: string): void {
this.$data.firstName = value; this.$data.fullName = value;
this.$data.firstNameError = ''; this.$data.fullNameError = '';
}, },
setLastName: function (value: string): void { setShortName: function (value: string): void {
this.$data.lastName = value; this.$data.shortName = value;
}, },
setPassword: function (value: string): void { setPassword: function (value: string): void {
this.$data.password = value; this.$data.password = value;
@ -150,8 +150,8 @@ import { createUserRequest } from '@/api/users';
}, },
validateFields: function (): boolean { validateFields: function (): boolean {
let isNoErrors = true; let isNoErrors = true;
if (!this.$data.firstName.trim()) { if (!this.$data.fullName.trim()) {
this.$data.firstNameError = 'Invalid First Name'; this.$data.fullNameError = 'Invalid Name';
isNoErrors = false; isNoErrors = false;
} }
@ -180,8 +180,8 @@ import { createUserRequest } from '@/api/users';
createUser: async function(): Promise<any> { createUser: async function(): Promise<any> {
let user = { let user = {
email: this.$data.email.trim(), email: this.$data.email.trim(),
firstName: this.$data.firstName.trim(), fullName: this.$data.fullName.trim(),
lastName: this.$data.lastName.trim(), shortName: this.$data.shortName.trim(),
}; };
let response = await createUserRequest(user, this.$data.password, this.$data.secret); let response = await createUserRequest(user, this.$data.password, this.$data.secret);

View File

@ -17,8 +17,8 @@ describe('mutations', () => {
it('Set user info', () => { it('Set user info', () => {
const state = { const state = {
user: { user: {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
} }
}; };
@ -26,23 +26,23 @@ describe('mutations', () => {
const store = new Vuex.Store({state, mutations}); const store = new Vuex.Store({state, mutations});
const user = { const user = {
firstName: 'firstName', fullName: 'fullName',
lastName: 'lastName', shortName: 'shortName',
email: 'email', email: 'email',
}; };
store.commit(USER_MUTATIONS.SET_USER_INFO, user); store.commit(USER_MUTATIONS.SET_USER_INFO, user);
expect(state.user.email).toBe('email'); expect(state.user.email).toBe('email');
expect(state.user.firstName).toBe('firstName'); expect(state.user.fullName).toBe('fullName');
expect(state.user.lastName).toBe('lastName'); expect(state.user.shortName).toBe('shortName');
}); });
it('clear user info', () => { it('clear user info', () => {
const state = { const state = {
user: { user: {
firstName: 'firstName', fullName: 'fullName',
lastName: 'lastName', shortName: 'shortName',
email: 'email', email: 'email',
} }
}; };
@ -52,21 +52,21 @@ describe('mutations', () => {
store.commit(USER_MUTATIONS.REVERT_TO_DEFAULT_USER_INFO); store.commit(USER_MUTATIONS.REVERT_TO_DEFAULT_USER_INFO);
expect(state.user.email).toBe(''); expect(state.user.email).toBe('');
expect(state.user.firstName).toBe(''); expect(state.user.fullName).toBe('');
expect(state.user.lastName).toBe(''); expect(state.user.shortName).toBe('');
}); });
it('Update user info', () => { it('Update user info', () => {
const state = { const state = {
user: { user: {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
} }
}; };
const user = { const user = {
firstName: 'firstName', fullName: 'fullName',
lastName: 'lastName', shortName: 'shortName',
email: 'email', email: 'email',
}; };
@ -75,8 +75,8 @@ describe('mutations', () => {
store.commit(USER_MUTATIONS.UPDATE_USER_INFO, user); store.commit(USER_MUTATIONS.UPDATE_USER_INFO, user);
expect(state.user.email).toBe('email'); expect(state.user.email).toBe('email');
expect(state.user.firstName).toBe('firstName'); expect(state.user.fullName).toBe('fullName');
expect(state.user.lastName).toBe('lastName'); expect(state.user.shortName).toBe('shortName');
}); });
}); });
@ -88,16 +88,16 @@ describe('actions', () => {
jest.spyOn(api, 'updateAccountRequest').mockReturnValue( jest.spyOn(api, 'updateAccountRequest').mockReturnValue(
Promise.resolve(<RequestResponse<User>>{ Promise.resolve(<RequestResponse<User>>{
isSuccess: true, data: { isSuccess: true, data: {
firstName: 'firstName', fullName: 'fullName',
lastName: 'lastName', shortName: 'shortName',
email: 'email', email: 'email',
} }
}) })
); );
const commit = jest.fn(); const commit = jest.fn();
const user = { const user = {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
}; };
@ -105,8 +105,8 @@ describe('actions', () => {
expect(dispatchResponse.isSuccess).toBeTruthy(); expect(dispatchResponse.isSuccess).toBeTruthy();
expect(commit).toHaveBeenCalledWith(USER_MUTATIONS.UPDATE_USER_INFO, { expect(commit).toHaveBeenCalledWith(USER_MUTATIONS.UPDATE_USER_INFO, {
firstName: 'firstName', fullName: 'fullName',
lastName: 'lastName', shortName: 'shortName',
email: 'email', email: 'email',
}); });
}); });
@ -119,8 +119,8 @@ describe('actions', () => {
); );
const commit = jest.fn(); const commit = jest.fn();
const user = { const user = {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
}; };
@ -164,8 +164,8 @@ describe('actions', () => {
Promise.resolve(<RequestResponse<User>>{ Promise.resolve(<RequestResponse<User>>{
isSuccess: true, isSuccess: true,
data: { data: {
firstName: '', fullName: '',
lastName: '', shortName: '',
email: '', email: '',
} }
}) })
@ -195,24 +195,24 @@ describe('getters', () => {
it('user model', function () { it('user model', function () {
const state = { const state = {
user: { user: {
firstName: 'firstName', fullName: 'fullName',
lastName: 'lastName', shortName: 'shortName',
email: 'email', email: 'email',
} }
}; };
const retrievedUser = usersModule.getters.user(state); const retrievedUser = usersModule.getters.user(state);
expect(retrievedUser.firstName).toBe('firstName'); expect(retrievedUser.fullName).toBe('fullName');
expect(retrievedUser.lastName).toBe('lastName'); expect(retrievedUser.shortName).toBe('shortName');
expect(retrievedUser.email).toBe('email'); expect(retrievedUser.email).toBe('email');
}); });
it('user name', function () { it('user name', function () {
const state = { const state = {
user: { user: {
firstName: 'John', fullName: 'John',
lastName: 'Doe' shortName: 'Doe'
} }
}; };