satellite/satellitedb: Add GetByEmailWithUnverified to users table
Allows us to handle duplicate emails better. Change-Id: I266057900725e50d1c47977da307714fd32d9081
This commit is contained in:
parent
9c1129b4c4
commit
984792fd1e
@ -18,7 +18,9 @@ import (
|
|||||||
type Users interface {
|
type Users interface {
|
||||||
// Get is a method for querying user from the database by id.
|
// Get is a method for querying user from the database by id.
|
||||||
Get(ctx context.Context, id uuid.UUID) (*User, error)
|
Get(ctx context.Context, id uuid.UUID) (*User, error)
|
||||||
// GetByEmail is a method for querying user by email from the database.
|
// GetByEmailWithUnverified is a method for querying users by email from the database.
|
||||||
|
GetByEmailWithUnverified(ctx context.Context, email string) (*User, []User, error)
|
||||||
|
// GetByEmail is a method for querying user by verified email from the database.
|
||||||
GetByEmail(ctx context.Context, email string) (*User, error)
|
GetByEmail(ctx context.Context, email string) (*User, error)
|
||||||
// Insert is a method for inserting user into the database.
|
// Insert is a method for inserting user into the database.
|
||||||
Insert(ctx context.Context, user *User) (*User, error)
|
Insert(ctx context.Context, user *User) (*User, error)
|
||||||
|
@ -5,6 +5,7 @@ package console_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -283,3 +284,47 @@ func testUsers(ctx context.Context, t *testing.T, repository console.Users, user
|
|||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetUserByEmail(t *testing.T) {
|
||||||
|
satellitedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db satellite.DB) {
|
||||||
|
usersRepo := db.Console().Users()
|
||||||
|
email := "test@mail.test"
|
||||||
|
|
||||||
|
inactiveUser := console.User{
|
||||||
|
ID: testrand.UUID(),
|
||||||
|
FullName: "Inactive User",
|
||||||
|
Email: email,
|
||||||
|
PasswordHash: []byte("123a123"),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := usersRepo.Insert(ctx, &inactiveUser)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = usersRepo.GetByEmail(ctx, email)
|
||||||
|
require.ErrorIs(t, sql.ErrNoRows, err)
|
||||||
|
|
||||||
|
verified, unverified, err := usersRepo.GetByEmailWithUnverified(ctx, email)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, verified)
|
||||||
|
require.Equal(t, inactiveUser.ID, unverified[0].ID)
|
||||||
|
|
||||||
|
activeUser := console.User{
|
||||||
|
ID: testrand.UUID(),
|
||||||
|
FullName: "Active User",
|
||||||
|
Email: email,
|
||||||
|
Status: console.Active,
|
||||||
|
PasswordHash: []byte("123a123"),
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = usersRepo.Insert(ctx, &activeUser)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Required to set the active status.
|
||||||
|
err = usersRepo.Update(ctx, &activeUser)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dbUser, err := usersRepo.GetByEmail(ctx, email)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, activeUser.ID, dbUser.ID)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -312,6 +312,10 @@ create user ( )
|
|||||||
update user ( where user.id = ? )
|
update user ( where user.id = ? )
|
||||||
delete user ( where user.id = ? )
|
delete user ( where user.id = ? )
|
||||||
|
|
||||||
|
read all (
|
||||||
|
select user
|
||||||
|
where user.normalized_email = ?
|
||||||
|
)
|
||||||
read one (
|
read one (
|
||||||
select user
|
select user
|
||||||
where user.normalized_email = ?
|
where user.normalized_email = ?
|
||||||
|
@ -11403,6 +11403,51 @@ func (obj *pgxImpl) Get_Reputation_By_Id(ctx context.Context,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (obj *pgxImpl) All_User_By_NormalizedEmail(ctx context.Context,
|
||||||
|
user_normalized_email User_NormalizedEmail_Field) (
|
||||||
|
rows []*User, err error) {
|
||||||
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
|
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.email, users.normalized_email, users.full_name, users.short_name, users.password_hash, users.status, users.partner_id, users.user_agent, users.created_at, users.project_limit, users.project_bandwidth_limit, users.project_storage_limit, users.paid_tier, users.position, users.company_name, users.company_size, users.working_on, users.is_professional, users.employee_count, users.have_sales_contact, users.mfa_enabled, users.mfa_secret_key, users.mfa_recovery_codes, users.signup_promo_code FROM users WHERE users.normalized_email = ?")
|
||||||
|
|
||||||
|
var __values []interface{}
|
||||||
|
__values = append(__values, user_normalized_email.value())
|
||||||
|
|
||||||
|
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
|
||||||
|
obj.logStmt(__stmt, __values...)
|
||||||
|
|
||||||
|
for {
|
||||||
|
rows, err = func() (rows []*User, err error) {
|
||||||
|
__rows, err := obj.driver.QueryContext(ctx, __stmt, __values...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer __rows.Close()
|
||||||
|
|
||||||
|
for __rows.Next() {
|
||||||
|
user := &User{}
|
||||||
|
err = __rows.Scan(&user.Id, &user.Email, &user.NormalizedEmail, &user.FullName, &user.ShortName, &user.PasswordHash, &user.Status, &user.PartnerId, &user.UserAgent, &user.CreatedAt, &user.ProjectLimit, &user.ProjectBandwidthLimit, &user.ProjectStorageLimit, &user.PaidTier, &user.Position, &user.CompanyName, &user.CompanySize, &user.WorkingOn, &user.IsProfessional, &user.EmployeeCount, &user.HaveSalesContact, &user.MfaEnabled, &user.MfaSecretKey, &user.MfaRecoveryCodes, &user.SignupPromoCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rows = append(rows, user)
|
||||||
|
}
|
||||||
|
if err := __rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
if obj.shouldRetry(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, obj.makeErr(err)
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (obj *pgxImpl) Get_User_By_NormalizedEmail_And_Status_Not_Number(ctx context.Context,
|
func (obj *pgxImpl) Get_User_By_NormalizedEmail_And_Status_Not_Number(ctx context.Context,
|
||||||
user_normalized_email User_NormalizedEmail_Field) (
|
user_normalized_email User_NormalizedEmail_Field) (
|
||||||
user *User, err error) {
|
user *User, err error) {
|
||||||
@ -17318,6 +17363,51 @@ func (obj *pgxcockroachImpl) Get_Reputation_By_Id(ctx context.Context,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (obj *pgxcockroachImpl) All_User_By_NormalizedEmail(ctx context.Context,
|
||||||
|
user_normalized_email User_NormalizedEmail_Field) (
|
||||||
|
rows []*User, err error) {
|
||||||
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
|
var __embed_stmt = __sqlbundle_Literal("SELECT users.id, users.email, users.normalized_email, users.full_name, users.short_name, users.password_hash, users.status, users.partner_id, users.user_agent, users.created_at, users.project_limit, users.project_bandwidth_limit, users.project_storage_limit, users.paid_tier, users.position, users.company_name, users.company_size, users.working_on, users.is_professional, users.employee_count, users.have_sales_contact, users.mfa_enabled, users.mfa_secret_key, users.mfa_recovery_codes, users.signup_promo_code FROM users WHERE users.normalized_email = ?")
|
||||||
|
|
||||||
|
var __values []interface{}
|
||||||
|
__values = append(__values, user_normalized_email.value())
|
||||||
|
|
||||||
|
var __stmt = __sqlbundle_Render(obj.dialect, __embed_stmt)
|
||||||
|
obj.logStmt(__stmt, __values...)
|
||||||
|
|
||||||
|
for {
|
||||||
|
rows, err = func() (rows []*User, err error) {
|
||||||
|
__rows, err := obj.driver.QueryContext(ctx, __stmt, __values...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer __rows.Close()
|
||||||
|
|
||||||
|
for __rows.Next() {
|
||||||
|
user := &User{}
|
||||||
|
err = __rows.Scan(&user.Id, &user.Email, &user.NormalizedEmail, &user.FullName, &user.ShortName, &user.PasswordHash, &user.Status, &user.PartnerId, &user.UserAgent, &user.CreatedAt, &user.ProjectLimit, &user.ProjectBandwidthLimit, &user.ProjectStorageLimit, &user.PaidTier, &user.Position, &user.CompanyName, &user.CompanySize, &user.WorkingOn, &user.IsProfessional, &user.EmployeeCount, &user.HaveSalesContact, &user.MfaEnabled, &user.MfaSecretKey, &user.MfaRecoveryCodes, &user.SignupPromoCode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rows = append(rows, user)
|
||||||
|
}
|
||||||
|
if err := __rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
if obj.shouldRetry(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, obj.makeErr(err)
|
||||||
|
}
|
||||||
|
return rows, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (obj *pgxcockroachImpl) Get_User_By_NormalizedEmail_And_Status_Not_Number(ctx context.Context,
|
func (obj *pgxcockroachImpl) Get_User_By_NormalizedEmail_And_Status_Not_Number(ctx context.Context,
|
||||||
user_normalized_email User_NormalizedEmail_Field) (
|
user_normalized_email User_NormalizedEmail_Field) (
|
||||||
user *User, err error) {
|
user *User, err error) {
|
||||||
@ -22267,6 +22357,16 @@ func (rx *Rx) All_StoragenodeStorageTally_By_IntervalEndTime_GreaterOrEqual(ctx
|
|||||||
return tx.All_StoragenodeStorageTally_By_IntervalEndTime_GreaterOrEqual(ctx, storagenode_storage_tally_interval_end_time_greater_or_equal)
|
return tx.All_StoragenodeStorageTally_By_IntervalEndTime_GreaterOrEqual(ctx, storagenode_storage_tally_interval_end_time_greater_or_equal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rx *Rx) All_User_By_NormalizedEmail(ctx context.Context,
|
||||||
|
user_normalized_email User_NormalizedEmail_Field) (
|
||||||
|
rows []*User, err error) {
|
||||||
|
var tx *Tx
|
||||||
|
if tx, err = rx.getTx(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return tx.All_User_By_NormalizedEmail(ctx, user_normalized_email)
|
||||||
|
}
|
||||||
|
|
||||||
func (rx *Rx) Count_BucketMetainfo_Name_By_ProjectId(ctx context.Context,
|
func (rx *Rx) Count_BucketMetainfo_Name_By_ProjectId(ctx context.Context,
|
||||||
bucket_metainfo_project_id BucketMetainfo_ProjectId_Field) (
|
bucket_metainfo_project_id BucketMetainfo_ProjectId_Field) (
|
||||||
count int64, err error) {
|
count int64, err error) {
|
||||||
@ -23618,6 +23718,10 @@ type Methods interface {
|
|||||||
storagenode_storage_tally_interval_end_time_greater_or_equal StoragenodeStorageTally_IntervalEndTime_Field) (
|
storagenode_storage_tally_interval_end_time_greater_or_equal StoragenodeStorageTally_IntervalEndTime_Field) (
|
||||||
rows []*StoragenodeStorageTally, err error)
|
rows []*StoragenodeStorageTally, err error)
|
||||||
|
|
||||||
|
All_User_By_NormalizedEmail(ctx context.Context,
|
||||||
|
user_normalized_email User_NormalizedEmail_Field) (
|
||||||
|
rows []*User, err error)
|
||||||
|
|
||||||
Count_BucketMetainfo_Name_By_ProjectId(ctx context.Context,
|
Count_BucketMetainfo_Name_By_ProjectId(ctx context.Context,
|
||||||
bucket_metainfo_project_id BucketMetainfo_ProjectId_Field) (
|
bucket_metainfo_project_id BucketMetainfo_ProjectId_Field) (
|
||||||
count int64, err error)
|
count int64, err error)
|
||||||
|
@ -28,6 +28,7 @@ type users struct {
|
|||||||
func (users *users) Get(ctx context.Context, id uuid.UUID) (_ *console.User, err error) {
|
func (users *users) Get(ctx context.Context, id uuid.UUID) (_ *console.User, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
user, err := users.db.Get_User_By_Id(ctx, dbx.User_Id(id[:]))
|
user, err := users.db.Get_User_By_Id(ctx, dbx.User_Id(id[:]))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -35,7 +36,34 @@ func (users *users) Get(ctx context.Context, id uuid.UUID) (_ *console.User, err
|
|||||||
return userFromDBX(ctx, user)
|
return userFromDBX(ctx, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByEmail is a method for querying user by email from the database.
|
// GetByEmailWithUnverified is a method for querying users by email from the database.
|
||||||
|
func (users *users) GetByEmailWithUnverified(ctx context.Context, email string) (verified *console.User, unverified []console.User, err error) {
|
||||||
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
usersDbx, err := users.db.All_User_By_NormalizedEmail(ctx, dbx.User_NormalizedEmail(normalizeEmail(email)))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var errors errs.Group
|
||||||
|
for _, userDbx := range usersDbx {
|
||||||
|
u, err := userFromDBX(ctx, userDbx)
|
||||||
|
if err != nil {
|
||||||
|
errors.Add(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if u.Status == console.Active {
|
||||||
|
verified = u
|
||||||
|
} else {
|
||||||
|
unverified = append(unverified, *u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return verified, unverified, errors.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByEmail is a method for querying user by verified email from the database.
|
||||||
func (users *users) GetByEmail(ctx context.Context, email string) (_ *console.User, err error) {
|
func (users *users) GetByEmail(ctx context.Context, email string) (_ *console.User, err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
user, err := users.db.Get_User_By_NormalizedEmail_And_Status_Not_Number(ctx, dbx.User_NormalizedEmail(normalizeEmail(email)))
|
user, err := users.db.Get_User_By_NormalizedEmail_And_Status_Not_Number(ctx, dbx.User_NormalizedEmail(normalizeEmail(email)))
|
||||||
|
Loading…
Reference in New Issue
Block a user