sync: tell the user which address their server got wrong
Two gaps left by fc7e520, both found in review.
The claimed path was kept when the claimed host was replaced, though
both come from the generator we had just decided not to trust. A
subdirectory install behind a proxy reports an empty webroot from inside
the container, so /nextcloud was dropped and discovery ran against the
wrong base -- the same dead end, one level down. The origin is now
rebuilt entirely from the poll endpoint, whose own prefix is whatever
precedes index.php/login/v2/poll.
And the mismatch rode out of poll() with nowhere to go. It is carried on
the state rather than the step, because it is learned during the browser
step while the setting it blames is what the user has to go and fix
afterwards -- so it has to outlive the step that discovered it.
This commit is contained in:
@@ -162,6 +162,19 @@ internal fun AddAccountScreen(
|
||||
is AddAccountStep.ChooseLists -> ListsStep(step, viewModel)
|
||||
AddAccountStep.Done -> Unit
|
||||
}
|
||||
|
||||
// Learned during the browser step and shown from there on, whichever
|
||||
// step follows: the address it blames is one the user has to go and
|
||||
// correct on the server, and it is just as true once the lists load.
|
||||
state.originMismatch?.let { mismatch ->
|
||||
QuirkNote(
|
||||
text = stringResource(
|
||||
R.string.add_account_origin_mismatch,
|
||||
mismatch.actual,
|
||||
mismatch.expected,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,15 @@ data class AddAccountUiState(
|
||||
* login flow to a different host than the one typed.
|
||||
*/
|
||||
val quirk: ServerQuirk? = null,
|
||||
/**
|
||||
* The login flow named an origin we could not have reached, and we used the
|
||||
* one that answered instead.
|
||||
*
|
||||
* Sticky, unlike the per-step note: it is learned during the browser step
|
||||
* but the setting it blames is what the user has to go and fix, so it has to
|
||||
* survive into the steps after it.
|
||||
*/
|
||||
val originMismatch: NextcloudLoginFlow.HostMismatch? = null,
|
||||
/** Set when the flow cannot continue at all; the UI offers only "start over". */
|
||||
val fatal: String? = null,
|
||||
/** Non-null once the browser flow has a URL to open. */
|
||||
@@ -218,6 +227,12 @@ class AddAccountViewModel @Inject constructor(
|
||||
username = result.credentials.loginName
|
||||
appPassword = result.credentials.appPassword
|
||||
serverRoot = result.credentials.server
|
||||
// The server contradicted itself about where it lives.
|
||||
// We recovered, but the setting behind it is the user's
|
||||
// to fix, so say so rather than silently coercing.
|
||||
result.hostMismatch?.let { mismatch ->
|
||||
_state.update { it.copy(originMismatch = mismatch) }
|
||||
}
|
||||
working("Reading your task lists")
|
||||
val outcome = gateway.discover(
|
||||
// The server the credentials were *issued by*, not the
|
||||
|
||||
@@ -355,6 +355,7 @@
|
||||
<string name="add_account_browser_reopen">Open the browser again</string>
|
||||
<string name="add_account_browser_use_password">Use a password instead</string>
|
||||
<string name="add_account_browser_host_mismatch">The server sent us to %1$s, but you typed %2$s. That usually means its overwrite.cli.url setting is wrong.</string>
|
||||
<string name="add_account_origin_mismatch">The server reported its address as %1$s, which this device cannot reach, so %2$s was used instead. Its overwrite.cli.url or trusted_proxies setting is probably wrong.</string>
|
||||
|
||||
<string name="add_account_lists_title">Which lists should sync?</string>
|
||||
<string name="add_account_lists_read_only">Read-only</string>
|
||||
|
||||
@@ -136,6 +136,37 @@ class AddAccountViewModelTest {
|
||||
.isEqualTo("https://dav.example.com/")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an origin the server got wrong is surfaced and stays visible`() =
|
||||
runTest(dispatcher) {
|
||||
gateway.discoveryOutcomes += CalDavDiscovery.Outcome.NeedsAuthentication(
|
||||
listOf("cloud.example.com"),
|
||||
)
|
||||
gateway.loginFlow = flow()
|
||||
gateway.pollResults += NextcloudLoginFlow.PollResult.Approved(
|
||||
credentials = NextcloudLoginFlow.Credentials(
|
||||
server = "https://cloud.example.com/".toHttpUrl(),
|
||||
loginName = "me",
|
||||
appPassword = "app-pw",
|
||||
),
|
||||
hostMismatch = NextcloudLoginFlow.HostMismatch(
|
||||
expected = "cloud.example.com",
|
||||
actual = "nextcloud",
|
||||
),
|
||||
)
|
||||
gateway.discoveryOutcomes += found(collection("Tasks"))
|
||||
|
||||
val vm = viewModel()
|
||||
vm.onServerInputChanged("https://cloud.example.com/")
|
||||
vm.onServerSubmitted()
|
||||
advanceUntilIdle()
|
||||
|
||||
// Sticky: it is learned mid-flow, but the setting it blames is
|
||||
// what the user has to go and fix afterwards.
|
||||
assertThat(vm.state.value.step).isInstanceOf(AddAccountStep.ChooseLists::class.java)
|
||||
assertThat(vm.state.value.originMismatch?.actual).isEqualTo("nextcloud")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a discovery failure after approval reports what actually failed`() =
|
||||
runTest(dispatcher) {
|
||||
|
||||
Reference in New Issue
Block a user