Skip to content

Commit

Permalink
Merge pull request #6487 from grzesiek2010/COLLECT-6485
Browse files Browse the repository at this point in the history
Do not lock the forms db when a form uses entities but is started in view-only mode
  • Loading branch information
seadowg authored Oct 31, 2024
2 parents 0fcf9e3 + cbaeeb5 commit 1a10357
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.odk.collect.android.support.pages

import org.odk.collect.android.R

class ViewFormPage(private val formName: String) : Page<ViewFormPage>() {

override fun assertOnPage(): ViewFormPage {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,14 @@ class FormUriActivity : LocalizedActivity() {
object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>, extras: CreationExtras): T {
return FormUriViewModel(
intent.data,
intent,
scheduler,
projectsRepository,
projectsDataService,
contentResolver,
formsRepositoryProvider,
instanceRepositoryProvider,
settingsProvider,
savepointsRepositoryProvider,
changeLockProvider,
resources
Expand Down Expand Up @@ -142,12 +143,6 @@ class FormUriActivity : LocalizedActivity() {
action = intent.action
data = uri
intent.extras?.let { sourceExtras -> putExtras(sourceExtras) }
if (!canFormBeEdited()) {
putExtra(
ApplicationConstants.BundleKeys.FORM_MODE,
ApplicationConstants.FormModes.VIEW_SENT
)
}
}
)
}
Expand All @@ -162,20 +157,6 @@ class FormUriActivity : LocalizedActivity() {
.show()
}

private fun canFormBeEdited(): Boolean {
val uri = intent.data!!
val uriMimeType = contentResolver.getType(uri)

val formEditingEnabled = if (uriMimeType == InstancesContract.CONTENT_ITEM_TYPE) {
val instance = instanceRepositoryProvider.create().get(ContentUriHelper.getIdFromUri(uri))
instance!!.canBeEdited(settingsProvider)
} else {
true
}

return formEditingEnabled
}

override fun onSaveInstanceState(outState: Bundle) {
outState.putBoolean(FORM_FILLING_ALREADY_STARTED, formFillingAlreadyStarted)
super.onSaveInstanceState(outState)
Expand All @@ -187,17 +168,19 @@ class FormUriActivity : LocalizedActivity() {
}

private class FormUriViewModel(
private val uri: Uri?,
private val intent: Intent,
private val scheduler: Scheduler,
private val projectsRepository: ProjectsRepository,
private val projectsDataService: ProjectsDataService,
private val contentResolver: ContentResolver,
private val formsRepositoryProvider: FormsRepositoryProvider,
private val instancesRepositoryProvider: InstancesRepositoryProvider,
private val settingsProvider: SettingsProvider,
private val savepointsRepositoryProvider: SavepointsRepositoryProvider,
private val changeLockProvider: ChangeLockProvider,
private val resources: Resources
) : ViewModel() {
private val uri: Uri? = intent.data

private val _formInspectionResult = MutableLiveData<FormInspectionResult>()
val formInspectionResult: LiveData<FormInspectionResult> = _formInspectionResult
Expand All @@ -210,6 +193,7 @@ private class FormUriViewModel(
?: assertValidUri()
?: assertFormExists()
?: assertFormNotEncrypted()
?: assertNonEditableFormsAreStartedWithCorrectMode()
?: assertDoesNotUseEntitiesOrFormsUpdateNotInProgress()
if (error != null) {
FormInspectionResult.Error(error)
Expand Down Expand Up @@ -325,10 +309,24 @@ private class FormUriViewModel(
}
}

private fun assertNonEditableFormsAreStartedWithCorrectMode(): String? {
if (!canFormBeEdited()) {
intent.putExtra(
ApplicationConstants.BundleKeys.FORM_MODE,
ApplicationConstants.FormModes.VIEW_SENT
)
}
return null
}

private fun assertDoesNotUseEntitiesOrFormsUpdateNotInProgress(): String? {
val uriMimeType = contentResolver.getType(uri!!)
val projectId = projectsDataService.getCurrentProject().uuid

if (intent.extras?.getString(ApplicationConstants.BundleKeys.FORM_MODE) == ApplicationConstants.FormModes.VIEW_SENT) {
return null
}

val usesEntities = if (uriMimeType == FormsContract.CONTENT_ITEM_TYPE) {
val form = formsRepositoryProvider.create().get(ContentUriHelper.getIdFromUri(uri))!!
form.usesEntities()
Expand Down Expand Up @@ -377,6 +375,19 @@ private class FormUriViewModel(
}
)
}

private fun canFormBeEdited(): Boolean {
val uriMimeType = contentResolver.getType(uri!!)

val formEditingEnabled = if (uriMimeType == InstancesContract.CONTENT_ITEM_TYPE) {
val instance = instancesRepositoryProvider.create().get(ContentUriHelper.getIdFromUri(uri))
instance!!.canBeEdited(settingsProvider)
} else {
true
}

return formEditingEnabled
}
}

private sealed class FormInspectionResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,67 @@ class FormUriActivityTest {
)
}

@Test
fun `When attempting to view a non-editable form that uses entities and the forms database is locked then start form for view only`() {
val project = Project.Saved("123", "First project", "A", "#cccccc")
projectsRepository.save(project)
whenever(projectsDataService.getCurrentProject()).thenReturn(project)

formsRepository.save(
FormUtils.buildForm(
"1",
"1",
TempFiles.createTempDir().absolutePath,
usesEntities = true
).build()
)

val instance = instancesRepository.save(
Instance.Builder()
.formId("1")
.formVersion("1")
.instanceFilePath(TempFiles.createTempFile(TempFiles.createTempDir()).absolutePath)
.status(Instance.STATUS_COMPLETE)
.build()
)

changeLock.lock()
launcherRule.launchForResult<FormUriActivity>(getSavedIntent(project.uuid, instance.dbId))
fakeScheduler.flush()

assertStartSavedFormIntent(project.uuid, instance.dbId, false)
}

@Test
fun `When attempting to view a non-editable form that uses entities then do not lock the forms database`() {
val project = Project.Saved("123", "First project", "A", "#cccccc")
projectsRepository.save(project)
whenever(projectsDataService.getCurrentProject()).thenReturn(project)

formsRepository.save(
FormUtils.buildForm(
"1",
"1",
TempFiles.createTempDir().absolutePath,
usesEntities = true
).build()
)

val instance = instancesRepository.save(
Instance.Builder()
.formId("1")
.formVersion("1")
.instanceFilePath(TempFiles.createTempFile(TempFiles.createTempDir()).absolutePath)
.status(Instance.STATUS_COMPLETE)
.build()
)

launcherRule.launchForResult<FormUriActivity>(getSavedIntent(project.uuid, instance.dbId))
fakeScheduler.flush()

assertThat(changeLock.tryLock(), equalTo(true))
}

private fun getBlankFormIntent(projectId: String?, dbId: Long) =
Intent(context, FormUriActivity::class.java).apply {
data = if (projectId == null) {
Expand Down

0 comments on commit 1a10357

Please sign in to comment.