From 439beffd0248f603b7b70f87e54c6d04c49ac4b0 Mon Sep 17 00:00:00 2001 From: Evance <56567958+evance-mose@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:17:00 -0700 Subject: [PATCH] AuditEvent Resource (#53) * Add auditEvent * add repository for auditEvent * spotless --- .../engine/auditEvent/AuditEventRepository.kt | 88 +++++++++++++++++++ .../engine/auditEvent/AuditEventWorker.kt | 45 ++++++++++ .../engine/configuration/app/ConfigService.kt | 8 ++ .../fhircore/engine/di/CoreModule.kt | 8 ++ .../engine/src/main/res/values/strings.xml | 1 + .../fhircore/quest/ui/main/AppMainActivity.kt | 13 ++- 6 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventRepository.kt create mode 100644 android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventWorker.kt diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventRepository.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventRepository.kt new file mode 100644 index 0000000000..3ad1be229b --- /dev/null +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventRepository.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.engine.auditEvent + +import java.util.Date +import java.util.UUID +import javax.inject.Inject +import javax.inject.Singleton +import org.hl7.fhir.r4.model.AuditEvent +import org.hl7.fhir.r4.model.Coding +import org.hl7.fhir.r4.model.Practitioner +import org.smartregister.fhircore.engine.R +import org.smartregister.fhircore.engine.data.local.DefaultRepository +import org.smartregister.fhircore.engine.util.SharedPreferenceKey +import org.smartregister.fhircore.engine.util.SharedPreferencesHelper +import org.smartregister.fhircore.engine.util.extension.asReference + +@Singleton +class AuditEventRepository +@Inject +constructor( + val defaultRepository: DefaultRepository, + val sharedPreferences: SharedPreferencesHelper, +) : IAuditEventRepository { + override suspend fun createAuditEvent() { + // Get Practitioner Resource + val practitionerID = + sharedPreferences.read(key = SharedPreferenceKey.PRACTITIONER_ID.name, defaultValue = null) + ?: return + + val practitioner = defaultRepository.loadResource(practitionerID!!) + + val context = sharedPreferences.context + + // Create AuditEvent Resource + val auditEvent = + AuditEvent().apply { + id = UUID.randomUUID().toString() + type = + Coding().apply { + system = context.getString(R.string.audit_event_system) + code = "110114" + display = "User Authentication" + } + subtype = + listOf( + Coding().apply { + system = context.getString(R.string.audit_event_system) + code = "110122" + display = "Login" + }, + ) + outcome = AuditEvent.AuditEventOutcome._0 + action = AuditEvent.AuditEventAction.C + recorded = Date() + agent = + listOf( + AuditEvent.AuditEventAgentComponent().apply { + who = practitioner?.asReference() + requestor = true + }, + ) + source = + AuditEvent.AuditEventSourceComponent().apply { observer = practitioner?.asReference() } + } + + // Save AuditEvent Resource + defaultRepository.addOrUpdate(true, auditEvent) + } +} + +interface IAuditEventRepository { + suspend fun createAuditEvent() +} diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventWorker.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventWorker.kt new file mode 100644 index 0000000000..90a32c97e2 --- /dev/null +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/auditEvent/AuditEventWorker.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2021 Ona Systems, Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.smartregister.fhircore.engine.auditEvent + +import android.content.Context +import androidx.hilt.work.HiltWorker +import androidx.work.CoroutineWorker +import androidx.work.WorkerParameters +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import timber.log.Timber + +@HiltWorker +class AuditEventWorker +@AssistedInject +constructor( + @Assisted val appContext: Context, + @Assisted workerParameters: WorkerParameters, + private val auditEventRepository: AuditEventRepository, +) : CoroutineWorker(appContext, workerParameters) { + + override suspend fun doWork(): Result { + Timber.e("AuditEventWorker is running") + auditEventRepository.createAuditEvent() + return Result.success() + } + + companion object { + const val NAME = "AuditEventWorker" + } +} diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ConfigService.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ConfigService.kt index 10bace2ec2..fc6077c3cd 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ConfigService.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/configuration/app/ConfigService.kt @@ -18,12 +18,14 @@ package org.smartregister.fhircore.engine.configuration.app import android.content.Context import androidx.work.ExistingPeriodicWorkPolicy +import androidx.work.OneTimeWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder import androidx.work.WorkManager import java.util.concurrent.TimeUnit import org.hl7.fhir.r4.model.Coding import org.smartregister.fhircore.engine.appointment.MissedFHIRAppointmentsWorker import org.smartregister.fhircore.engine.appointment.ProposedWelcomeServiceAppointmentsWorker +import org.smartregister.fhircore.engine.auditEvent.AuditEventWorker import org.smartregister.fhircore.engine.sync.ResourceTag import org.smartregister.fhircore.engine.task.FhirTaskPlanWorker import org.smartregister.fhircore.engine.task.WelcomeServiceBackToCarePlanWorker @@ -119,4 +121,10 @@ interface ConfigService { workRequest, ) } + + fun scheduleAuditEvent(context: Context) { + val workRequest = OneTimeWorkRequestBuilder().build() + + WorkManager.getInstance(context).enqueue(workRequest) + } } diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/di/CoreModule.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/di/CoreModule.kt index ca29e8e5e7..e32e09ec55 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/di/CoreModule.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/di/CoreModule.kt @@ -30,6 +30,7 @@ import dagger.hilt.components.SingletonComponent import javax.inject.Singleton import org.hl7.fhir.r4.context.SimpleWorkerContext import org.hl7.fhir.r4.model.Parameters +import org.smartregister.fhircore.engine.auditEvent.AuditEventRepository import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry import org.smartregister.fhircore.engine.configuration.app.ConfigService import org.smartregister.fhircore.engine.data.local.DefaultRepository @@ -91,4 +92,11 @@ class CoreModule { defaultRepository: DefaultRepository, configurationRegistry: ConfigurationRegistry, ): PatientDao = HivRegisterDao(fhirEngine, defaultRepository, configurationRegistry) + + @Singleton + @Provides + fun provideAudiEventRepository( + defaultRepository: DefaultRepository, + sharedPreferencesHelper: SharedPreferencesHelper, + ): AuditEventRepository = AuditEventRepository(defaultRepository, sharedPreferencesHelper) } diff --git a/android/engine/src/main/res/values/strings.xml b/android/engine/src/main/res/values/strings.xml index df30809186..6b537661db 100644 --- a/android/engine/src/main/res/values/strings.xml +++ b/android/engine/src/main/res/values/strings.xml @@ -155,4 +155,5 @@ Error connecting to the server. Please contact the system administrator Re-fetch Practitioner Dev Menu + http://dicom.nema.org/resources/ontology/DCM diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt index 31bf881041..2d79dd8fae 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/main/AppMainActivity.kt @@ -34,6 +34,7 @@ import org.hl7.fhir.r4.model.Encounter import org.hl7.fhir.r4.model.ResourceType import org.smartregister.fhircore.engine.R import org.smartregister.fhircore.engine.configuration.app.ConfigService +import org.smartregister.fhircore.engine.data.remote.shared.TokenAuthenticator import org.smartregister.fhircore.engine.sync.OnSyncListener import org.smartregister.fhircore.engine.sync.SyncBroadcaster import org.smartregister.fhircore.engine.task.FhirCarePlanGenerator @@ -61,9 +62,11 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { @Inject lateinit var configService: ConfigService + @Inject lateinit var tokenAuthenticator: TokenAuthenticator + val appMainViewModel by viewModels() - val authActivityLauncherForResult = + private val authActivityLauncherForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { res -> if (res.resultCode == Activity.RESULT_OK) { appMainViewModel.onEvent(AppMainEvent.ResumeSync) @@ -75,6 +78,7 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { setupTimeOutListener() setContent { AppTheme { MainScreen(appMainViewModel = appMainViewModel) } } syncBroadcaster.registerSyncListener(this, lifecycleScope) + scheduleAuthWorkers() } override fun onResume() { @@ -171,6 +175,13 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener { } } + private fun scheduleAuthWorkers() { + val isAuthenticated = tokenAuthenticator.sessionActive() + if (isAuthenticated) { + with(configService) { scheduleAuditEvent(applicationContext) } + } + } + private fun setupTimeOutListener() { if (application is QuestApplication) { (application as QuestApplication).onInActivityListener =