1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-20 00:39:08 -05:00

Refactor multi logs support (#165)

This commit is contained in:
Mikołaj Pich 2018-10-14 15:42:36 +02:00 committed by Rafał Borcz
parent 5cd8ed88c0
commit bb69d1b643
19 changed files with 433 additions and 122 deletions

View File

@ -72,7 +72,7 @@ ext.supportVersion = "28.0.0"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation('com.github.wulkanowy:api:f54b673') { exclude module: "threetenbp" }
implementation('com.github.wulkanowy:api:a5667f8000') { exclude module: "threetenbp" }
implementation "com.android.support:support-v4:$supportVersion"
implementation "com.android.support:appcompat-v7:$supportVersion"
implementation "com.android.support:design:$supportVersion"

View File

@ -38,7 +38,7 @@ class SessionLocalTest {
@Test
fun saveAndReadTest() {
sessionLocal.saveStudent(Student(email = "test", password = "test123", schoolId = "23")).blockingAwait()
sessionLocal.saveStudent(Student(email = "test", password = "test123", schoolId = "23", endpoint = "fakelog.cf", loginType = "AUTO")).blockingAwait()
assert(sharedHelper.getLong(SessionLocal.LAST_USER_KEY, 0) == 1L)
assert(sessionLocal.isSessionSaved)

View File

@ -2,7 +2,7 @@ package io.github.wulkanowy.data
import android.content.res.Resources
import io.github.wulkanowy.R
import io.github.wulkanowy.api.auth.NotLoggedInException
import io.github.wulkanowy.api.login.NotLoggedInException
import timber.log.Timber
import java.io.IOException
import java.net.SocketTimeoutException

View File

@ -12,6 +12,10 @@ data class Student(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
var endpoint: String,
var loginType: String,
var email: String,
var password: String,

View File

@ -24,10 +24,10 @@ class SessionRepository @Inject constructor(
lateinit var cachedStudents: Single<List<Student>>
private set
fun getConnectedStudents(email: String, password: String, symbol: String): Single<List<Student>> {
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap { isConnected ->
if (isConnected) remote.getConnectedStudents(email, password, symbol)
if (isConnected) remote.getConnectedStudents(email, password, symbol, endpoint)
else Single.error<List<Student>>(UnknownHostException("No internet connection"))
}.doOnSuccess { cachedStudents = Single.just(it) }
return cachedStudents

View File

@ -4,24 +4,29 @@ import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Single
import java.net.URL
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SessionRemote @Inject constructor(private val api: Api) {
fun getConnectedStudents(email: String, password: String, symbol: String): Single<List<Student>> {
return Single.just(initApi(Student(email = email, password = password, symbol = symbol)))
fun getConnectedStudents(email: String, password: String, symbol: String, endpoint: String): Single<List<Student>> {
return Single.just(initApi(Student(email = email, password = password, symbol = symbol, endpoint = endpoint, loginType = "AUTO")))
.flatMap { _ ->
api.getPupils().map { students ->
students.map {
Student(email = email,
Student(
email = email,
password = password,
symbol = it.symbol,
studentId = it.studentId,
studentName = it.studentName,
schoolId = it.schoolId,
schoolName = it.schoolName)
schoolName = it.schoolName,
endpoint = endpoint,
loginType = it.loginType.name
)
}
}
}
@ -31,12 +36,14 @@ class SessionRemote @Inject constructor(private val api: Api) {
return Single.just(initApi(student)).flatMap { _ ->
api.getSemesters().map { semesters ->
semesters.map {
Semester(studentId = student.studentId,
Semester(
studentId = student.studentId,
diaryId = it.diaryId,
diaryName = it.diaryName,
semesterId = it.semesterId.toString(),
semesterName = it.semesterNumber,
current = it.current)
current = it.current
)
}
}
@ -49,9 +56,11 @@ class SessionRemote @Inject constructor(private val api: Api) {
email = student.email
password = student.password
symbol = student.symbol
host = "vulcan.net.pl"
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
ssl = student.endpoint.startsWith("https")
schoolId = student.schoolId
studentId = student.studentId
loginType = Api.LoginType.valueOf(student.loginType)
notifyDataChanged()
}
}

View File

@ -1,7 +1,7 @@
package io.github.wulkanowy.ui.login
import android.content.res.Resources
import io.github.wulkanowy.api.auth.BadCredentialsException
import io.github.wulkanowy.api.login.BadCredentialsException
import io.github.wulkanowy.data.ErrorHandler
class LoginErrorHandler(resources: Resources) : ErrorHandler(resources) {

View File

@ -36,16 +36,24 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
override fun initInputs() {
loginSignButton.setOnClickListener {
presenter.attemptLogin(loginEmailEdit.text.toString(),
presenter.attemptLogin(
loginNicknameEdit.text.toString(),
loginPassEdit.text.toString(),
loginSymbolEdit.text.toString())
loginSymbolEdit.text.toString(),
resources.getStringArray(R.array.endpoints_values)[loginHostEdit.selectedItemPosition]
)
}
loginPassEdit.setOnEditorActionListener { _, id, _ -> onEditAction(id) }
loginHostEdit.run {
adapter = ArrayAdapter.createFromResource(context, R.array.endpoints_keys, android.R.layout.simple_spinner_item).apply {
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
}
}
loginSymbolEdit.run {
setAdapter(ArrayAdapter(context, android.R.layout.simple_list_item_1,
resources.getStringArray(R.array.symbols_values)))
setAdapter(ArrayAdapter(context, android.R.layout.simple_list_item_1, resources.getStringArray(R.array.symbols_values)))
setOnEditorActionListener { _, id, _ -> onEditAction(id) }
}
}
@ -69,20 +77,13 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
(activity as LoginSwitchListener?)?.switchFragment(1)
}
override fun setErrorEmailRequired() {
loginEmailEdit.run {
override fun setErrorNicknameRequired() {
loginNicknameEdit.run {
requestFocus()
error = getString(R.string.login_field_required)
}
}
override fun setErrorEmailInvalid() {
loginEmailEdit.run {
requestFocus()
error = getString(R.string.login_invalid_email)
}
}
override fun setErrorPassRequired(focus: Boolean) {
loginPassEdit.run {
if (focus) requestFocus()
@ -119,7 +120,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
}
override fun resetViewErrors() {
loginEmailEdit.error = null
loginNicknameEdit.error = null
loginPassEdit.error = null
}

View File

@ -19,9 +19,9 @@ class LoginFormPresenter @Inject constructor(
view.initInputs()
}
fun attemptLogin(email: String, password: String, symbol: String) {
fun attemptLogin(email: String, password: String, symbol: String, endpoint: String) {
if (!validateCredentials(email, password, symbol)) return
disposable.add(sessionRepository.getConnectedStudents(email, password, normalizeSymbol(symbol))
disposable.add(sessionRepository.getConnectedStudents(email, password, symbol, endpoint)
.observeOn(schedulers.mainThread())
.subscribeOn(schedulers.backgroundThread())
.doOnSubscribe {
@ -51,11 +51,11 @@ class LoginFormPresenter @Inject constructor(
}, { errorHandler.proceed(it) }))
}
private fun validateCredentials(email: String, password: String, symbol: String): Boolean {
private fun validateCredentials(login: String, password: String, symbol: String): Boolean {
var isCorrect = true
if (email.isEmpty()) {
view?.setErrorEmailRequired()
if (login.isEmpty()) {
view?.setErrorNicknameRequired()
isCorrect = false
}
@ -69,19 +69,10 @@ class LoginFormPresenter @Inject constructor(
isCorrect = false
}
if (!email.contains("[@]|[\\\\]{4}".toRegex()) && email.isNotEmpty()) {
view?.setErrorEmailInvalid()
isCorrect = false
}
if (password.length <= 4 && password.isNotEmpty()) {
if (password.length < 6 && password.isNotEmpty()) {
view?.setErrorPassInvalid(focus = isCorrect)
isCorrect = false
}
return isCorrect
}
private fun normalizeSymbol(symbol: String): String {
return if (symbol.isEmpty()) "Default" else symbol
}
}

View File

@ -6,14 +6,12 @@ interface LoginFormView : BaseView {
fun initInputs()
fun setErrorEmailRequired()
fun setErrorNicknameRequired()
fun setErrorPassRequired(focus: Boolean)
fun setErrorSymbolRequire()
fun setErrorEmailInvalid()
fun setErrorPassInvalid(focus: Boolean)
fun setErrorPassIncorrect()

View File

@ -66,10 +66,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:hint="@string/login_email_hint">
android:hint="@string/login_nickname_hint">
<android.support.design.widget.TextInputEditText
android:id="@+id/loginEmailEdit"
android:id="@+id/loginNicknameEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
@ -80,6 +80,7 @@
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:hint="@string/login_password_hint">
<android.support.design.widget.TextInputEditText
@ -93,6 +94,12 @@
app:fontFamily="sans-serif" />
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/loginHostEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/login_host_hint" />
</LinearLayout>
<android.support.design.widget.TextInputLayout

View File

@ -15,13 +15,13 @@
<!--Login form-->
<string name="login_header_default">Zaloguj się za pomocą konta ucznia lub rodzica</string>
<string name="login_header_symbol">Podaj symbol dziennika VULCAN</string>
<string name="login_email_hint">Email</string>
<string name="login_nickname_hint">Email lub nick</string>
<string name="login_password_hint">Hasło</string>
<string name="login_host_hint">Dziennik</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Zaloguj</string>
<string name="login_progress">Logowanie&#8230;</string>
<string name="login_sync">Synchronizacja</string>
<string name="login_invalid_email">Ten adres email nie jest poprawny</string>
<string name="login_invalid_password">To hasło jest za krótkie</string>
<string name="login_incorrect_password">To hasło jest niepoprawne</string>
<string name="login_incorrect_symbol">Nie znaleziono ucznia. Sprwadź symbol</string>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string-array name="endpoints_keys">
<item>Vulcan</item>
<item>Opolska eSzkoła</item>
<item>Gdańska Platforma Edukacyjna</item>
<item>EduNet Miasta Tarnowa</item>
<item>ResMan Rzeszów</item>
<item>Fakelog</item>
<item>Fakelog lokalnie</item>
</string-array>
<string-array name="endpoints_values">
<item>https://vulcan.net.pl</item>
<item>https://eszkola.opolskie.pl</item>
<item>https://edu.gdansk.pl</item>
<item>https://umt.tarnow.pl</item>
<item>https://resman.pl</item>
<item>https://fakelog.cf</item>
<item>http://fakelog.localhost:3000</item>
</string-array>
</resources>

File diff suppressed because it is too large Load Diff

View File

@ -15,13 +15,13 @@
<!--Login form-->
<string name="login_header_default">Sign in with the student or parent account</string>
<string name="login_header_symbol">Enter the VULCAN diary symbol</string>
<string name="login_email_hint">Email</string>
<string name="login_nickname_hint">Email or nick</string>
<string name="login_password_hint">Password</string>
<string name="login_host_hint">Log</string>
<string name="login_symbol_hint">Symbol</string>
<string name="login_sign_in">Sign in</string>
<string name="login_progress">Logging in&#8230;</string>
<string name="login_sync">Synchronization&#8230;</string>
<string name="login_invalid_email">This email address is invalid</string>
<string name="login_invalid_password">This password is too short</string>
<string name="login_incorrect_password">This password is incorrect</string>
<string name="login_incorrect_symbol">Student not found. Check the symbol</string>

View File

@ -22,10 +22,10 @@ class SessionRemoteTest {
@Test
fun testRemoteAll() {
doReturn(Single.just(listOf(Pupil("", "", "", "test", "", ""))))
doReturn(Single.just(listOf(Pupil("", "", "", "test", "", "", Api.LoginType.AUTO))))
.`when`(mockApi).getPupils()
val students = SessionRemote(mockApi).getConnectedStudents("", "", "").blockingGet()
val students = SessionRemote(mockApi).getConnectedStudents("", "", "", "http://fakelog.cf").blockingGet()
assertEquals(1, students.size)
assertEquals("test", students.first().studentName)
}

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.ui.login.form
import io.github.wulkanowy.TestSchedulers
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.SessionRepository
import io.github.wulkanowy.ui.login.LoginErrorHandler
@ -39,65 +40,51 @@ class LoginFormPresenterTest {
}
@Test
fun emptyEmailLoginTest() {
presenter.attemptLogin("", "test123", "test")
fun emptyNicknameLoginTest() {
presenter.attemptLogin("", "test123", "test", "https://fakelog.cf")
verify(loginFormView).setErrorEmailRequired()
verify(loginFormView).setErrorNicknameRequired()
verify(loginFormView, never()).setErrorPassRequired(false)
verify(loginFormView, never()).setErrorSymbolRequire()
verify(loginFormView, never()).setErrorEmailInvalid()
verify(loginFormView, never()).setErrorPassInvalid(false)
}
@Test
fun invalidEmailLoginTest() {
presenter.attemptLogin("test", "test123", "test")
verify(loginFormView, never()).setErrorEmailRequired()
verify(loginFormView, never()).setErrorPassRequired(false)
verify(loginFormView, never()).setErrorSymbolRequire()
verify(loginFormView).setErrorEmailInvalid()
verify(loginFormView, never()).setErrorPassInvalid(false)
}
@Test
fun emptyPassLoginTest() {
presenter.attemptLogin("@", "", "test")
presenter.attemptLogin("@", "", "test", "https://fakelog.cf")
verify(loginFormView, never()).setErrorEmailRequired()
verify(loginFormView, never()).setErrorNicknameRequired()
verify(loginFormView).setErrorPassRequired(true)
verify(loginFormView, never()).setErrorSymbolRequire()
verify(loginFormView, never()).setErrorEmailInvalid()
verify(loginFormView, never()).setErrorPassInvalid(false)
}
@Test
fun invalidPassLoginTest() {
presenter.attemptLogin("@", "123", "test")
presenter.attemptLogin("@", "123", "test", "https://fakelog.cf")
verify(loginFormView, never()).setErrorEmailRequired()
verify(loginFormView, never()).setErrorNicknameRequired()
verify(loginFormView, never()).setErrorPassRequired(true)
verify(loginFormView, never()).setErrorSymbolRequire()
verify(loginFormView, never()).setErrorEmailInvalid()
verify(loginFormView).setErrorPassInvalid(true)
}
@Test
fun emptySymbolLoginTest() {
doReturn(Single.just(emptyList<Student>()))
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString())
presenter.attemptLogin("@", "12345", "")
presenter.attemptLogin("@", "12345", "")
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString(), anyString())
presenter.attemptLogin("@", "123456", "", "https://fakelog.cf")
presenter.attemptLogin("@", "123456", "", "https://fakelog.cf")
verify(loginFormView).setErrorSymbolRequire()
}
@Test
fun loginTest() {
val studentTest = Student(email = "test@", password = "123")
val studentTest = Student(email = "test@", password = "123", endpoint = "https://fakelog.cf", loginType = "AUTO")
doReturn(Single.just(listOf(studentTest)))
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString())
presenter.attemptLogin("@", "12345", "test")
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString(), anyString())
presenter.attemptLogin("@", "123456", "test", "https://fakelog.cf")
verify(loginFormView).hideSoftKeyboard()
verify(loginFormView).showLoginProgress(true)
@ -109,8 +96,8 @@ class LoginFormPresenterTest {
@Test
fun loginEmptyTest() {
doReturn(Single.just(emptyList<Student>()))
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString())
presenter.attemptLogin("@", "12345", "test")
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString(), anyString())
presenter.attemptLogin("@", "123456", "test", "https://fakelog.cf")
verify(loginFormView).hideSoftKeyboard()
verify(loginFormView).showLoginProgress(true)
@ -122,9 +109,9 @@ class LoginFormPresenterTest {
@Test
fun loginEmptyTwiceTest() {
doReturn(Single.just(emptyList<Student>()))
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString())
presenter.attemptLogin("@", "12345", "")
presenter.attemptLogin("@", "12345", "test")
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString(), anyString())
presenter.attemptLogin("@", "123456", "", "https://fakelog.cf")
presenter.attemptLogin("@", "123456", "test", "https://fakelog.cf")
verify(loginFormView, times(2)).hideSoftKeyboard()
verify(loginFormView, times(2)).showLoginProgress(true)
@ -139,8 +126,8 @@ class LoginFormPresenterTest {
fun loginErrorTest() {
val testException = RuntimeException()
doReturn(Single.error<List<Student>>(testException))
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString())
presenter.attemptLogin("@", "12345", "test")
.`when`(repository).getConnectedStudents(anyString(), anyString(), anyString(), anyString())
presenter.attemptLogin("@", "123456", "test", "https://fakelog.cf")
verify(loginFormView).hideSoftKeyboard()
verify(loginFormView).showLoginProgress(true)

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.ui.login.options
import io.github.wulkanowy.TestSchedulers
import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.ErrorHandler
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.SessionRepository
@ -25,7 +26,7 @@ class LoginOptionsPresenterTest {
private lateinit var presenter: LoginOptionsPresenter
private val testStudent by lazy { Student(email = "test", password = "test123") }
private val testStudent by lazy { Student(email = "test", password = "test123", endpoint = "https://fakelog.cf", loginType = "AUTO") }
private val testException by lazy { RuntimeException("Problem") }

View File

@ -9,7 +9,7 @@ buildscript {
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.android.tools.build:gradle:3.2.0'
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "io.fabric.tools:gradle:1.26.0"
classpath "com.google.gms:oss-licenses:0.9.2"
classpath "com.github.triplet.gradle:play-publisher:1.2.2"