Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AuditEvent Resource #53

Merged
merged 3 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<Practitioner>(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()
}
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -119,4 +121,10 @@ interface ConfigService {
workRequest,
)
}

fun scheduleAuditEvent(context: Context) {
val workRequest = OneTimeWorkRequestBuilder<AuditEventWorker>().build()

WorkManager.getInstance(context).enqueue(workRequest)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
1 change: 1 addition & 0 deletions android/engine/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,5 @@
<string name="error_loading_config_general">Error connecting to the server. Please contact the system administrator</string>
<string name="re_fetch_practitioner">Re-fetch Practitioner</string>
<string name="dev_menu">Dev Menu</string>
<string name="audit_event_system">http://dicom.nema.org/resources/ontology/DCM</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -61,9 +62,11 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener {

@Inject lateinit var configService: ConfigService

@Inject lateinit var tokenAuthenticator: TokenAuthenticator

val appMainViewModel by viewModels<AppMainViewModel>()

val authActivityLauncherForResult =
private val authActivityLauncherForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { res ->
if (res.resultCode == Activity.RESULT_OK) {
appMainViewModel.onEvent(AppMainEvent.ResumeSync)
Expand All @@ -75,6 +78,7 @@ open class AppMainActivity : BaseMultiLanguageActivity(), OnSyncListener {
setupTimeOutListener()
setContent { AppTheme { MainScreen(appMainViewModel = appMainViewModel) } }
syncBroadcaster.registerSyncListener(this, lifecycleScope)
scheduleAuthWorkers()
}

override fun onResume() {
Expand Down Expand Up @@ -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 =
Expand Down
Loading