Skip to content

Commit

Permalink
Merge branch 'main' into hh-reg-location-picker-tests
Browse files Browse the repository at this point in the history
* main:
  add docs on tagging (#3089)
  Constrain isAAB option to Boolean type (#3093)
  Create manual-apk-release.yml (#3003)
  Fix setting related entity location on Group member and related resources (#3092)
  Enhance Image and ActionableButton Widget to add ability to copy text (#3040)
  Add Related entity location tag on newly created resources via configs (#3086)
  Spotless clean
  Fixes config resources flagged for upsync 🐛
  Clean up
  • Loading branch information
AbdulWahabMemon committed Feb 23, 2024
2 parents 2e75ed2 + 2b5d44b commit 177f750
Show file tree
Hide file tree
Showing 39 changed files with 934 additions and 290 deletions.
112 changes: 112 additions & 0 deletions .github/workflows/manual-apk-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Manual APK Release
run-name: Generating a FHIR Core Release APK 🚀
on:
workflow_dispatch:
inputs:
buildType:
description: 'Select APK Build Type'
required: true
default: 'Release'
type: choice
options:
- Debug
- DebugNonProxy
- Release
flavor:
description: 'APK flavor e.g. sidBunda'
required: true
isAab:
description: 'For Playstore release only. Generates AAB'
required: true
type: boolean
default: false
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v3
- name: Import Secrets from Vault
id: import-secrets
uses: hashicorp/[email protected]
with:
url: https://vault.onalabs.org
token: ${{ secrets.VAULT_TOKEN }}
# caCertificate: ${{ secrets.VAULT_CA_CERT }}
tlsSkipVerify: true
secrets: |
kv-v2-fhircore/data/fhircore_apk_credentials KEYSTORE_ALIAS | KEYSTORE_ALIAS;
kv-v2-fhircore/data/fhircore_apk_credentials KEYSTORE_FILE | KEYSTORE_FILE;
kv-v2-fhircore/data/fhircore_apk_credentials KEYSTORE_PASSWORD | KEYSTORE_PASSWORD;
kv-v2-fhircore/data/fhircore_apk_credentials KEY_PASSWORD | KEY_PASSWORD;
kv-v2-fhircore/data/fhircore_apk_credentials LOCAL_PROPERTIES_FILE | LOCAL_PROPERTIES_FILE;
- name: Test secret from Vault
id: test-secret
run: |
touch secrets.json
echo '${{ toJson(steps.import-secrets.outputs)}}' >> secrets.json
cat secrets.json
- name: Decode & Generate Keystore file
run: echo $ENCODED_KEYSTORE | base64 -di > "${HOME}"/fhircore.keystore.jks
env:
ENCODED_KEYSTORE: ${{ secrets.KEYSTORE_FILE }}

- name: Checkout 🛎️
uses: actions/checkout@v2
with:
fetch-depth: 2

- name: Set up JDK 17
uses: actions/setup-java@v1
with:
java-version: 17

- name: Grant execute permission for gradlew
run: chmod +x gradlew
working-directory: android

- name: Decode & Generate local.properties file
run: echo $LOCAL_PROPERTIES | base64 -di > local.properties
working-directory: android
env:
LOCAL_PROPERTIES: ${{ secrets.LOCAL_PROPERTIES_FILE }}

- name: Decode & Generate keystore.properties file
run: echo $KEYSTORE_PROPERTIES | base64 -di > keystore.properties
working-directory: android
env:
KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_FILE }}

- id: product-flavor
name: Generate Product Flavor identifier
run: |
id=$(echo ${{ github.event.inputs.flavor }}${{ github.event.inputs.buildType }} | tr [:upper:] [:lower:])
echo "::set-output name=id::$id"
- name: Generate AAB (Android App Bundle) file
if: ${{ github.event.inputs.isAab }}
run: ./gradlew :quest:bundle${{github.event.inputs.flavor}}${{github.event.inputs.buildType}} -x :quest:test${{github.event.inputs.flavor}}${{github.event.inputs.buildType}}DebugUnitTest --stacktrace
working-directory: android

- name: Upload AAB file to tag assets
if: ${{ github.event.inputs.isAab }}
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: android/quest/build/outputs/bundle/${{steps.product-flavor.outputs.id}}/release/quest-${{steps.product-flavor.outputs.id}}-release.aab
asset_name: "$tag.aab"
tag: ${{ github.ref }}
overwrite: true

- name: Generate APK (Android App PacKage) file
if: ${{ github.event.inputs.isAab != true }}
run: ./gradlew :quest:assemble${{github.event.inputs.flavor}}${{github.event.inputs.buildType}} -x :quest:test${{github.event.inputs.flavor}}${{github.event.inputs.buildType}}DebugUnitTest --stacktrace
working-directory: android

- name: Test APK file generation
run: |
ls -lha android/quest/build/outputs/apk/${{steps.product-flavor.outputs.id}}/release/quest-${{steps.product-flavor.outputs.id}}-release.apk --stacktrace
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import com.google.android.fhir.FhirEngine
import com.google.android.fhir.db.ResourceNotFoundException
import com.google.android.fhir.get
import com.google.android.fhir.knowledge.KnowledgeManager
import com.google.android.fhir.logicalId
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.File
import java.io.FileNotFoundException
Expand Down Expand Up @@ -76,7 +75,6 @@ import org.smartregister.fhircore.engine.util.extension.referenceValue
import org.smartregister.fhircore.engine.util.extension.retrieveCompositionSections
import org.smartregister.fhircore.engine.util.extension.searchCompositionByIdentifier
import org.smartregister.fhircore.engine.util.extension.tryDecodeJson
import org.smartregister.fhircore.engine.util.extension.updateFrom
import org.smartregister.fhircore.engine.util.extension.updateLastUpdated
import org.smartregister.fhircore.engine.util.helper.LocalizationHelper
import retrofit2.HttpException
Expand Down Expand Up @@ -416,7 +414,7 @@ constructor(
} // is focus.identifier a necessary check
.groupBy { section ->
section.focus.reference.substringBefore(
ConfigurationRegistry.TYPE_REFERENCE_DELIMITER,
TYPE_REFERENCE_DELIMITER,
missingDelimiterValue = "",
)
}
Expand Down Expand Up @@ -552,22 +550,17 @@ constructor(
}

/**
* Using this [FhirEngine] and [DispatcherProvider], update this stored resources with the passed
* resource, or create it if not found.
* Update this stored resources with the passed resource, or create it if not found. If the
* resource is a Metadata Resource save it in the Knowledge Manager
*
* Note
*/
suspend fun <R : Resource> addOrUpdate(resource: R) {
withContext(dispatcherProvider.io()) {
resource.updateLastUpdated()
try {
fhirEngine.get(resource.resourceType, resource.logicalId).run {
fhirEngine.update(updateFrom(resource))
}
} catch (resourceNotFoundException: ResourceNotFoundException) {
try {
createRemote(resource)
} catch (sqlException: SQLException) {
Timber.e(sqlException)
}
createOrUpdateRemote(resource)
} catch (sqlException: SQLException) {
Timber.e(sqlException)
}

/**
Expand All @@ -593,7 +586,7 @@ constructor(
?: "${openSrpApplication?.getFhirServerHost().toString()?.trimEnd { it == '/' }}/${this.referenceValue()}"
}

private fun writeToFile(resource: Resource): File {
fun writeToFile(resource: Resource): File {
val fileName =
if (resource is MetadataResource && resource.name != null) {
resource.name
Expand All @@ -610,9 +603,11 @@ constructor(
* Using this [FhirEngine] and [DispatcherProvider], for all passed resources, make sure they all
* have IDs or generate if they don't, then pass them to create.
*
* Note: The backing db API for fhirEngine.create(..,isLocalOnly) performs an UPSERT
*
* @param resources vararg of resources
*/
suspend fun createRemote(vararg resources: Resource) {
suspend fun createOrUpdateRemote(vararg resources: Resource) {
return withContext(dispatcherProvider.io()) {
resources.onEach {
it.updateLastUpdated()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.hl7.fhir.r4.model.ResourceType
import org.smartregister.fhircore.engine.configuration.event.EventWorkflow
import org.smartregister.fhircore.engine.domain.model.ActionConfig
import org.smartregister.fhircore.engine.domain.model.ActionParameter
import org.smartregister.fhircore.engine.domain.model.QuestionnaireType
import org.smartregister.fhircore.engine.domain.model.RuleConfig
import org.smartregister.fhircore.engine.domain.model.SnackBarMessageConfig
import org.smartregister.fhircore.engine.util.extension.extractLogicalIdUuid
Expand All @@ -35,7 +36,7 @@ data class QuestionnaireConfig(
val title: String? = null,
val saveButtonText: String? = null,
val planDefinitions: List<String>? = null,
var type: String = "DEFAULT",
var type: String = QuestionnaireType.DEFAULT.name,
val resourceIdentifier: String? = null,
val resourceType: ResourceType? = null,
val removeResource: Boolean? = null,
Expand All @@ -49,7 +50,7 @@ data class QuestionnaireConfig(
val configRules: List<RuleConfig>? = null,
val extraParams: List<ActionParameter>? = null,
val onSubmitActions: List<ActionConfig>? = null,
val barcodeLinkId: String = "patient-barcode",
val barcodeLinkId: String? = "patient-barcode",
val extractedResourceUniquePropertyExpressions: List<ExtractedResourceUniquePropertyExpression>? =
null,
val saveQuestionnaireResponse: Boolean = true,
Expand All @@ -59,6 +60,7 @@ data class QuestionnaireConfig(
val showRequiredTextAsterisk: Boolean = true,
val showRequiredText: Boolean = false,
val managingEntityRelationshipCode: String? = null,
val linkIds: List<LinkIdConfig>? = null,
) : java.io.Serializable, Parcelable {

fun interpolate(computedValuesMap: Map<String, Any>) =
Expand All @@ -85,8 +87,9 @@ data class QuestionnaireConfig(
planDefinitions = planDefinitions?.map { it.interpolate(computedValuesMap) },
readOnlyLinkIds = readOnlyLinkIds?.map { it.interpolate(computedValuesMap) },
onSubmitActions = onSubmitActions?.map { it.interpolate(computedValuesMap) },
barcodeLinkId = barcodeLinkId.interpolate(computedValuesMap),
barcodeLinkId = barcodeLinkId?.interpolate(computedValuesMap),
cqlInputResources = cqlInputResources?.map { it.interpolate(computedValuesMap) },
linkIds = linkIds?.onEach { it.linkId.interpolate(computedValuesMap) },
)
}

Expand Down Expand Up @@ -114,3 +117,19 @@ data class ExtractedResourceUniquePropertyExpression(
val resourceType: ResourceType,
val fhirPathExpression: String,
) : java.io.Serializable, Parcelable

@Serializable
@Parcelize
data class LinkIdConfig(
val linkId: String,
val type: LinkIdType,
) : java.io.Serializable, Parcelable

@Serializable
@Parcelize
enum class LinkIdType : Parcelable {
READ_ONLY,
BARCODE,
LOCATION,
IDENTIFIER,
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,32 @@ interface ConfigService {
fun provideResourceTags(sharedPreferencesHelper: SharedPreferencesHelper): List<Coding> {
val tags = mutableListOf<Coding>()
defineResourceTags().forEach { strategy ->
if (strategy.type == ResourceType.Practitioner.name) {
val id = sharedPreferencesHelper.read(SharedPreferenceKey.PRACTITIONER_ID.name, null)
if (id.isNullOrBlank()) {
strategy.tag.let { tag -> tags.add(tag.copy().apply { code = "Not defined" }) }
} else {
strategy.tag.let { tag ->
tags.add(tag.copy().apply { code = id.extractLogicalIdUuid() })
}
}
} else {
val ids = sharedPreferencesHelper.read<List<String>>(strategy.type)
if (ids.isNullOrEmpty()) {
strategy.tag.let { tag -> tags.add(tag.copy().apply { code = "Not defined" }) }
} else {
ids.forEach { id ->
when (strategy.type) {
ResourceType.Practitioner.name -> {
val id = sharedPreferencesHelper.read(SharedPreferenceKey.PRACTITIONER_ID.name, null)
if (id.isNullOrBlank() || id.isEmpty()) {
strategy.tag.let { tag -> tags.add(tag.copy().apply { code = "Not defined" }) }
} else {
strategy.tag.let { tag ->
tags.add(tag.copy().apply { code = id.extractLogicalIdUuid() })
}
}
}
APP_VERSION -> tags.add(strategy.tag.copy())
else -> {
val ids = sharedPreferencesHelper.read<List<String>>(strategy.type)
if (ids.isNullOrEmpty()) {
strategy.tag.let { tag -> tags.add(tag.copy().apply { code = "Not defined" }) }
} else {
ids.forEach { id ->
strategy.tag.let { tag ->
tags.add(tag.copy().apply { code = id.extractLogicalIdUuid() })
}
}
}
}
}
}

return tags
}

Expand Down Expand Up @@ -91,5 +94,6 @@ interface ConfigService {

companion object {
const val ACTIVE_SEARCH_PARAM = "active"
const val APP_VERSION = "AppVersion"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ data class NavigationMenuConfig(
data class ImageConfig(
val type: String = ICON_TYPE_LOCAL,
val reference: String? = null,
val color: String? = null,
@Contextual var decodedBitmap: Bitmap? = null,
) : Parcelable, java.io.Serializable {
fun interpolate(computedValuesMap: Map<String, Any>): ImageConfig {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import androidx.compose.ui.graphics.Shape
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import org.smartregister.fhircore.engine.configuration.navigation.ImageConfig
import org.smartregister.fhircore.engine.domain.model.ActionConfig
import org.smartregister.fhircore.engine.domain.model.ViewType
import org.smartregister.fhircore.engine.util.extension.interpolate

Expand All @@ -40,9 +41,12 @@ data class ImageProperties(
override val clickable: String = "false",
override val visible: String = "true",
val tint: String? = null,
val text: String? = null,
val imageConfig: ImageConfig? = null,
val size: Int? = null,
val shape: ImageShape? = null,
val textColor: String? = null,
val actions: List<ActionConfig> = emptyList(),
) : ViewProperties(), Parcelable {
override fun interpolate(computedValuesMap: Map<String, Any>): ViewProperties {
return this.copy(
Expand All @@ -53,6 +57,7 @@ data class ImageProperties(
),
tint = this.tint?.interpolate(computedValuesMap),
backgroundColor = this.backgroundColor?.interpolate(computedValuesMap),
text = this.text?.interpolate(computedValuesMap),
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,7 @@ enum class ApplicationWorkflow {

/** A workflow that launches user insight screen */
LAUNCH_INSIGHT_SCREEN,

/** A workflow that copies text to keyboard */
COPY_TEXT,
}
Loading

0 comments on commit 177f750

Please sign in to comment.