Skip to content

Commit

Permalink
chore: add signup usecase implementation (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
maxwellgithinji authored Sep 27, 2021
1 parent e882a32 commit 7c5110e
Show file tree
Hide file tree
Showing 13 changed files with 1,015 additions and 5 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ jobs:
go get github.com/stretchr/testify/assert@v1.7.0
go get github.com/ory/go-acc
go install github.com/savannahghi/bewellcli@$CLI_VERSION
go get golang.org/x/oauth2/internal
- name: Run lint and test
run: |
Expand Down
3 changes: 3 additions & 0 deletions deps.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
staging:
- depName: engagement
depRootDomain: https://engagement-staging.healthcloud.co.ke
testing:
- depName: engagement
depRootDomain: https://engagement-testing.savannahghi.org
Expand Down
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@ module github.com/savannahghi/onboarding-service
go 1.16

require (
cloud.google.com/go/firestore v1.5.0
firebase.google.com/go v3.13.0+incompatible
github.com/99designs/gqlgen v0.13.0
github.com/casbin/casbin/v2 v2.31.3
github.com/google/uuid v1.2.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/savannahghi/converterandformatter v0.0.9
github.com/savannahghi/enumutils v0.0.3
github.com/savannahghi/feedlib v0.0.4
github.com/savannahghi/firebasetools v0.0.15
github.com/savannahghi/onboarding v0.0.18
github.com/savannahghi/interserviceclient v0.0.13
github.com/savannahghi/onboarding v0.0.21
github.com/savannahghi/profileutils v0.0.17
github.com/savannahghi/scalarutils v0.0.4
github.com/savannahghi/serverutils v0.0.6
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.0
github.com/vektah/gqlparser/v2 v2.1.0
go.opencensus.io v0.23.0
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.21.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ github.com/savannahghi/interserviceclient v0.0.13 h1:hKUrWkUQW7mNZLp/wxJNnzORDpN
github.com/savannahghi/interserviceclient v0.0.13/go.mod h1:aGGEc+40bBVHVDs1k0CzK5uPb5080vv4fb25T/cuXQk=
github.com/savannahghi/onboarding v0.0.18 h1:eepnWjXLnQdc5hAL6pEq//c1nQrSUHRvmtwB68EBjKs=
github.com/savannahghi/onboarding v0.0.18/go.mod h1:kn+yrdfhjgeCmzs9AfP9+cVJWi3kfmgj/kn7pNor0xY=
github.com/savannahghi/onboarding v0.0.21 h1:FHM18w57WlXud9HibzbcRvfQc7y7sBqQ7tO3uIiKeLM=
github.com/savannahghi/onboarding v0.0.21/go.mod h1:kn+yrdfhjgeCmzs9AfP9+cVJWi3kfmgj/kn7pNor0xY=
github.com/savannahghi/profileutils v0.0.6/go.mod h1:Ct0sjzOW9zjDN58ynT5GTV6M2hHMY3nsFDV08I6gpO4=
github.com/savannahghi/profileutils v0.0.17 h1:Zgk3n+ZtgQjI8vLTde4/c2U/t/Zh+q9jXZqVRL5ptRg=
github.com/savannahghi/profileutils v0.0.17/go.mod h1:Sq/2fK2iVntGqwC0EFe5SED0+AkdOrxp7gra9KmWPQQ=
Expand Down
45 changes: 45 additions & 0 deletions pkg/onboarding/infrastructure/infrastructure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package infrastructure

import (
"github.com/savannahghi/firebasetools"
baseExt "github.com/savannahghi/onboarding/pkg/onboarding/application/extension"
libUtils "github.com/savannahghi/onboarding/pkg/onboarding/application/utils"
libInfra "github.com/savannahghi/onboarding/pkg/onboarding/infrastructure"
engagementSvc "github.com/savannahghi/onboarding/pkg/onboarding/infrastructure/services/engagement"
libOnboardingUsecase "github.com/savannahghi/onboarding/pkg/onboarding/usecases"
)

const (
engagementService = "engagement"
)

// Interactor is an implementation of the infrastructure interface
// It combines each individual service implementation
type Interactor struct {
libOnboardingUsecase.LoginUseCases
libOnboardingUsecase.SignUpUseCases
engagementSvc.ServiceEngagementImpl
libOnboardingUsecase.ProfileUseCase
}

// NewInteractor initializes a new infrastructure interactor
func NewInteractor() Interactor {

i := libInfra.NewInfrastructureInteractor()
var fc firebasetools.IFirebaseClient
baseExtension := baseExt.NewBaseExtensionImpl(fc)
pinExtension := baseExt.NewPINExtensionImpl()
profile := libOnboardingUsecase.NewProfileUseCase(i, baseExtension)
userPinUseCase := libOnboardingUsecase.NewUserPinUseCase(i, profile, baseExtension, pinExtension)
login := libOnboardingUsecase.NewLoginUseCases(i, profile, baseExtension, pinExtension)
signup := libOnboardingUsecase.NewSignUpUseCases(i, profile, userPinUseCase, baseExtension)
engagementClient := libUtils.NewInterServiceClient(engagementService, baseExtension)
engagement := engagementSvc.NewServiceEngagementImpl(engagementClient, baseExtension)

return Interactor{
login,
signup,
*engagement,
profile,
}
}
4 changes: 4 additions & 0 deletions pkg/onboarding/presentation/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/savannahghi/onboarding-service/pkg/onboarding/presentation/graph"
"github.com/savannahghi/onboarding-service/pkg/onboarding/presentation/graph/generated"
"github.com/savannahghi/onboarding-service/pkg/onboarding/presentation/interactor"
"github.com/savannahghi/onboarding-service/pkg/onboarding/usecases"
"github.com/savannahghi/onboarding/pkg/onboarding/application/extension"
osinfra "github.com/savannahghi/onboarding/pkg/onboarding/infrastructure"
openSourcePresentation "github.com/savannahghi/onboarding/pkg/onboarding/presentation"
Expand Down Expand Up @@ -66,10 +67,13 @@ func Router(ctx context.Context) (*mux.Router, error) {

openSourceUsecases := osusecases.NewUsecasesInteractor(infrastructure, baseExt, pinExt)

var signupUsecase usecases.UseCaseSignUp

// Initialize the interactor
i, err := interactor.NewOnboardingInteractor(
infrastructure,
openSourceUsecases,
signupUsecase,
)
if err != nil {
return nil, fmt.Errorf("can't instantiate service : %w", err)
Expand Down
10 changes: 7 additions & 3 deletions pkg/onboarding/presentation/interactor/interactor.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,27 @@
package interactor

import (
"github.com/savannahghi/onboarding-service/pkg/onboarding/usecases"
"github.com/savannahghi/onboarding/pkg/onboarding/infrastructure"
sharelib "github.com/savannahghi/onboarding/pkg/onboarding/usecases"
libOnboardingUsecase "github.com/savannahghi/onboarding/pkg/onboarding/usecases"
)

// Interactor represents an assemble of all use cases into a single object that can be instantiated anywhere
type Interactor struct {
OpenSourceInfra infrastructure.Infrastructure
OpenSourceUsecases sharelib.Interactor
OpenSourceUsecases libOnboardingUsecase.Interactor
SignUpUseCase usecases.UseCaseSignUp
}

// NewOnboardingInteractor returns a new onboarding interactor
func NewOnboardingInteractor(
openSourceInfra infrastructure.Infrastructure,
openSourceUsecases sharelib.Interactor,
openSourceUsecases libOnboardingUsecase.Interactor,
signupUsecase usecases.UseCaseSignUp,
) (*Interactor, error) {
return &Interactor{
OpenSourceInfra: openSourceInfra,
OpenSourceUsecases: openSourceUsecases,
SignUpUseCase: signupUsecase,
}, nil
}
203 changes: 203 additions & 0 deletions pkg/onboarding/usecases/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package usecases_test

import (
"context"
"fmt"
"log"
"os"
"strings"
"testing"
"time"

"cloud.google.com/go/firestore"
"firebase.google.com/go/auth"
"github.com/google/uuid"
"github.com/savannahghi/feedlib"
"github.com/savannahghi/firebasetools"
"github.com/savannahghi/interserviceclient"
"github.com/savannahghi/onboarding-service/pkg/onboarding/infrastructure"
"github.com/savannahghi/onboarding/pkg/onboarding/application/dto"
"github.com/savannahghi/onboarding/pkg/onboarding/application/exceptions"
"github.com/savannahghi/onboarding/pkg/onboarding/domain"
"github.com/savannahghi/onboarding/pkg/onboarding/infrastructure/database/fb"
"github.com/savannahghi/profileutils"
"github.com/savannahghi/serverutils"
)

// NewInterServiceClient initializes an external service in the correct environment given its name
func InitializeTestService(
ctx context.Context,
) (infrastructure.Interactor, error) {
infra := infrastructure.NewInteractor()
return infra, nil

}

func InitializeTestFirebaseClient(ctx context.Context) (*firestore.Client, *auth.Client) {
fc := firebasetools.FirebaseClient{}
fa, err := fc.InitFirebase()
if err != nil {
log.Panicf("unable to initialize Firebase: %s", err)
}

fsc, err := fa.Firestore(ctx)
if err != nil {
log.Panicf("unable to initialize Firestore: %s", err)
}

fbc, err := fa.Auth(ctx)
if err != nil {
log.Panicf("can't initialize Firebase auth when setting up tests: %s", err)
}
return fsc, fbc
}

func TestMain(m *testing.M) {
log.Printf("Setting tests up ...")
envOriginalValue := os.Getenv("ENVIRONMENT")
os.Setenv("ENVIRONMENT", "staging")
emailOriginalValue := os.Getenv("SAVANNAH_ADMIN_EMAIL")
os.Setenv("SAVANNAH_ADMIN_EMAIL", "test@bewell.co.ke")
debugEnvValue := os.Getenv("DEBUG")
os.Setenv("DEBUG", "true")
os.Setenv("REPOSITORY", "firebase")
collectionEnvValue := os.Getenv("ROOT_COLLECTION_SUFFIX")
// !NOTE!
// Under no circumstances should you remove this env var when testing
// You risk purging important collections, like our prod collections
os.Setenv("ROOT_COLLECTION_SUFFIX", fmt.Sprintf("onboarding_ci_%v", time.Now().Unix()))

ctx := context.Background()

fsc, fbc := InitializeTestFirebaseClient(ctx)
if fsc == nil {
log.Panicf("failed to initialize test FireStore client")
}
if fbc == nil {
log.Panicf("failed to initialize test FireBase client")
}

purgeRecords := func() {
if serverutils.MustGetEnvVar(domain.Repo) == domain.FirebaseRepository {
r := fb.Repository{}
collections := []string{
r.GetPINsCollectionName(),
r.GetUserProfileCollectionName(),
r.GetSurveyCollectionName(),
r.GetCommunicationsSettingsCollectionName(),
r.GetExperimentParticipantCollectionName(),
r.GetProfileNudgesCollectionName(),
}
for _, collection := range collections {
ref := fsc.Collection(collection)
firebasetools.DeleteCollection(ctx, fsc, ref, 10)
}
}

}

// try clean up first
purgeRecords()

// do clean up
log.Printf("Running tests ...")
code := m.Run()

log.Printf("Tearing tests down ...")
purgeRecords()

// restore environment varibles to original values
os.Setenv(envOriginalValue, "ENVIRONMENT")
os.Setenv(emailOriginalValue, "SAVANNAH_ADMIN_EMAIL")
os.Setenv("DEBUG", debugEnvValue)
os.Setenv("ROOT_COLLECTION_SUFFIX", collectionEnvValue)

os.Exit(code)
}

// CreateTestUserByPhone creates a user that is to be used in
// running of our test cases.
// If the test user already exists then they are logged in
// to get their auth credentials
func CreateOrLoginTestUserByPhone(t *testing.T) (*auth.Token, error) {
ctx := context.Background()
i, err := InitializeTestService(ctx)
fmt.Printf("43: THE ERROR IS: %v\n", err)
if err != nil {
return nil, fmt.Errorf("unable to initialize test service")
}
phone := "+254720000000"
flavour := feedlib.FlavourConsumer
pin := interserviceclient.TestUserPin
testAppID := uuid.New().String()
otp, err := i.VerifyPhoneNumber(ctx, phone, &testAppID)
fmt.Printf("52: THE OTP IS: %v\n", otp)
fmt.Printf("53: THE ERROR IS: %v\n", err)
if err != nil {
if strings.Contains(err.Error(), exceptions.CheckPhoneNumberExistError().Error()) {
logInCreds, err := i.LoginByPhone(
ctx,
phone,
interserviceclient.TestUserPin,
flavour,
)
fmt.Printf("62: THE ERROR IS: %v\n", err)
if err != nil {
return nil, fmt.Errorf("failed to log in test user: %v", err)
}

return &auth.Token{
UID: logInCreds.Auth.UID,
}, nil
}

return nil, fmt.Errorf("failed to check if test phone exists: %v", err)
}

u, err := i.CreateUserByPhone(
ctx,
&dto.SignUpInput{
PhoneNumber: &phone,
PIN: &pin,
Flavour: flavour,
OTP: &otp.OTP,
},
)
fmt.Printf("84: THE ERROR IS: %v\n", err)
if err != nil {
return nil, fmt.Errorf("failed to create a test user: %v", err)
}
if u == nil {
return nil, fmt.Errorf("nil test user response")
}

return &auth.Token{
UID: u.Auth.UID,
}, nil
}

// TestAuthenticatedContext returns a logged in context, useful for test purposes
func GetTestAuthenticatedContext(t *testing.T) (context.Context, *auth.Token, error) {
ctx := context.Background()
auth, err := CreateOrLoginTestUserByPhone(t)
fmt.Printf("99: THE ERROR IS: %v\n", err)
if err != nil {
return nil, nil, err
}
authenticatedContext := context.WithValue(
ctx,
firebasetools.AuthTokenContextKey,
auth,
)
return authenticatedContext, auth, nil
}

func generateTestOTP(t *testing.T, phone string) (*profileutils.OtpResponse, error) {
ctx := context.Background()
i, err := InitializeTestService(ctx)
if err != nil {
return nil, fmt.Errorf("unable to initialize test service: %v", err)
}
testAppID := uuid.New().String()
return i.GenerateAndSendOTP(ctx, phone, &testAppID)
}
26 changes: 26 additions & 0 deletions pkg/onboarding/usecases/profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package usecases

import (
"github.com/savannahghi/onboarding-service/pkg/onboarding/infrastructure"
libProfileUsecase "github.com/savannahghi/onboarding/pkg/onboarding/usecases"
)

// UsecaseProfile represent the open sourced profile usecase
type UsecaseProfile interface {
libProfileUsecase.ProfileUseCase
}

// UsecaseProfileImpl is the open sourced usecase implememtation
type UsecaseProfileImpl struct {
infrastructure infrastructure.Interactor
}

// NewProfileUseCase instantiates profile usecases
func NewProfileUseCase(
infrastructure infrastructure.Interactor,
) *UsecaseProfileImpl {
return &UsecaseProfileImpl{
infrastructure: infrastructure,
}

}
Loading

0 comments on commit 7c5110e

Please sign in to comment.