Skip to content

Commit

Permalink
chore: scaffold user staff models (#34)
Browse files Browse the repository at this point in the history
Signed-off-by: maxwellgithinji <maxwellgithinji@gmail.com>
  • Loading branch information
maxwellgithinji committed Oct 15, 2021
1 parent 2a6ab85 commit 8172a56
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 13 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/imroc/req v0.3.0
github.com/lib/pq v1.10.3
github.com/savannahghi/converterandformatter v0.0.9
github.com/savannahghi/enumutils v0.0.3
github.com/savannahghi/feedlib v0.0.4
Expand Down
10 changes: 5 additions & 5 deletions pkg/onboarding/domain/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ type Identifier struct {
//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
ID uuid.UUID // 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
UserID uuid.UUID // TODO: Foreign key to User

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

Expand Down Expand Up @@ -200,15 +200,15 @@ 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
UserID uuid.UUID // 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
FacilityID uuid.UUID

TreatmentEnrollmentDate *time.Time

Expand Down Expand Up @@ -256,7 +256,7 @@ type Metric struct {
type StaffProfile struct {
ID *string

UserID string // foreign key to user
UserID uuid.UUID // foreign key to user

StaffNumber string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type Create interface {
GetOrCreateFacility(ctx context.Context, facility *Facility) (*Facility, error)
CollectMetrics(ctx context.Context, metrics *Metric) (*Metric, error)
// RegisterStaffUser(user User, profile StaffProfile) (*User, *StaffProfile, error)
}

// GetOrCreateFacility ...
Expand Down
137 changes: 129 additions & 8 deletions pkg/onboarding/infrastructure/database/postgres/gorm/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,6 @@ func (Facility) TableName() string {
return "facility"
}

func allTables() []interface{} {
tables := []interface{}{
&Facility{},
&Metric{},
}
return tables
}

// Metric reprents the metrics data structure input
type Metric struct {
Base
Expand Down Expand Up @@ -85,3 +77,132 @@ func (m *Metric) BeforeCreate(tx *gorm.DB) (err error) {
func (Metric) TableName() string {
return "metric"
}

// User represents the table data structure for a user
type User struct {
Base

UserID *uuid.UUID `gorm:"primaryKey;unique;column:user_id"` // globally unique ID

Username string `gorm:"column:username"` // @handle, also globally unique; nickname

DisplayName string `gorm:"column:display_name"` // user's preferred display name

// TODO Consider making the names optional in DB; validation in frontends
FirstName string `gorm:"column:first_name"` // given name
MiddleName *string `gorm:"column:user_id"`
LastName string `gorm:"column:last_name"`

UserType string `gorm:"column:user_type"` // TODO enum; e.g client, health care worker

Gender string `gorm:"column:gender"` // TODO enum; genders; keep it simple

Active bool `gorm:"column:active"`

Contacts []Contact `gorm:"many2many:user_contact;"` // TODO: validate, ensure

// for the preferred language list, order matters
Languages []string `gorm:"type:text[];column:languages"` // TODO: turn this into a slice of enums, start small (en, sw)

PushTokens []string `gorm:"type:text[];column:push_tokens"`

// when a user logs in successfully, set this
LastSuccessfulLogin *time.Time `gorm:"type:time;column:last_successful_login"`

// 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 `gorm:"type:time;column:last_failed_login"`

// each time there is a failed login, **increment** this
// set to zero after successful login
FailedLoginCount int `gorm:"column:failed_login_count"`

// calculated each time there is a failed login
NextAllowedLogin *time.Time `gorm:"type:time;column:next_allowed_login"`

TermsAccepted bool `gorm:"type:bool;column:terms_accepted"`
AcceptedTermsID string `gorm:"column:accepted_terms_id"` // foreign key to version of terms they accepted
}

// TableName customizes how the table name is generated
func (User) TableName() string {
return "user"
}

// Contact hold contact information/details for users
type Contact struct {
Base

ContactID uuid.UUID `gorm:"primaryKey;unique;column:contact_id"`

Type string `gorm:"column:type"` // TODO enum

Contact string `gorm:"column:contact"` // TODO Validate: phones are E164, emails are valid

Active bool `gorm:"column:active"`

// 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 `gorm:"column:opted_in"`
}

// TableName customizes how the table name is generated
func (Contact) TableName() string {
return "contact"
}

// StaffProfile contains all the information a staff should have about themselves
type StaffProfile struct {
StaffProfileID *uuid.UUID `gorm:"primaryKey;unique;column:staff_profile_id"`

UserID *uuid.UUID `gorm:"unique;column:user_id"` // foreign key to user
User User `gorm:"foreignKey:user_id;references:user_id;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`

StaffNumber string `gorm:"column:staff_number"`

Facilities []*Facility `gorm:"many2many:staffprofile_facility;not null;"` // TODO: needs at least one

// A UI switcher optionally toggles the default
// TODO: the list of facilities to switch between is strictly those that the user is assigned to
DefaultFacilityID uuid.UUID `gorm:"column:default_facility_id"` // TODO: required, FK to facility
Facility Facility `gorm:"foreignKey:default_facility_id;references:facility_id;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`

// there is nothing special about super-admin; just the set of roles they have
Roles []string `gorm:"type:text[];column:roles"` // TODO: roles are an enum (controlled list), known to both FE and BE

Addresses []*Address `gorm:"many2many:staffprofile_address;"`
}

// TableName customizes how the table name is generated
func (StaffProfile) TableName() string {
return "staffprofile"
}

// Address are value objects for user address e.g postal code
type Address struct {
AddressID *uuid.UUID `gorm:"primaryKey;unique;column:address_id"` // globally unique

Type string `gorm:"column:type"` // TODO: enum; postal, physical or both
Text string `gorm:"column:text"` // actual address, can be multi-line
Country string `gorm:"column:country"` // TODO: enum
PostalCode string `gorm:"column:postal_code"`
County string `gorm:"column:county"` // TODO: counties belong to a country
Active bool `gorm:"column:active"`
}

// TableName customizes how the table name is generated
func (Address) TableName() string {
return "address"
}

func allTables() []interface{} {
tables := []interface{}{
&Facility{},
&Metric{},
&User{},
&Contact{},
&StaffProfile{},
&Address{},
}
return tables
}

0 comments on commit 8172a56

Please sign in to comment.