Skip to content

Commit

Permalink
Merge pull request #93 from Tiqr/Edured-100_show_error_message_on_sec…
Browse files Browse the repository at this point in the history
…urity

Edured 100 show error message on security
Added missing error message handling for security screen.
Not automatically triggering the authentication, but informing the user they must grant access.
  • Loading branch information
IuliaSTANA authored May 26, 2023
2 parents a6272b3 + baa5eeb commit 4ddc998
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 102 deletions.
4 changes: 1 addition & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ val keystorePass = if (devKeystorePassFile.exists()) {

android {
compileSdk = libs.versions.android.sdk.compile.get().toInt()
buildToolsVersion = libs.versions.android.buildTools.get()

val gitTagCount = "git tag --list".runCommand().split('\n').size
val gitTag = "git describe --tags --dirty".runCommand()
Expand Down Expand Up @@ -93,7 +92,6 @@ android {
}

buildFeatures {
dataBinding = true
compose = true
}

Expand All @@ -118,7 +116,7 @@ android {
abortOnError = false
}
composeOptions {
kotlinCompilerExtensionVersion = "1.4.5"
kotlinCompilerExtensionVersion = "1.4.6"
}
packagingOptions {
resources {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ private fun ConfirmCodeContent(
onValueChange: (String) -> Unit = {},
) {
val keyboardController = LocalSoftwareKeyboardController.current

if (uiState.errorData != null) {
val context = LocalContext.current
AlertDialogWithSingleButton(
Expand Down Expand Up @@ -138,6 +137,7 @@ private fun ConfirmCodeContent(
}
PrimaryButton(
text = stringResource(R.string.confirm_sms_code_button),
enabled = uiState.input.isNotEmpty(),
onClick = onClick,
modifier = Modifier
.fillMaxWidth()
Expand Down
111 changes: 57 additions & 54 deletions app/src/main/kotlin/nl/eduid/screens/security/SecurityScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import nl.eduid.R
import nl.eduid.ui.AlertDialogWithSingleButton
import nl.eduid.ui.EduIdTopAppBar
import nl.eduid.ui.InfoField
import nl.eduid.ui.theme.ButtonGreen
Expand All @@ -36,12 +34,12 @@ fun SecurityScreen(
) = EduIdTopAppBar(
onBackClicked = goBack,
) {
val securityInfo by viewModel.securityInfo.observeAsState(SecurityScreenData())
SecurityScreenContent(
securityInfo = securityInfo,
securityInfo = viewModel.uiState,
onConfigurePasswordClicked = onConfigurePasswordClick,
onEditEmailClicked = onEditEmailClicked,
on2FaClicked = on2FaClicked,
dismissError = viewModel::dismissError
)
}

Expand All @@ -51,70 +49,75 @@ fun SecurityScreenContent(
onConfigurePasswordClicked: () -> Unit = {},
onEditEmailClicked: () -> Unit = {},
on2FaClicked: () -> Unit = {},
dismissError:()->Unit = {}
) = Column(
verticalArrangement = Arrangement.Bottom,
modifier = Modifier
.verticalScroll(rememberScrollState())
modifier = Modifier.verticalScroll(rememberScrollState())
) {
Spacer(Modifier.height(36.dp))
if (securityInfo.errorData != null) {
val context = LocalContext.current
AlertDialogWithSingleButton(
title = securityInfo.errorData.title(context),
explanation = securityInfo.errorData.message(context),
buttonLabel = stringResource(R.string.button_ok),
onDismiss = dismissError
)
}

Text(
style = MaterialTheme.typography.titleLarge.copy(
textAlign = TextAlign.Start,
color = ButtonGreen
),
text = stringResource(R.string.security_title),
modifier = Modifier
.fillMaxWidth()
textAlign = TextAlign.Start, color = ButtonGreen
), text = stringResource(R.string.security_title), modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(12.dp))
Text(
style = MaterialTheme.typography.bodyLarge.copy(textAlign = TextAlign.Start),
text = stringResource(R.string.security_subtitle),
modifier = Modifier
.fillMaxWidth()
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(36.dp))
if (securityInfo.email.isBlank()) {
if (securityInfo.isLoading) {
Spacer(Modifier.height(24.dp))
CircularProgressIndicator(
modifier = Modifier
.height(80.dp)
.width(80.dp)
.align(alignment = Alignment.CenterHorizontally)
)
} else {
InfoField(
title = stringResource(R.string.security_2fa_key),
subtitle = stringResource(R.string.security_provided_by_eduid),
onClick = on2FaClicked,
endIcon = R.drawable.shield_tick_blue,
label = stringResource(R.string.security_sign_in_methods)
)
Spacer(Modifier.height(16.dp))
InfoField(
title = stringResource(R.string.security_send_a_magic_link_to),
subtitle = securityInfo.email,
onClick = onEditEmailClicked,
endIcon = R.drawable.edit_icon
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.height(16.dp))
InfoField(
title = if (securityInfo.hasPassword) {
stringResource(R.string.security_change_password)
} else {
stringResource(R.string.security_add_a_password)
},
subtitle = if (securityInfo.hasPassword) {
"****"
} else {
""
},
onClick = onConfigurePasswordClicked,
endIcon = R.drawable.edit_icon
)
Spacer(Modifier.height(16.dp))
}
InfoField(
title = stringResource(R.string.security_2fa_key),
subtitle = if (securityInfo.twoFAProvider != null) {
stringResource(
R.string.security_provided_by_eduid, securityInfo.twoFAProvider
)
} else {
stringResource(
R.string.security_provided_by_na,
)
},
onClick = on2FaClicked,
endIcon = R.drawable.shield_tick_blue,
label = stringResource(R.string.security_sign_in_methods)
)
Spacer(Modifier.height(16.dp))
InfoField(
title = stringResource(R.string.security_send_a_magic_link_to),
subtitle = securityInfo.email,
onClick = onEditEmailClicked,
endIcon = R.drawable.edit_icon
)
Spacer(Modifier.height(16.dp))
InfoField(
title = if (securityInfo.hasPassword) {
stringResource(R.string.security_change_password)
} else {
stringResource(R.string.security_add_a_password)
}, subtitle = if (securityInfo.hasPassword) {
"****"
} else {
""
}, onClick = onConfigurePasswordClicked, endIcon = R.drawable.edit_icon
)
Spacer(Modifier.height(16.dp))
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package nl.eduid.screens.security

import nl.eduid.ErrorData

data class SecurityScreenData(
val twoFactorEnabled: Boolean = false,
val isLoading: Boolean = false,
val errorData: ErrorData? = null,
val twoFAProvider: String? = null,
val email: String = "",
val hasPassword: Boolean = false,
)
66 changes: 48 additions & 18 deletions app/src/main/kotlin/nl/eduid/screens/security/SecurityViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,36 +1,66 @@
package nl.eduid.screens.security

import androidx.lifecycle.MutableLiveData
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import nl.eduid.di.model.UserDetails
import nl.eduid.screens.personalinfo.PersonalInfoRepository
import nl.eduid.ErrorData
import nl.eduid.R
import nl.eduid.di.assist.DataAssistant
import nl.eduid.di.model.UnauthorizedException
import org.tiqr.data.repository.IdentityRepository
import javax.inject.Inject

@HiltViewModel
class SecurityViewModel @Inject constructor(private val repository: PersonalInfoRepository) :
ViewModel() {
val securityInfo = MutableLiveData<SecurityScreenData>()
class SecurityViewModel @Inject constructor(
private val assistant: DataAssistant,
private val identity: IdentityRepository,
) : ViewModel() {
var uiState: SecurityScreenData by mutableStateOf(SecurityScreenData())
private set

init {
viewModelScope.launch {
val userDetails = repository.getUserDetails()
if (userDetails != null) {
val uiData = convertToUiData(userDetails)
securityInfo.postValue(uiData)
uiState = uiState.copy(isLoading = true, errorData = null)
try {
val userDetails = assistant.getErringUserDetails()
uiState = if (userDetails != null) {
val identity = identity.identity(userDetails.id).firstOrNull()
val provider = if (identity != null) {
identity.identityProvider.displayName
} else {
null
}
uiState.copy(
isLoading = false, errorData = null, email = userDetails.email,
twoFAProvider = provider,
hasPassword = userDetails.hasPasswordSet(),
)
} else {
uiState.copy(
isLoading = false, errorData = ErrorData(
titleId = R.string.err_title_load_fail,
messageId = R.string.err_msg_data_history_fail
)
)
}

} catch (e: UnauthorizedException) {
uiState = uiState.copy(
isLoading = false, errorData = ErrorData(
titleId = R.string.err_title_load_fail,
messageId = R.string.err_msg_unauthorized_request_fail
)
)
}
}
}

private fun convertToUiData(userDetails: UserDetails): SecurityScreenData {
return userDetails.eduIdPerServiceProvider.values.map {
SecurityScreenData(
twoFactorEnabled = false,
email = userDetails.email,
hasPassword = userDetails.hasPasswordSet(),
)
}.first()
fun dismissError() {
uiState = uiState.copy(errorData = null)
}
}
3 changes: 2 additions & 1 deletion app/src/main/res/values-nl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@
<string name="button_confirm">Bevestigen</string>
<string name="security_sign_in_methods">Aanmeldmethoden</string>
<string name="security_2fa_key">2FA sleutel</string>
<string name="security_provided_by_eduid">Geleverd door</string>
<string name="security_provided_by_eduid">Geleverd door %s</string>
<string name="security_provided_by_na">Geleverd door n.v.t.</string>
<string name="security_send_a_magic_link_to">Stuur een magiche link naar</string>
<string name="security_add_a_password">Wachtwoord toevoegen</string>
<string name="security_change_password">Wijzig uw wachtwoord</string>
Expand Down
3 changes: 2 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@
<string name="button_confirm">Confirm</string>
<string name="security_sign_in_methods">Sign-in methods</string>
<string name="security_2fa_key">2FA key</string>
<string name="security_provided_by_eduid">Provided by eduID</string>
<string name="security_provided_by_eduid">Provided by %s</string>
<string name="security_provided_by_na">Provided by n/a</string>
<string name="security_send_a_magic_link_to">Send a magic link to</string>
<string name="security_add_a_password">Add a password</string>
<string name="security_change_password">Change your password</string>
Expand Down
Loading

0 comments on commit 4ddc998

Please sign in to comment.