diff --git a/oauth/src/OAuthClient.kt b/oauth/src/OAuthClient.kt index 424a3b9e..d82e1291 100644 --- a/oauth/src/OAuthClient.kt +++ b/oauth/src/OAuthClient.kt @@ -67,7 +67,7 @@ class GoogleOAuthClient(httpClient: HttpClient): OAuthClient( val res = fetchProfileResponse(token) val email = Email(res.getString("email")) return UserProfile(provider, res.getString("id"), email, - res.getOrNull("givenName") ?: email.value.substringBefore("@").capitalize(), res.getOrNull("familyName") ?: "", + res.getOrNull("givenName") ?: email.extractName(), res.getOrNull("familyName") ?: "", res.getOrNull("picture")?.let { URI(it) }, res.getLocale()) } } @@ -82,8 +82,8 @@ class MicrosoftOAuthClient(httpClient: HttpClient): OAuthClient( ) { override suspend fun profile(token: OAuthTokenResponse, exchange: HttpExchange): UserProfile { val res = fetchProfileResponse(token) - val email = res.getOrNull("mail") ?: res.getOrNull("userPrincipalName") ?: error("Cannot obtain user's email") - return UserProfile(provider, res.getString("id"), Email(email), res.getOrNull("givenName") ?: email.substringBefore("@").capitalize(), res.getOrNull("surname") ?: "", + val email = Email(res.getOrNull("mail") ?: res.getOrNull("userPrincipalName") ?: error("Cannot obtain user's email")) + return UserProfile(provider, res.getString("id"), email, res.getOrNull("givenName") ?: email.extractName(), res.getOrNull("surname") ?: "", locale = res.getLocale("preferredLanguage")) } } @@ -102,7 +102,7 @@ class FacebookOAuthClient(httpClient: HttpClient): OAuthClient( val avatarExists = avatarData?.getOrNull("is_silhouette") != true val email = Email(res.getString("email")) return UserProfile(provider, res.getString("id"), - email, res.getOrNull("firstName") ?: email.value.substringBefore("@").capitalize(), res.getOrNull("lastName") ?: "", + email, res.getOrNull("firstName") ?: email.extractName(), res.getOrNull("lastName") ?: "", avatarData?.getOrNull("url")?.takeIf { avatarExists }?.let { URI(it) }, res.getLocale()) } @@ -119,7 +119,7 @@ class AppleOAuthClient(httpClient: HttpClient): OAuthClient( override suspend fun profile(token: OAuthTokenResponse, exchange: HttpExchange): UserProfile { val email = token.idToken!!.payload.email!! val user = exchange.bodyParams["user"]?.let { http.json.parse(it.toString()) } - return UserProfile(provider, token.idToken.payload.subject, email, user?.name?.firstName ?: email.value.substringBefore("@").capitalize(), user?.name?.lastName ?: "") + return UserProfile(provider, token.idToken.payload.subject, email, user?.name?.firstName ?: email.extractName(), user?.name?.lastName ?: "") } data class AppleUserProfile(val name: AppleUserName, val email: Email) @@ -128,3 +128,10 @@ class AppleOAuthClient(httpClient: HttpClient): OAuthClient( data class OAuthTokenResponse(val accessToken: String, val expiresIn: Int, val scope: String? = null, val tokenType: String? = null, val idToken: JWT? = null, val refreshToken: String? = null) data class UserProfile(val provider: String, override val id: String, override val email: Email, override val firstName: String, override val lastName: String, val avatarUrl: URI? = null, val locale: Locale? = null): OAuthUser + +internal fun Email.extractName(): String { + val localPart = value.substringBefore("@") + return localPart.replaceFirstChar { + if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() + } +} diff --git a/oauth/test/OAuthClientKtTest.kt b/oauth/test/OAuthClientKtTest.kt new file mode 100644 index 00000000..6c854b38 --- /dev/null +++ b/oauth/test/OAuthClientKtTest.kt @@ -0,0 +1,32 @@ +import ch.tutteli.atrium.api.fluent.en_GB.toEqual +import ch.tutteli.atrium.api.verbs.expect +import klite.Email +import klite.oauth.extractName +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +class OAuthClientKtTest { + + @ParameterizedTest + @MethodSource("emailTestCases") + fun `use capitalized email local part as name`(emailAddress: String, expectedName: String) { + val email = Email(emailAddress) + expect(email.extractName()).toEqual(expectedName) + } + + companion object { + @JvmStatic + fun emailTestCases(): Stream = + Stream.of( + Arguments.of("foo@bar.com", "Foo"), + Arguments.of("fOo@bar.com", "Foo"), + Arguments.of("john.doe@example.com", "John.doe"), + Arguments.of("alice@example.org", "Alice"), + Arguments.of("bob-smith@mail.co.uk", "Bob-smith"), + Arguments.of("1234@numeric.com", "1234"), + Arguments.of("UPPERCASE@example.com", "Uppercase") + ) + } +}