Skip to content

Commit

Permalink
sms expirable verification codes included in the api and database ind…
Browse files Browse the repository at this point in the history
…exes improved
  • Loading branch information
lucasmenendez committed Sep 25, 2024
1 parent 8007e41 commit d6957ae
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 18 deletions.
35 changes: 26 additions & 9 deletions api/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,14 +208,23 @@ func (a *API) verifyUserAccountHandler(w http.ResponseWriter, r *http.Request) {
// verification code is not found, an error is returned. If any other error
// occurs, a generic error is returned.
func (a *API) userVerificationCodeInfoHandler(w http.ResponseWriter, r *http.Request) {
// get the user email from the request query
// get the user email or the phone number of the user from the request query
userEmail := r.URL.Query().Get("email")
if userEmail == "" {
ErrInvalidUserData.With("no email provided").Write(w)
userPhone := r.URL.Query().Get("phone")
// check the email or the phone number is not empty
if userEmail == "" && userPhone == "" {
ErrInvalidUserData.With("no email or phone number provided").Write(w)
return
}
// get the user information from the database by email
user, err := a.db.UserByEmail(userEmail)
var err error
var user *db.User
// get the user information from the database by email or phone
if userEmail != "" {
user, err = a.db.UserByEmail(userEmail)
} else {
user, err = a.db.UserByPhone(userPhone)
}
// check the error getting the user information
if err != nil {
if err == db.ErrNotFound {
ErrUserNotFound.Write(w)
Expand Down Expand Up @@ -259,12 +268,20 @@ func (a *API) resendUserVerificationCodeHandler(w http.ResponseWriter, r *http.R
ErrMalformedBody.Write(w)
return
}
if verification.Email == "" {
ErrInvalidUserData.With("no email provided").Write(w)
// check the email or the phone number is not empty
if verification.Email == "" && verification.Phone == "" {
ErrInvalidUserData.With("no email or phone number provided").Write(w)
return
}
// get the user information from the database by email
user, err := a.db.UserByEmail(verification.Email)
var err error
var user *db.User
// get the user information from the database by email or phone
if verification.Email != "" {
user, err = a.db.UserByEmail(verification.Email)
} else {
user, err = a.db.UserByPhone(verification.Phone)
}
// check the error getting the user information
if err != nil {
if err == db.ErrNotFound {
ErrUnauthorized.Write(w)
Expand Down
22 changes: 13 additions & 9 deletions db/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ func (ms *MongoStorage) createIndexes() error {
if _, err := ms.users.Indexes().CreateOne(ctx, userEmailIndex); err != nil {
return fmt.Errorf("failed to create index on addresses for users: %w", err)
}
// create an index for the 'phone' field on users
userPhoneIndex := mongo.IndexModel{
Keys: bson.D{{Key: "phone", Value: 1}}, // 1 for ascending order
Options: options.Index().SetUnique(true),
}
if _, err := ms.users.Indexes().CreateOne(ctx, userPhoneIndex); err != nil {
return fmt.Errorf("failed to create index on phone for users: %w", err)
}
// create an index for the 'name' field on organizations (must be unique)
organizationNameIndex := mongo.IndexModel{
Keys: bson.D{{Key: "name", Value: 1}}, // 1 for ascending order
Expand All @@ -121,21 +129,17 @@ func (ms *MongoStorage) createIndexes() error {
if _, err := ms.organizations.Indexes().CreateOne(ctx, organizationNameIndex); err != nil {
return fmt.Errorf("failed to create index on name for organizations: %w", err)
}
// create an index for the 'code' field on user verifications (must be unique)
// create an index for the ('code', 'type') tuple on user verifications (must be unique)
verificationCodeIndex := mongo.IndexModel{
Keys: bson.D{{Key: "code", Value: 1}}, // 1 for ascending order
Keys: bson.D{
{Key: "code", Value: 1}, // 1 for ascending order
{Key: "type", Value: 1}, // 1 for ascending order
},
Options: options.Index().SetUnique(true),
}
if _, err := ms.verifications.Indexes().CreateOne(ctx, verificationCodeIndex); err != nil {
return fmt.Errorf("failed to create index on code for verifications: %w", err)
}
// create an index for the 'type' field on user verifications
verificationTypeIndex := mongo.IndexModel{
Keys: bson.D{{Key: "type", Value: 1}}, // 1 for ascending order
}
if _, err := ms.verifications.Indexes().CreateOne(ctx, verificationTypeIndex); err != nil {
return fmt.Errorf("failed to create index on type for verifications: %w", err)
}
return nil
}

Expand Down
21 changes: 21 additions & 0 deletions db/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,27 @@ func (ms *MongoStorage) UserByEmail(email string) (*User, error) {
return user, nil
}

// UserByPhone method returns the user with the given phone number. If the user
// doesn't exist, it returns a specific error. If other errors occur, it returns
// the error.
func (ms *MongoStorage) UserByPhone(phone string) (*User, error) {
ms.keysLock.RLock()
defer ms.keysLock.RUnlock()

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

result := ms.users.FindOne(ctx, bson.M{"phone": phone})
user := &User{}
if err := result.Decode(user); err != nil {
if err == mongo.ErrNoDocuments {
return nil, ErrNotFound
}
return nil, err
}
return user, nil
}

// SetUser method creates or updates the user in the database. If the user
// already exists, it updates the fields that have changed. If the user doesn't
// exist, it creates it. If an error occurs, it returns the error.
Expand Down

0 comments on commit d6957ae

Please sign in to comment.