Skip to content

Commit

Permalink
Practitioner Details implementation (#890)
Browse files Browse the repository at this point in the history
* Refactor Practitioner Details implementation (#1520)

* Refactor SharedPreference keys

* Create custom JSON parser

* Refactor SharedPreferencesHelper

* Implement Practitioner Details

* Add fhir-common-utils dependency

* Returns null when Organization is not found

* Add TODO tracker for multi Organization

* Migrate practitioner endpoint url as a String extension

Co-authored-by: Fikri Milano <fikrimilano1@gmail.com>
Co-authored-by: maimoona.kausar <maimoonak.mk@gmail.com>
  • Loading branch information
3 people authored Aug 24, 2022
1 parent ed887e9 commit ddbcf13
Show file tree
Hide file tree
Showing 40 changed files with 1,257 additions and 267 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Adds internationalization(MLS) for App configs
- Adds register, navigation menus and profile configurations using JSON files
- Implements Practitioner Details

## [0.0.9 Quest, 0.0.10 EIR, 0.0.4 - ANC] - 2022-07-04, 2021-11-24, 2022-04-01
### Added
Expand Down
1 change: 1 addition & 0 deletions android/engine/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ dependencies {
implementation 'androidx.fragment:fragment-ktx:1.5.0'
implementation 'io.jsonwebtoken:jjwt:0.9.1'
implementation 'androidx.security:security-crypto:1.1.0-alpha03'
implementation 'org.smartregister:fhir-common-utils:0.0.2-SNAPSHOT'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
implementation "androidx.cardview:cardview:1.0.0"
Expand Down
259 changes: 259 additions & 0 deletions android/engine/src/main/assets/sample_practitioner_payload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
{
"resourceType": "Bundle",
"id": "51d382cf-63e5-4aa8-bcb3-369d2fd300cb",
"meta": {
"lastUpdated": "2022-08-17T07:24:25.608+00:00"
},
"type": "searchset",
"total": 1,
"link": [
{
"relation": "self",
"url": "https://fhir.labs.smartregister.org:443/fhir/practitioner-details?keycloak-uuid=34f0d616-afc8-4446-ae87-bb60be4bdbc9"
}
],
"entry": [
{
"fullUrl": "https://fhir.labs.smartregister.org:443/fhir/practitioner-details/34f0d616-afc8-4446-ae87-bb60be4bdbc9",
"resource": {
"resourceType": "practitioner-details",
"id": "34f0d616-afc8-4446-ae87-bb60be4bdbc9",
"meta": {
"profile": [
"http://hl7.org/fhir/profiles/custom-resource"
]
},
"KeycloakUserDetails": {
"id": "34f0d616-afc8-4446-ae87-bb60be4bdbc9",
"user-bio": [
{
"identifier": "b87ff3c2-cbc6-43e6-b753-a9620756f9e4",
"userName": "demo",
"preferredName": "demo",
"familyName": "41887",
"givenName": "Demo",
"emailVerified": "false"
}
],
"user-roles": [
"ROLE_realm-admin",
"ROLE_OPENMRS",
"ROLE_EDIT_KEYCLOAK_USERS",
"ROLE_offline_access",
"ROLE_VIEW_KEYCLOAK_USERS",
"ROLE_uma_authorization",
"ROLE_ALL_EVENTS",
"ROLE_PLANS_FOR_USER"
]
},
"fhir": {
"id": "136252",
"careteams": [
{
"resourceType": "CareTeam",
"id": "136253",
"meta": {
"versionId": "1",
"lastUpdated": "2022-07-25T16:41:45.221+00:00",
"source": "#98d1c5ca256d7e8b"
},
"identifier": [
{
"use": "official",
"value": "46384571-ad31-4c20-8aa0-266f80ef6582"
}
],
"status": "active",
"name": "Nala Team",
"participant": [
{
"member": {
"reference": "Practitioner/136252"
}
}
]
}
],
"teams": [
{
"resourceType": "Organization",
"id": "136254",
"meta": {
"versionId": "2",
"lastUpdated": "2022-07-25T16:42:51.523+00:00",
"source": "#dad854aca8ea9fcd"
},
"identifier": [
{
"use": "official",
"value": "e58c9509-8ff2-4664-b805-e9dd5bf0cf8a"
}
],
"active": true,
"type": [
{
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/organization-type",
"code": "prov"
}
]
}
],
"name": "Nala Team",
"alias": [
"nala"
]
}
],
"locations": [
{
"resourceType": "Location",
"id": "136256",
"meta": {
"versionId": "1",
"lastUpdated": "2022-07-25T16:44:38.620+00:00",
"source": "#b46640c1adfc6d38"
},
"identifier": [
{
"use": "official",
"value": "c3bd4bcc-889e-4e3d-a72b-a0b611b8fb64"
}
],
"status": "active",
"name": "Nala Location ",
"physicalType": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/location-physical-type",
"code": "jdn",
"display": "Jurisdiction"
}
]
},
"partOf": {
"reference": "Location/109211",
"display": "Charlie Clinic"
}
}
],
"locationHierarchyList": [
{
"resourceType": "LocationHierarchy",
"id": "Location Resource : 136256",
"meta": {
"profile": [
"http://hl7.org/fhir/profiles/custom-resource"
]
},
"LocationHierarchyTree": {
"locationsHierarchy": {
"listOfNodes": {
"treeNodeId": "Location/136256",
"treeNode": [
{
"nodeId": "Location/136256",
"label": "Nala Location ",
"node": {
"resourceType": "Location",
"id": "136256",
"meta": {
"versionId": "1",
"lastUpdated": "2022-07-25T16:44:38.620+00:00",
"source": "#b46640c1adfc6d38"
},
"identifier": [
{
"use": "official",
"value": "c3bd4bcc-889e-4e3d-a72b-a0b611b8fb64"
}
],
"status": "active",
"name": "Nala Location ",
"physicalType": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/location-physical-type",
"code": "jdn",
"display": "Jurisdiction"
}
]
},
"partOf": {
"reference": "Location/109211",
"display": "Charlie Clinic"
}
},
"parent": "Location/109211",
"children": [
{
"childId": "Location/137151",
"treeNode": {
"nodeId": "Location/137151",
"label": "Test Village",
"node": {
"resourceType": "Location",
"id": "137151",
"meta": {
"versionId": "1",
"lastUpdated": "2022-08-04T11:41:32.683+00:00",
"source": "#1bb63352eef7cefc"
},
"identifier": [
{
"use": "official",
"value": "f7f4c729-fd05-40aa-bdc3-fccd74589264"
}
],
"status": "active",
"name": "Test Village",
"description": "Test",
"physicalType": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/location-physical-type",
"code": "jdn",
"display": "Jurisdiction"
}
]
},
"partOf": {
"reference": "Location/136256",
"display": "Nala Location "
}
},
"parent": "Location/136256"
}
}
]
}
]
},
"parentChildren": [
{
"identifier": "Location/109211",
"childIdentifiers": [
"Location/136256"
]
},
{
"identifier": "Location/136256",
"childIdentifiers": [
"Location/137151"
]
}
]
}
},
"locationId": "136256"
}
],
"practitionerId": [
"136252"
]
}
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.core.os.bundleOf
import ca.uhn.fhir.parser.IParser
import dagger.hilt.android.qualifiers.ApplicationContext
import java.util.Locale
import javax.inject.Inject
Expand All @@ -37,11 +38,12 @@ import okhttp3.ResponseBody
import org.smartregister.fhircore.engine.R
import org.smartregister.fhircore.engine.configuration.app.ConfigService
import org.smartregister.fhircore.engine.data.remote.auth.OAuthService
import org.smartregister.fhircore.engine.data.remote.fhir.resource.FhirResourceService
import org.smartregister.fhircore.engine.data.remote.model.response.OAuthResponse
import org.smartregister.fhircore.engine.ui.login.LoginActivity
import org.smartregister.fhircore.engine.util.DispatcherProvider
import org.smartregister.fhircore.engine.util.SecureSharedPreference
import org.smartregister.fhircore.engine.util.SharedPreferencesHelper
import org.smartregister.fhircore.engine.util.extension.practitionerEndpointUrl
import org.smartregister.fhircore.engine.util.extension.showToast
import org.smartregister.fhircore.engine.util.toSha1
import retrofit2.Call
Expand All @@ -56,11 +58,12 @@ constructor(
@ApplicationContext val context: Context,
val accountManager: AccountManager,
val oAuthService: OAuthService,
val fhirResourceService: FhirResourceService,
val parser: IParser,
val configService: ConfigService,
val secureSharedPreference: SecureSharedPreference,
val tokenManagerService: TokenManagerService,
val sharedPreference: SharedPreferencesHelper,
val dispatcherProvider: DispatcherProvider
) : AbstractAccountAuthenticator(context) {

override fun addAccount(
Expand Down Expand Up @@ -183,6 +186,16 @@ constructor(
}
}

fun getPractitionerDetailsFromAssets(): org.hl7.fhir.r4.model.Bundle {
val jsonPayload =
context.assets.open(PATH_PRACTITIONER_DETAILS_PAYLOAD).bufferedReader().use { it.readText() }
return parser.parseResource(jsonPayload) as org.hl7.fhir.r4.model.Bundle
}

suspend fun getPractitionerDetails(keycloakUuid: String): org.hl7.fhir.r4.model.Bundle {
return fhirResourceService.getResource(url = keycloakUuid.practitionerEndpointUrl())
}

@Throws(NetworkErrorException::class)
fun fetchToken(username: String, password: CharArray): Call<OAuthResponse> {
val data = buildOAuthPayload(PASSWORD)
Expand Down Expand Up @@ -348,5 +361,6 @@ constructor(
const val USERNAME = "username"
const val PASSWORD = "password"
const val REFRESH_TOKEN = "refresh_token"
const val PATH_PRACTITIONER_DETAILS_PAYLOAD = "sample_practitioner_payload.json"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import org.hl7.fhir.r4.model.Composition
import org.hl7.fhir.r4.model.ResourceType
import org.smartregister.fhircore.engine.data.local.DefaultRepository
import org.smartregister.fhircore.engine.data.remote.fhir.resource.FhirResourceDataSource
import org.smartregister.fhircore.engine.util.APP_ID_KEY
import org.smartregister.fhircore.engine.util.DispatcherProvider
import org.smartregister.fhircore.engine.util.SharedPreferenceKey
import org.smartregister.fhircore.engine.util.SharedPreferencesHelper
import org.smartregister.fhircore.engine.util.extension.camelCase
import org.smartregister.fhircore.engine.util.extension.decodeJson
Expand Down Expand Up @@ -276,7 +276,7 @@ constructor(
// TODO load these type of configs from assets too
CoroutineScope(dispatcherProvider.io()).launch {
try {
sharedPreferencesHelper.read(APP_ID_KEY, null)?.let { appId: String ->
sharedPreferencesHelper.read(SharedPreferenceKey.APP_ID.name, null)?.let { appId: String ->
repository.searchCompositionByIdentifier(appId)?.let { composition ->
composition
.retrieveCompositionSections()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ import org.hl7.fhir.r4.model.ResourceType
import org.hl7.fhir.r4.model.SearchParameter
import org.smartregister.fhircore.engine.configuration.ConfigType
import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry
import org.smartregister.fhircore.engine.data.remote.model.response.UserInfo
import org.smartregister.fhircore.engine.sync.SyncBroadcaster
import org.smartregister.fhircore.engine.task.FhirTaskPlanWorker
import org.smartregister.fhircore.engine.util.SharedPreferenceKey
import timber.log.Timber

/** An interface that provides the application configurations. */
Expand Down Expand Up @@ -82,7 +82,7 @@ interface ConfigService {
/** Retrieve registry sync params */
fun loadRegistrySyncParams(
configurationRegistry: ConfigurationRegistry,
authenticatedUserInfo: UserInfo?,
paramsMap: Map<String, List<String>>?,
): Map<ResourceType, Map<String, String>> {
val pairs = mutableListOf<Pair<ResourceType, Map<String, String>>>()

Expand All @@ -100,8 +100,13 @@ interface ConfigService {
val paramExpression = sp.expression
val expressionValue =
when (paramName) {
ConfigurationRegistry.ORGANIZATION -> authenticatedUserInfo?.organization
ConfigurationRegistry.PUBLISHER -> authenticatedUserInfo?.questionnairePublisher
// TODO: Does not support multi organization yet,
// https://github.com/opensrp/fhircore/issues/1550
ConfigurationRegistry.ORGANIZATION ->
paramsMap
?.get(SharedPreferenceKey.PRACTITIONER_DETAILS_ORGANIZATION_IDS.name)
?.firstOrNull()
?.substringAfter("/")
ConfigurationRegistry.ID -> paramExpression
ConfigurationRegistry.COUNT -> appConfig.remoteSyncPageSize.toString()
else -> null
Expand Down
Loading

0 comments on commit ddbcf13

Please sign in to comment.