mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-01-31 15:28:20 +01:00
Fix login when an error occurs (#187)
This commit is contained in:
parent
7686228e01
commit
834ef7c297
@ -39,7 +39,7 @@ class StudentLocalTest {
|
||||
@Test
|
||||
fun saveAndReadTest() {
|
||||
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true))
|
||||
.blockingAwait()
|
||||
.blockingGet()
|
||||
assert(studentLocal.isStudentSaved)
|
||||
|
||||
val student = studentLocal.getCurrentStudent().blockingGet()
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
|
||||
import androidx.room.TypeConverters
|
||||
import io.github.wulkanowy.data.db.dao.AttendanceDao
|
||||
import io.github.wulkanowy.data.db.dao.ExamDao
|
||||
@ -47,6 +48,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
companion object {
|
||||
fun newInstance(context: Context): AppDatabase {
|
||||
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
|
||||
.setJournalMode(TRUNCATE)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Attendance
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface AttendanceDao {
|
||||
|
||||
|
@ -7,7 +7,9 @@ import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Exam
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface ExamDao {
|
||||
|
||||
|
@ -7,7 +7,9 @@ import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.github.wulkanowy.data.db.entities.Grade
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface GradeDao {
|
||||
|
||||
|
@ -6,7 +6,9 @@ import androidx.room.Insert
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.GradeSummary
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface GradeSummaryDao {
|
||||
|
||||
|
@ -7,7 +7,9 @@ import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Homework
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface HomeworkDao {
|
||||
|
||||
|
@ -7,7 +7,9 @@ import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.github.wulkanowy.data.db.entities.Note
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface NoteDao {
|
||||
|
||||
|
@ -6,19 +6,21 @@ import androidx.room.OnConflictStrategy.IGNORE
|
||||
import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface SemesterDao {
|
||||
|
||||
@Insert(onConflict = IGNORE)
|
||||
fun insertAll(semester: List<Semester>)
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId AND diary_id = :diaryId")
|
||||
fun update(semesterId: Int, diaryId: Int)
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId")
|
||||
fun load(studentId: Int): Maybe<List<Semester>>
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId AND diary_id = :diaryId")
|
||||
fun updateCurrent(semesterId: Int, diaryId: Int)
|
||||
|
||||
@Query("UPDATE Semesters SET is_current = 0 WHERE student_id = :studentId")
|
||||
fun resetCurrent(studentId: Int)
|
||||
}
|
||||
|
@ -5,18 +5,16 @@ import androidx.room.Delete
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.FAIL
|
||||
import androidx.room.Query
|
||||
import androidx.room.Update
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.reactivex.Maybe
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface StudentDao {
|
||||
|
||||
@Insert(onConflict = FAIL)
|
||||
fun insert(student: Student)
|
||||
|
||||
@Update
|
||||
fun update(student: Student)
|
||||
fun insert(student: Student): Long
|
||||
|
||||
@Delete
|
||||
fun delete(student: Student)
|
||||
@ -27,6 +25,9 @@ interface StudentDao {
|
||||
@Query("SELECT * FROM Students")
|
||||
fun loadAll(): Maybe<List<Student>>
|
||||
|
||||
@Query("UPDATE Students SET is_current = 1 WHERE student_id = :studentId")
|
||||
fun updateCurrent(studentId: Int)
|
||||
|
||||
@Query("UPDATE Students SET is_current = 0")
|
||||
fun resetCurrent()
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ import androidx.room.Query
|
||||
import io.github.wulkanowy.data.db.entities.Timetable
|
||||
import io.reactivex.Maybe
|
||||
import org.threeten.bp.LocalDate
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Dao
|
||||
interface TimetableDao {
|
||||
|
||||
|
@ -44,7 +44,7 @@ class StudentRepository @Inject constructor(
|
||||
return local.getCurrentStudent().toSingle()
|
||||
}
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
fun saveStudent(student: Student): Single<Long> {
|
||||
return local.saveStudent(student)
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ class StudentRepository @Inject constructor(
|
||||
return local.setCurrentStudent(student)
|
||||
}
|
||||
|
||||
fun logoutCurrentStudent(): Completable {
|
||||
return local.logoutCurrentStudent()
|
||||
fun logoutStudent(student: Student): Completable {
|
||||
return local.logoutStudent(student)
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ class SemesterLocal @Inject constructor(private val semesterDb: SemesterDao) {
|
||||
fun setCurrentSemester(semester: Semester) {
|
||||
semesterDb.run {
|
||||
resetCurrent(semester.studentId)
|
||||
update(semester.semesterId, semester.diaryId)
|
||||
updateCurrent(semester.semesterId, semester.diaryId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import io.github.wulkanowy.utils.security.decrypt
|
||||
import io.github.wulkanowy.utils.security.encrypt
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Single
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@ -25,36 +26,32 @@ class StudentLocal @Inject constructor(
|
||||
val isStudentSaved
|
||||
get() = sharedPref.getBoolean(STUDENT_SAVED_KEY, false)
|
||||
|
||||
fun saveStudent(student: Student): Completable {
|
||||
return Completable.fromCallable {
|
||||
studentDb.run {
|
||||
resetCurrent()
|
||||
studentDb.insert(student.copy(password = encrypt(student.password, context)))
|
||||
}
|
||||
}.doOnComplete { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
|
||||
}
|
||||
|
||||
fun getCurrentStudent(): Maybe<Student> {
|
||||
return studentDb.loadCurrent().map { it.apply { password = decrypt(password) } }
|
||||
fun saveStudent(student: Student): Single<Long> {
|
||||
return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) }
|
||||
.doOnSuccess { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
|
||||
}
|
||||
|
||||
fun getStudents(): Maybe<List<Student>> {
|
||||
return studentDb.loadAll()
|
||||
}
|
||||
|
||||
fun getCurrentStudent(): Maybe<Student> {
|
||||
return studentDb.loadCurrent().map { it.apply { password = decrypt(password) } }
|
||||
}
|
||||
|
||||
fun setCurrentStudent(student: Student): Completable {
|
||||
return Completable.fromCallable {
|
||||
studentDb.run {
|
||||
resetCurrent()
|
||||
update(student.apply { isCurrent = true })
|
||||
updateCurrent(student.studentId)
|
||||
}
|
||||
}.doOnComplete { sharedPref.putBoolean(STUDENT_SAVED_KEY, true) }
|
||||
}
|
||||
|
||||
fun logoutCurrentStudent(): Completable {
|
||||
return studentDb.loadCurrent().doOnSuccess {
|
||||
studentDb.delete(it)
|
||||
sharedPref.putBoolean(STUDENT_SAVED_KEY, false)
|
||||
}.ignoreElement()
|
||||
fun logoutStudent(student: Student): Completable {
|
||||
return Completable.fromCallable {
|
||||
studentDb.delete(student)
|
||||
if (student.isCurrent) sharedPref.putBoolean(STUDENT_SAVED_KEY, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package io.github.wulkanowy.ui.modules.account
|
||||
|
||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -77,6 +79,13 @@ class AccountDialog : DaggerAppCompatDialogFragment(), AccountView {
|
||||
}
|
||||
}
|
||||
|
||||
override fun openClearLoginView() {
|
||||
activity?.also {
|
||||
startActivity(LoginActivity.getStartIntent(it)
|
||||
.apply { addFlags(FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
}
|
||||
|
||||
override fun showConfirmDialog() {
|
||||
context?.let {
|
||||
AlertDialog.Builder(it)
|
||||
|
@ -29,7 +29,8 @@ class AccountPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
fun onLogoutConfirm() {
|
||||
disposable.add(studentRepository.logoutCurrentStudent()
|
||||
disposable.add(studentRepository.getCurrentStudent()
|
||||
.flatMapCompletable { studentRepository.logoutStudent(it) }
|
||||
.andThen(studentRepository.getSavedStudents())
|
||||
.flatMap {
|
||||
if (it.isNotEmpty()) studentRepository.switchStudent(it[0]).toSingle { it }
|
||||
@ -40,7 +41,7 @@ class AccountPresenter @Inject constructor(
|
||||
.doFinally { view?.dismissView() }
|
||||
.subscribe({
|
||||
view?.apply {
|
||||
if (it.isEmpty()) openLoginView()
|
||||
if (it.isEmpty()) openClearLoginView()
|
||||
else recreateView()
|
||||
}
|
||||
}, { errorHandler.proceed(it) }))
|
||||
|
@ -14,6 +14,8 @@ interface AccountView : BaseView {
|
||||
|
||||
fun openLoginView()
|
||||
|
||||
fun openClearLoginView()
|
||||
|
||||
fun recreateView()
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,11 @@ class LoginOptionsPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun registerStudent(student: Student) {
|
||||
disposable.add(studentRepository.saveStudent(student.apply { isCurrent = true })
|
||||
.andThen(semesterRepository.getSemesters(student, true))
|
||||
.onErrorResumeNext { studentRepository.logoutCurrentStudent().andThen(Single.error(it)) }
|
||||
disposable.add(studentRepository.saveStudent(student)
|
||||
.map { student.apply { id = it } }
|
||||
.flatMap { semesterRepository.getSemesters(student, true) }
|
||||
.onErrorResumeNext { studentRepository.logoutStudent(student).andThen(Single.error(it)) }
|
||||
.flatMapCompletable { studentRepository.switchStudent(student) }
|
||||
.subscribeOn(schedulers.backgroundThread)
|
||||
.observeOn(schedulers.mainThread)
|
||||
.doOnSubscribe {
|
||||
|
@ -9,9 +9,17 @@ import android.os.Build.VERSION_CODES.JELLY_BEAN_MR2
|
||||
import android.os.Build.VERSION_CODES.M
|
||||
import android.security.KeyPairGeneratorSpec
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties.*
|
||||
import android.security.keystore.KeyProperties.DIGEST_SHA256
|
||||
import android.security.keystore.KeyProperties.DIGEST_SHA512
|
||||
import android.security.keystore.KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1
|
||||
import android.security.keystore.KeyProperties.PURPOSE_DECRYPT
|
||||
import android.security.keystore.KeyProperties.PURPOSE_ENCRYPT
|
||||
import android.security.keystore.KeyProperties.SIGNATURE_PADDING_RSA_PKCS1
|
||||
import android.util.Base64
|
||||
import android.util.Base64.*
|
||||
import android.util.Base64.DEFAULT
|
||||
import android.util.Base64.decode
|
||||
import android.util.Base64.encode
|
||||
import android.util.Base64.encodeToString
|
||||
import timber.log.Timber
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
@ -20,7 +28,7 @@ import java.nio.charset.Charset
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.KeyStore
|
||||
import java.security.PrivateKey
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
import java.util.Calendar.YEAR
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.Cipher.DECRYPT_MODE
|
||||
@ -28,7 +36,6 @@ import javax.crypto.Cipher.ENCRYPT_MODE
|
||||
import javax.crypto.CipherInputStream
|
||||
import javax.crypto.CipherOutputStream
|
||||
import javax.security.auth.x500.X500Principal
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
private const val KEY_ALIAS = "USER_PASSWORD"
|
||||
|
||||
@ -80,7 +87,6 @@ fun encrypt(plainText: String, context: Context): String {
|
||||
Timber.e(exception, "An error occurred while encrypting text")
|
||||
String(encode(plainText.toByteArray(KEY_CHARSET), DEFAULT), KEY_CHARSET)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun decrypt(cipherText: String): String {
|
||||
|
@ -68,8 +68,9 @@ class LoginOptionsPresenterTest {
|
||||
|
||||
@Test
|
||||
fun onSelectedStudentTest() {
|
||||
doReturn(Completable.complete()).`when`(studentRepository).saveStudent(testStudent)
|
||||
doReturn(Single.just(1L)).`when`(studentRepository).saveStudent(testStudent)
|
||||
doReturn(Single.just(emptyList<Semester>())).`when`(semesterRepository).getSemesters(testStudent, true)
|
||||
doReturn(Completable.complete()).`when`(studentRepository).switchStudent(testStudent)
|
||||
presenter.onItemSelected(LoginOptionsItem(testStudent))
|
||||
verify(loginOptionsView).showContent(false)
|
||||
verify(loginOptionsView).showProgress(true)
|
||||
@ -78,9 +79,9 @@ class LoginOptionsPresenterTest {
|
||||
|
||||
@Test
|
||||
fun onSelectedStudentErrorTest() {
|
||||
doReturn(Completable.error(testException)).`when`(studentRepository).saveStudent(testStudent)
|
||||
doReturn(Single.error<Student>(testException)).`when`(studentRepository).saveStudent(testStudent)
|
||||
doReturn(Single.just(emptyList<Semester>())).`when`(semesterRepository).getSemesters(testStudent, true)
|
||||
doReturn(Completable.complete()).`when`(studentRepository).logoutCurrentStudent()
|
||||
doReturn(Completable.complete()).`when`(studentRepository).logoutStudent(testStudent)
|
||||
presenter.onItemSelected(LoginOptionsItem(testStudent))
|
||||
verify(loginOptionsView).showContent(false)
|
||||
verify(loginOptionsView).showProgress(true)
|
||||
|
Loading…
x
Reference in New Issue
Block a user