Skip to content

Commit

Permalink
chore: make api usecases scaffold
Browse files Browse the repository at this point in the history
Signed-off-by: Otieno Calvine <nyarangaotieno@gmail.com>
  • Loading branch information
NYARAS committed Oct 14, 2021
1 parent f21f502 commit 8922328
Show file tree
Hide file tree
Showing 6 changed files with 482 additions and 27 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ require (
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.21.0
go.opentelemetry.io/otel v1.0.0-RC1
go.opentelemetry.io/otel/trace v1.0.0-RC1
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
gorm.io/datatypes v1.0.2
gorm.io/driver/postgres v1.1.2
gorm.io/gorm v1.21.16
Expand Down
25 changes: 10 additions & 15 deletions pkg/onboarding/application/dto/output.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package dto

import (
"github.com/savannahghi/firebasetools"
"github.com/savannahghi/onboarding-service/pkg/onboarding/domain"
)
// // FacilityEdge is used to serialize GraphQL Relay edges for healthcare facilities
// type FacilityEdge struct {
// Cursor *string `json:"cursor"`
// Node *domain.Facility `json:"node"`
// }

// FacilityEdge is used to serialize GraphQL Relay edges for healthcare facilities
type FacilityEdge struct {
Cursor *string `json:"cursor"`
Node *domain.Facility `json:"node"`
}

// FacilityConnection is used to serialize GraphQL Relay connections for healthcare facilities
type FacilityConnection struct {
Edges []*FacilityEdge `json:"edges"`
PageInfo *firebasetools.PageInfo `json:"pageInfo"`
}
// // FacilityConnection is used to serialize GraphQL Relay connections for healthcare facilities
// type FacilityConnection struct {
// Edges []*FacilityEdge `json:"edges"`
// PageInfo *firebasetools.PageInfo `json:"pageInfo"`
// }
196 changes: 195 additions & 1 deletion pkg/onboarding/domain/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
//
// e.g CCC clinics, Pharmacies.
type Facility struct {
// ID is the Global customer ID(GCID)
// ID is the Global facility ID(GCID)
ID uuid.UUID
// unique within this structure
Name string
Expand All @@ -38,6 +38,200 @@ type Facility struct {
// Date string // TODO: Clear spec on validation e.g dates must be ISO 8601
// }

// User holds details that both the client and staff have in common
//
// Client and Staff cannot exist without being a user
type User struct {
ID uuid.UUID // globally unique ID

Username string // @handle, also globally unique; nickname

DisplayName string // user's preferred display name

// TODO Consider making the names optional in DB; validation in frontends
FirstName string // given name
MiddleName *string
LastName string

UserType string // TODO enum; e.g client, health care worker

Gender string // TODO enum; genders; keep it simple

Active bool

Contacts []*Contact // TODO: validate, ensure

// for the preferred language list, order matters
Languages []string // TODO: turn this into a slice of enums, start small (en, sw)

PushTokens []string

// when a user logs in successfully, set this
LastSuccessfulLogin *time.Time

// whenever there is a failed login (e.g bad PIN), set this
// reset to null / blank when they succeed at logging in
LastFailedLogin *time.Time

// each time there is a failed login, **increment** this
// set to zero after successful login
FailedLoginCount int

// calculated each time there is a failed login
NextAllowedLogin *time.Time

TermsAccepted bool
AcceptedTermsID string // foreign key to version of terms they accepted
}

// AuthCredentials is the authentication credentials for a given user
type AuthCredentials struct {
User *User

RefreshToken string
IDToken string
ExpiresIn time.Time
}

// UserPIN is used to store users' PINs and their entire change history.
type UserPIN struct {
UserID string // TODO: At the DB, this should be indexed

HashedPIN string
ValidFrom time.Time
ValidTo time.Time

// TODO: Compute this each time an operation involving the PIN is carried out
// in order to make routine things e.g login via PIN fast
IsValid bool // TODO: Consider a composite or partial DB index with UserID, IsValid, flavour
Flavour string
}

// Identifier are specific/unique identifiers for a user
type Identifier struct {
ID *string // globally unique identifier
ClientID string // TODO: FK to client
IdentifierType string // TODO: Enum; start with basics e.g CCC number, ID number
IdentifierUse string // TODO: Enum; e.g official, temporary, old (see FHIR Person for enum)

// TODO: Validate identifier value against type e.g format of CCC number
// TODO: Unique together: identifier value & type i.e the same identifier can't be used for more than one client
IdentifierValue string // the actual identifier e.g CCC number
Description string
ValidFrom *time.Time
ValidTo *time.Time
Active bool
IsPrimaryIdentifier bool
}

// ClientProfile holds the details of end users who are not using the system in
// a professional capacity e.g consumers, patients etc.
//It is a linkage model e.g to tie together all of a person's identifiers
// and their health record ID
type ClientProfile struct {
ID string // globally unique identifier; synthetic i.e has no encoded meaning

// every client is a user first
// biodata is linked to the user record
// the client record is for bridging to other identifiers e.g patient record IDs
UserID string // TODO: Foreign key to User

TreatmentEnrollmentDate *time.Time // use for date of treatment enrollment

ClientType string // TODO: enum; e.g PMTCT, OVC

Active bool

HealthRecordID *string // optional link to a health record e.g FHIR Patient ID

// TODO: a client can have many identifiers; an identifier belongs to a client
// (implement reverse relation lookup)
Identifiers []*Identifier

Addresses []*Address

RelatedPersons []*RelatedPerson // e.g next of kin

// client's currently assigned facility
FacilityID string // TODO: FK

TreatmentBuddyUserID string // TODO: optional, FK to User

CHVUserID string // TODO: optional, FK to User

ClientCounselled bool
}

// Address are value objects for user address e.g postal code
type Address struct {
ID string

Type string // TODO: enum; postal, physical or both
Text string // actual address, can be multi-line
Country string // TODO: enum
PostalCode string
County string // TODO: counties belong to a country
Active bool
}

// RelatedPerson holds the details for person we consider relates to a Client
//
// It servers as Next of Kin details
type RelatedPerson struct {
ID string

Active bool
RelatedTo string // TODO: FK to client
RelationshipType string // TODO: enum
FirstName string
LastName string
OtherName string // TODO: optional
Gender string // TODO: enum

DateOfBirth *time.Time // TODO: optional
Addresses []*Address // TODO: optional
Contacts []*Contact // TODO: optional
}

// ClientProfileRegistrationPayload holds the registration input we need to register a client
//
// into the system. Every Client us a user first
type ClientProfileRegistrationPayload struct {
// every client is a user first
// biodata is linked to the user record
// the client record is for bridging to other identifiers e.g patient record IDs
UserID string // TODO: Foreign key to User

ClientType string // TODO: enum; e.g PMTCT, OVC

PrimaryIdentifier *Identifier // TODO: optional, default set if not givemn

Addresses []*Address

FacilityID string

TreatmentEnrollmentDate *time.Time

ClientCounselled bool

// TODO: when returning to UI, calculate length of treatment (return as days for ease of use in frontend)
}

// Contact hold contact information/details for users
type Contact struct {
ID string

Type string // TODO enum

Contact string // TODO Validate: phones are E164, emails are valid

Active bool

// a user may opt not to be contacted via this contact
// e.g if it's a shared phone owned by a teenager
OptedIn bool
}

// Metric reprents the metrics data structure input
type Metric struct {
// ensures we don't re-save the same metric; opaque; globally unique
Expand Down
101 changes: 101 additions & 0 deletions pkg/onboarding/usecases/client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package client

import "github.com/savannahghi/onboarding-service/pkg/onboarding/domain"

// IRegisterClient ...
type IRegisterClient interface {
// TODO: the input client profile must not have an ID set
// validate identifiers when creating
// if the enrollemnt date is not supplied, set it automatically
// default to the client profile being active right after creation
// create a patient on FHIR (HealthRecordID
// if identifers not supplied (e.g patient being created on app), set
// an internal identifier as the default. It should be updated later
// with the CCC number or other final identifier
// TODO: ensure the user exists...supplied user ID
// TODO: only register clients who've been counselled
// TODO: consider: after successful registration, send invite link automatically
RegisterClient(user domain.User, profile domain.ClientProfileRegistrationPayload) (*domain.ClientProfile, error)
}

// IAddClientIdentifier ...
type IAddClientIdentifier interface {
// TODO idType is an enum
// TODO use idType and settings to decide if it's a primary identifier or not
AddIdentifier(clientID string, idType string, idValue string, isPrimary bool) (*domain.Identifier, error)
}

// IInactivateClient ...
type IInactivateClient interface {
// TODO Consider making reasons an enum
InactivateClient(clientID string, reason string, notes string) (bool, error)
}

// IReactivateClient ...
type IReactivateClient interface {
ReactivateClient(clientID string, reason string, notes string) (bool, error)
}

// ITransferClient ...
type ITransferClient interface {
// TODO: maintain log of past transfers, who did it etc
TransferClient(
clientID string,
OriginFacilityID string,
DestinationFacilityID string,
Reason string, // TODO: consider making this an enum
Notes string, // optional notes...e.g if the reason given is "Other"
) (bool, error)
}

// IGetClientIdentifiers ...
type IGetClientIdentifiers interface {
GetIdentifiers(clientID string, active bool) ([]*domain.Identifier, error)
}

// IInactivateClientIdentifier ...
type IInactivateClientIdentifier interface {
InactivateIdentifier(clientID string, identifierID string) (bool, error)
}

// IAssignTreatmentSupporter ...
type IAssignTreatmentSupporter interface {
AssignTreatmentSupporter(
clientID string,
treatmentSupporterID string,
treatmentSupporterType string, // TODO: enum, start with CHV and Treatment buddy
) (bool, error)
}

// IUnassignTreatmentSupporter ...
type IUnassignTreatmentSupporter interface {
UnassignTreatmentSupporter(
clientID string,
treatmentSupporterID string,
reason string, // TODO: ensure these are in an audit log
notes string, // TODO: Optional
) (bool, error)
}

// IAddRelatedPerson ...
type IAddRelatedPerson interface {
// add next of kin
AddRelatedPerson(
clientID string,
relatedPerson *domain.RelatedPerson,
) (*domain.RelatedPerson, bool)
}

// ClientProfileUseCases ...
type ClientProfileUseCases interface {
IAddClientIdentifier
IGetClientIdentifiers
IInactivateClientIdentifier
IRegisterClient
IInactivateClient
IReactivateClient
ITransferClient
IAssignTreatmentSupporter
IUnassignTreatmentSupporter
IAddRelatedPerson
}
19 changes: 9 additions & 10 deletions pkg/onboarding/usecases/facility/facility.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"

"github.com/google/uuid"
"github.com/savannahghi/firebasetools"
"github.com/savannahghi/onboarding-service/pkg/onboarding/application/dto"
"github.com/savannahghi/onboarding-service/pkg/onboarding/domain"
"github.com/savannahghi/onboarding-service/pkg/onboarding/infrastructure"
Expand Down Expand Up @@ -108,15 +107,15 @@ func (f *UseCaseFacilityImpl) Reactivate(id string) (*domain.Facility, error) {
return nil, nil
}

// List returns a list if health facility
// TODO Document: callers should specify active
func (f *UseCaseFacilityImpl) List(
pagination *firebasetools.PaginationInput,
filter []*dto.FacilityFilterInput,
sort []*dto.FacilitySortInput,
) (*dto.FacilityConnection, error) {
return nil, nil
}
// // List returns a list if health facility
// // TODO Document: callers should specify active
// func (f *UseCaseFacilityImpl) List(
// pagination *firebasetools.PaginationInput,
// filter []*dto.FacilityFilterInput,
// sort []*dto.FacilitySortInput,
// ) (*dto.FacilityConnection, error) {
// return nil, nil
// }

// RetrieveFacility find the health facility by ID
func (f *UseCaseFacilityImpl) RetrieveFacility(ctx context.Context, id *uuid.UUID) (*domain.Facility, error) {
Expand Down
Loading

0 comments on commit 8922328

Please sign in to comment.