Skip to content

Commit

Permalink
feat: add get all screening tools endpoint
Browse files Browse the repository at this point in the history
Signed-off-by: Allan Sifuna <allansifuna324@gmail.com>
  • Loading branch information
allansifuna committed Dec 15, 2023
1 parent 983d77e commit 4dc515e
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 10 deletions.
6 changes: 6 additions & 0 deletions pkg/mycarehub/application/dto/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ type FacilityOutputPage struct {
Facilities []*domain.Facility
}

// ScreeningToolOutputPage returns a paginated list of screening tools
type ScreeningToolOutputPage struct {
Pagination *domain.Pagination `json:"pagination"`
ScreeningTools []*domain.ScreeningTool `json:"screeningTools"`
}

// ManagedClientOutputPage returns a paginated list of managed client profiles
type ManagedClientOutputPage struct {
Pagination *domain.Pagination `json:"pagination"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ type GormMock struct {
MockGetQuestionInputChoicesByQuestionIDFn func(ctx context.Context, questionID string) ([]*gorm.QuestionInputChoice, error)
MockCreateScreeningToolResponseFn func(ctx context.Context, screeningToolResponse *gorm.ScreeningToolResponse, screeningToolQuestionResponses []*gorm.ScreeningToolQuestionResponse) (*string, error)
MockGetAvailableScreeningToolsFn func(ctx context.Context, clientID string, screeningTool gorm.ScreeningTool, screeningToolIDs []string) ([]*gorm.ScreeningTool, error)
MockGetAllScreeningToolsFn func(ctx context.Context, pagination *domain.Pagination) ([]*gorm.ScreeningTool, *domain.Pagination, error)
MockGetScreeningToolResponsesWithin24HoursFn func(ctx context.Context, clientID, programID string) ([]*gorm.ScreeningToolResponse, error)
MockGetScreeningToolResponsesWithPendingServiceRequestsFn func(ctx context.Context, clientID, programID string) ([]*gorm.ScreeningToolResponse, error)
MockGetFacilityRespondedScreeningToolsFn func(ctx context.Context, facilityID, programID string, pagination *domain.Pagination) ([]*gorm.ScreeningTool, *domain.Pagination, error)
Expand Down Expand Up @@ -2460,6 +2461,11 @@ func (gm *GormMock) GetAvailableScreeningTools(ctx context.Context, clientID str
return gm.MockGetAvailableScreeningToolsFn(ctx, clientID, screeningTool, screeningToolIDs)
}

// GetAllScreeningTools mocks the implementation of getting all screening tools
func (gm *GormMock) GetAllScreeningTools(ctx context.Context, pagination *domain.Pagination) ([]*gorm.ScreeningTool, *domain.Pagination, error) {
return gm.MockGetAllScreeningToolsFn(ctx, pagination)
}

// GetScreeningToolResponsesWithin24Hours mocks the implementation of GetScreeningToolResponsesWithin24Hours method
func (gm *GormMock) GetScreeningToolResponsesWithin24Hours(ctx context.Context, clientID, programID string) ([]*gorm.ScreeningToolResponse, error) {
return gm.MockGetScreeningToolResponsesWithin24HoursFn(ctx, clientID, programID)
Expand Down
23 changes: 23 additions & 0 deletions pkg/mycarehub/infrastructure/database/postgres/gorm/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ type Query interface {
GetQuestionInputChoicesByQuestionID(ctx context.Context, questionID string) ([]*QuestionInputChoice, error)
GetAvailableScreeningTools(ctx context.Context, clientID string, screeningTool ScreeningTool, screeningToolIDs []string) ([]*ScreeningTool, error)
GetScreeningToolResponsesWithin24Hours(ctx context.Context, clientID, programID string) ([]*ScreeningToolResponse, error)
GetAllScreeningTools(ctx context.Context, pagination *domain.Pagination) ([]*ScreeningTool, *domain.Pagination, error)
GetScreeningToolResponsesWithPendingServiceRequests(ctx context.Context, clientID, programID string) ([]*ScreeningToolResponse, error)
GetFacilityRespondedScreeningTools(ctx context.Context, facilityID, programID string, pagination *domain.Pagination) ([]*ScreeningTool, *domain.Pagination, error)
GetScreeningToolServiceRequestOfRespondents(ctx context.Context, facilityID, programID string, screeningToolID string, searchTerm string, pagination *domain.Pagination) ([]*ClientServiceRequest, *domain.Pagination, error)
Expand Down Expand Up @@ -1430,6 +1431,28 @@ func (db *PGInstance) GetAvailableScreeningTools(ctx context.Context, clientID s
return screeningTools, nil
}

// GetAllScreeningTools returns all the available screening tools with pagination
func (db *PGInstance) GetAllScreeningTools(ctx context.Context, pagination *domain.Pagination) ([]*ScreeningTool, *domain.Pagination, error) {
var screeningTools []*ScreeningTool
var count int64

tx := db.DB.Model(&screeningTools)
if pagination != nil {
if err := tx.Count(&count).Error; err != nil {
return nil, nil, err
}

pagination.Count = count
paginateQuery(tx, pagination)
}

if err := tx.Find(&screeningTools).Error; err != nil {
return nil, nil, err
}

return screeningTools, pagination, nil
}

// GetScreeningToolResponsesWithin24Hours gets the user screening response that are within 24 hours
func (db *PGInstance) GetScreeningToolResponsesWithin24Hours(ctx context.Context, clientID, programID string) ([]*ScreeningToolResponse, error) {
var screeningToolResponses []*ScreeningToolResponse
Expand Down
35 changes: 35 additions & 0 deletions pkg/mycarehub/infrastructure/database/postgres/gorm/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5588,6 +5588,41 @@ func TestPGInstance_GetAvailableScreeningTools(t *testing.T) {
}
}

func TestPGInstance_GetAllScreeningTools(t *testing.T) {
type args struct {
ctx context.Context
pagination *domain.Pagination
}
tests := []struct {
name string
args args
wantCount int
wantErr bool
}{
{
name: "Happy case: get all screening tools",
args: args{
ctx: context.Background(),
pagination: &domain.Pagination{
Limit: 10,
CurrentPage: 1,
},
},
wantErr: false,
wantCount: 10,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, _, err := testingDB.GetAllScreeningTools(tt.args.ctx, tt.args.pagination)
if (err != nil) != tt.wantErr {
t.Errorf("PGInstance.GetAllScreeningTools() error = %v, wantErr %v", err, tt.wantErr)
return
}
})
}
}

func TestPGInstance_GetScreeningToolResponsesWithin24Hours(t *testing.T) {
type args struct {
ctx context.Context
Expand Down
23 changes: 23 additions & 0 deletions pkg/mycarehub/infrastructure/database/postgres/mock/pg_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ type PostgresMock struct {
MockCreateBookingFn func(ctx context.Context, booking *domain.Booking) (*domain.Booking, error)
MockUpdateBookingFn func(ctx context.Context, booking *domain.Booking, updateData map[string]interface{}) error
MockListBookingsFn func(ctx context.Context, clientID string, bookingState enums.BookingState, pagination *domain.Pagination) ([]*domain.Booking, *domain.Pagination, error)
MockGetAllScreeningToolsFn func(ctx context.Context, pagination *domain.Pagination) ([]*domain.ScreeningTool, *domain.Pagination, error)
}

// NewPostgresMock initializes a new instance of `GormMock` then mocking the case of success.
Expand Down Expand Up @@ -1898,6 +1899,23 @@ func NewPostgresMock() *PostgresMock {
Limit: 10,
}, nil
},
MockGetAllScreeningToolsFn: func(ctx context.Context, pagination *domain.Pagination) ([]*domain.ScreeningTool, *domain.Pagination, error) {
return []*domain.ScreeningTool{
{
ID: ID,
Active: true,
QuestionnaireID: ID,
Threshold: 4,
ClientTypes: []enums.ClientType{"PMTCT"},
Genders: []enumutils.Gender{"MALE"},
AgeRange: domain.AgeRange{
LowerBound: 14,
UpperBound: 20,
},
Questionnaire: domain.Questionnaire{},
},
}, pagination, nil
},
}
}

Expand Down Expand Up @@ -2518,6 +2536,11 @@ func (gm *PostgresMock) GetAvailableScreeningTools(ctx context.Context, clientID
return gm.MockGetAvailableScreeningToolsFn(ctx, clientID, screeningTool, screeningToolIDs)
}

// GetAllScreeningTools mocks the implementation of getting all screening tools
func (gm *PostgresMock) GetAllScreeningTools(ctx context.Context, pagination *domain.Pagination) ([]*domain.ScreeningTool, *domain.Pagination, error) {
return gm.MockGetAllScreeningToolsFn(ctx, pagination)
}

// GetScreeningToolResponsesWithin24Hours mocks the implementation of GetScreeningToolResponsesWithin24Hours method
func (gm *PostgresMock) GetScreeningToolResponsesWithin24Hours(ctx context.Context, clientID, programID string) ([]*domain.QuestionnaireScreeningToolResponse, error) {
return gm.MockGetScreeningToolResponsesWithin24HoursFn(ctx, clientID, programID)
Expand Down
46 changes: 46 additions & 0 deletions pkg/mycarehub/infrastructure/database/postgres/pg_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2201,6 +2201,52 @@ func (d *MyCareHubDb) GetAvailableScreeningTools(ctx context.Context, clientID s
return screeningToolList, nil
}

// GetAllScreeningTools fetches all screening tools for a client based on set criteria settings
func (d *MyCareHubDb) GetAllScreeningTools(ctx context.Context, pagination *domain.Pagination) ([]*domain.ScreeningTool, *domain.Pagination, error) {

screeningTools, pagination, err := d.query.GetAllScreeningTools(ctx, pagination)
if err != nil {
return nil, nil, err
}

var screeningToolList []*domain.ScreeningTool
for _, s := range screeningTools {
var clientTypes []enums.ClientType
for _, k := range s.ClientTypes {
clientTypes = append(clientTypes, enums.ClientType(k))
}
var genders []enumutils.Gender
for _, g := range s.Genders {
genders = append(genders, enumutils.Gender(g))
}

questionnaire, err := d.query.GetQuestionnaireByID(ctx, s.QuestionnaireID)
if err != nil {
return nil, nil, err
}

screeningToolList = append(screeningToolList, &domain.ScreeningTool{
ID: s.ID,
Active: s.Active,
QuestionnaireID: s.QuestionnaireID,
Threshold: s.Threshold,
ClientTypes: clientTypes,
Genders: genders,
AgeRange: domain.AgeRange{
LowerBound: s.MinimumAge,
UpperBound: s.MaximumAge,
},
Questionnaire: domain.Questionnaire{
ID: questionnaire.ID,
Active: questionnaire.Active,
Name: questionnaire.Name,
Description: questionnaire.Description,
},
})
}
return screeningToolList, pagination, nil
}

// GetScreeningToolResponsesWithin24Hours gets the user screening response that are within 24 hours
func (d *MyCareHubDb) GetScreeningToolResponsesWithin24Hours(ctx context.Context, clientID, programID string) ([]*domain.QuestionnaireScreeningToolResponse, error) {
screeningToolResponsesList, err := d.query.GetScreeningToolResponsesWithin24Hours(ctx, clientID, programID)
Expand Down
1 change: 1 addition & 0 deletions pkg/mycarehub/infrastructure/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ type Query interface {
SearchStaffServiceRequests(ctx context.Context, searchParameter string, requestType string, facilityID string) ([]*domain.ServiceRequest, error)
GetScreeningToolByID(ctx context.Context, screeningToolID string) (*domain.ScreeningTool, error)
GetAvailableScreeningTools(ctx context.Context, clientID string, screeningTool domain.ScreeningTool, screeningToolIDs []string) ([]*domain.ScreeningTool, error)
GetAllScreeningTools(ctx context.Context, pagination *domain.Pagination) ([]*domain.ScreeningTool, *domain.Pagination, error)
GetScreeningToolResponsesWithin24Hours(ctx context.Context, clientID, programID string) ([]*domain.QuestionnaireScreeningToolResponse, error)
GetScreeningToolResponsesWithPendingServiceRequests(ctx context.Context, clientID, programID string) ([]*domain.QuestionnaireScreeningToolResponse, error)
GetFacilityRespondedScreeningTools(ctx context.Context, facilityID, programID string, pagination *domain.Pagination) ([]*domain.ScreeningTool, *domain.Pagination, error)
Expand Down
4 changes: 4 additions & 0 deletions pkg/mycarehub/presentation/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ func Router(ctx context.Context) (*mux.Router, error) {
http.MethodOptions,
http.MethodGet,
).HandlerFunc(internalHandlers.GetServices())
r.Path("/screening-tools").Methods(
http.MethodOptions,
http.MethodGet,
).HandlerFunc(internalHandlers.GetAllScreeningTools())

// TODO: Refactor to implement delete client, staff and caregiver
// r.Path("/delete-user").Methods(
Expand Down
23 changes: 23 additions & 0 deletions pkg/mycarehub/presentation/rest/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type MyCareHubHandlersInterfaces interface {
SyncFacilities() http.HandlerFunc
GetServices() http.HandlerFunc
AppointmentsServiceRequests() http.HandlerFunc
GetAllScreeningTools() http.HandlerFunc
// DeleteUser() http.HandlerFunc
FetchContactOrganisations() http.HandlerFunc
Organisations() http.HandlerFunc
Expand Down Expand Up @@ -254,6 +255,28 @@ func (h *MyCareHubHandlersInterfacesImpl) GetServices() http.HandlerFunc {
}
}

// GetAllScreeningTools is an unauthenticated endpoint that returns a list of services
func (h *MyCareHubHandlersInterfacesImpl) GetAllScreeningTools() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

paginationInput := &dto.PaginationsInput{}
serverutils.DecodeJSONToTargetStruct(w, r, paginationInput)
resp, err := h.usecase.Questionnaires.GetAllScreeningTools(ctx, paginationInput)
if err != nil {
helpers.ReportErrorToSentry(err)
serverutils.WriteJSONResponse(w, errorcodeutil.CustomError{
Err: err,
Message: err.Error(),
Code: exceptions.GetErrorCode(err),
}, http.StatusBadRequest)
return
}

serverutils.WriteJSONResponse(w, resp, http.StatusOK)
}
}

// VerifyPhone is an unauthenticated endpoint that does a check on the provided username,
// performs a check to ascertain whether the user exists. it verifies whether the user also has a phone number where the otp will be sent
func (h *MyCareHubHandlersInterfacesImpl) VerifyPhone() http.HandlerFunc {
Expand Down
126 changes: 126 additions & 0 deletions pkg/mycarehub/presentation/rest/handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2015,6 +2015,132 @@ func TestMyCareHubHandlersInterfacesImpl_GetServices(t *testing.T) {
})
}
}
func TestMyCareHubHandlersInterfacesImpl_GetAllScreeningTools(t *testing.T) {
paginationInput := &dto.PaginationsInput{
Limit: 10,
CurrentPage: 1,
}
paginationPayload, err := json.Marshal(paginationInput)
if err != nil {
t.Errorf("error marshling pagination payload: %v", err)
return
}
invalidPaginationInput := &dto.PaginationsInput{
Limit: 10,
}
invalidPaginationPayload, err := json.Marshal(invalidPaginationInput)
if err != nil {
t.Errorf("error marshling pagination payload: %v", err)
return
}
type args struct {
url string
httpMethod string
body io.Reader
}
tests := []struct {
name string
args args
wantStatus int
wantErr bool
}{
{
name: "Happy Case - Successfully get all screening tools",
args: args{
url: fmt.Sprintf(
"%s/screening-tools",
baseURL,
),
httpMethod: http.MethodGet,
body: bytes.NewBuffer(paginationPayload),
},
wantStatus: http.StatusOK,
wantErr: false,
},
{
name: "Sad Case - failed to get all screening tools",
args: args{
url: fmt.Sprintf(
"%s/screening-tools",
baseURL,
),
httpMethod: http.MethodGet,
body: bytes.NewBuffer(invalidPaginationPayload),
},
wantStatus: http.StatusBadRequest,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r, err := http.NewRequest(
tt.args.httpMethod,
tt.args.url,
tt.args.body,
)
if err != nil {
t.Errorf("unable to compose request: %s", err)
return
}

if r == nil {
t.Errorf("nil request")
return
}
client := http.DefaultClient
r.Header.Add("Accept", "application/json")
r.Header.Add("Content-Type", "application/json")
resp, err := client.Do(r)
if err != nil {
t.Errorf("request error: %s", err)
return
}

if resp == nil && !tt.wantErr {
t.Errorf("nil response")
return
}

dataResponse, err := io.ReadAll(resp.Body)
if err != nil {
t.Errorf("can't read request body: %s", err)
return
}
if dataResponse == nil {
t.Errorf("nil response data")
return
}

data := map[string]interface{}{}
err = json.Unmarshal(dataResponse, &data)
if tt.wantErr && err != nil {
t.Errorf("bad data returned: %v", err)
return
}

if tt.wantErr {
errMsg, ok := data["error"]
if !ok {
t.Errorf("expected error: %s", errMsg)
return
}
}

if !tt.wantErr {
_, ok := data["error"]
if ok {
t.Errorf("error not expected")
return
}
}

if resp.StatusCode != tt.wantStatus {
t.Errorf("expected status %d, got %s", tt.wantStatus, resp.Status)
return
}
})
}
}

// TODO: Refactor to implement delete client, staff and caregiver
// func TestMyCareHubHandlersInterfacesImpl_DeleteUser(t *testing.T) {
Expand Down

0 comments on commit 4dc515e

Please sign in to comment.