forked from github/wulkanowy-mirror
Add schools API integration (#2302)
This commit is contained in:
parent
0fa197d520
commit
95b4d53fac
@ -69,6 +69,7 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
signingConfig signingConfigs.release
|
||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
||||
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
|
||||
}
|
||||
debug {
|
||||
minifyEnabled false
|
||||
@ -78,6 +79,7 @@ android {
|
||||
versionNameSuffix "-dev"
|
||||
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
||||
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,6 +257,7 @@ dependencies {
|
||||
playImplementation 'com.google.android.play:core:1.10.3'
|
||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
playImplementation 'com.google.android.gms:play-services-ads:22.4.0'
|
||||
playImplementation "com.google.android.play:integrity:1.2.0"
|
||||
|
||||
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300'
|
||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301'
|
||||
|
@ -0,0 +1,11 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class IntegrityHelper @Inject constructor() {
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun getIntegrityToken(requestId: String): String? = null
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class IntegrityHelper @Inject constructor() {
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun getIntegrityToken(requestId: String): String? = null
|
||||
}
|
@ -14,6 +14,7 @@ import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import io.github.wulkanowy.data.api.AdminMessageService
|
||||
import io.github.wulkanowy.data.api.SchoolsService
|
||||
import io.github.wulkanowy.data.db.AppDatabase
|
||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
@ -82,19 +83,29 @@ internal class DataModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideRetrofit(
|
||||
fun provideAdminMessageService(
|
||||
okHttpClient: OkHttpClient,
|
||||
json: Json,
|
||||
appInfo: AppInfo
|
||||
): Retrofit = Retrofit.Builder()
|
||||
): AdminMessageService = Retrofit.Builder()
|
||||
.baseUrl(appInfo.messagesBaseUrl)
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||
.build()
|
||||
.create()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
fun provideAdminMessageService(retrofit: Retrofit): AdminMessageService = retrofit.create()
|
||||
fun provideSchoolsService(
|
||||
okHttpClient: OkHttpClient,
|
||||
json: Json,
|
||||
appInfo: AppInfo,
|
||||
): SchoolsService = Retrofit.Builder()
|
||||
.baseUrl(appInfo.schoolsBaseUrl)
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||
.build()
|
||||
.create()
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
|
@ -0,0 +1,14 @@
|
||||
package io.github.wulkanowy.data.api
|
||||
|
||||
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
||||
import io.github.wulkanowy.data.pojos.LoginEvent
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
interface SchoolsService {
|
||||
|
||||
@POST("/log/loginEvent")
|
||||
suspend fun logLoginEvent(@Body request: IntegrityRequest<LoginEvent>)
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package io.github.wulkanowy.data.pojos
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LoginEvent(
|
||||
val uuid: String,
|
||||
val schoolName: String,
|
||||
val schoolShort: String,
|
||||
val schoolAddress: String,
|
||||
val scraperBaseUrl: String,
|
||||
val symbol: String,
|
||||
val schoolId: String,
|
||||
val loginType: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class IntegrityRequest<T>(
|
||||
val tokenString: String,
|
||||
val data: T,
|
||||
)
|
@ -0,0 +1,68 @@
|
||||
package io.github.wulkanowy.data.repositories
|
||||
|
||||
import io.github.wulkanowy.data.api.SchoolsService
|
||||
import io.github.wulkanowy.data.db.entities.Semester
|
||||
import io.github.wulkanowy.data.db.entities.Student
|
||||
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
|
||||
import io.github.wulkanowy.data.pojos.IntegrityRequest
|
||||
import io.github.wulkanowy.data.pojos.LoginEvent
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
import io.github.wulkanowy.utils.IntegrityHelper
|
||||
import io.github.wulkanowy.utils.getCurrentOrLast
|
||||
import io.github.wulkanowy.utils.init
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Singleton
|
||||
class SchoolsRepository @Inject constructor(
|
||||
private val integrityHelper: IntegrityHelper,
|
||||
private val schoolsService: SchoolsService,
|
||||
private val sdk: Sdk,
|
||||
) {
|
||||
|
||||
suspend fun logSchoolLogin(loginData: LoginData, students: List<StudentWithSemesters>) {
|
||||
students.forEach {
|
||||
runCatching {
|
||||
withTimeout(10.seconds) {
|
||||
logLogin(loginData, it.student, it.semesters.getCurrentOrLast())
|
||||
}
|
||||
}
|
||||
.onFailure { Timber.e(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun logLogin(loginData: LoginData, student: Student, semester: Semester) {
|
||||
val requestId = UUID.randomUUID().toString()
|
||||
val token = integrityHelper.getIntegrityToken(requestId) ?: return
|
||||
|
||||
val schoolInfo = sdk
|
||||
.init(student.copy(password = loginData.password))
|
||||
.switchDiary(
|
||||
diaryId = semester.diaryId,
|
||||
kindergartenDiaryId = semester.kindergartenDiaryId,
|
||||
schoolYear = semester.schoolYear
|
||||
)
|
||||
.getSchool()
|
||||
|
||||
schoolsService.logLoginEvent(
|
||||
IntegrityRequest(
|
||||
tokenString = token,
|
||||
data = LoginEvent(
|
||||
uuid = requestId,
|
||||
schoolAddress = schoolInfo.address,
|
||||
schoolName = schoolInfo.name,
|
||||
schoolShort = student.schoolShortName,
|
||||
scraperBaseUrl = student.scrapperBaseUrl,
|
||||
loginType = student.loginType,
|
||||
symbol = student.symbol,
|
||||
schoolId = student.schoolSymbol,
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import io.github.wulkanowy.data.pojos.RegisterStudent
|
||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.SchoolsRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException
|
||||
@ -26,6 +27,7 @@ import javax.inject.Inject
|
||||
|
||||
class LoginStudentSelectPresenter @Inject constructor(
|
||||
studentRepository: StudentRepository,
|
||||
private val schoolsRepository: SchoolsRepository,
|
||||
private val loginErrorHandler: LoginErrorHandler,
|
||||
private val syncManager: SyncManager,
|
||||
private val analytics: AnalyticsHelper,
|
||||
@ -236,17 +238,20 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun registerStudents(students: List<LoginStudentSelectItem>) {
|
||||
val studentsWithSemesters = students
|
||||
.filterIsInstance<LoginStudentSelectItem.Student>().map { item ->
|
||||
item.student.mapToStudentWithSemesters(
|
||||
user = registerUser,
|
||||
symbol = item.symbol,
|
||||
scrapperDomainSuffix = loginData.domainSuffix,
|
||||
unit = item.unit,
|
||||
colors = appInfo.defaultColorsForAvatar,
|
||||
)
|
||||
}
|
||||
resourceFlow { studentRepository.saveStudents(studentsWithSemesters) }
|
||||
val filteredStudents = students.filterIsInstance<LoginStudentSelectItem.Student>()
|
||||
val studentsWithSemesters = filteredStudents.map { item ->
|
||||
item.student.mapToStudentWithSemesters(
|
||||
user = registerUser,
|
||||
symbol = item.symbol,
|
||||
scrapperDomainSuffix = loginData.domainSuffix,
|
||||
unit = item.unit,
|
||||
colors = appInfo.defaultColorsForAvatar,
|
||||
)
|
||||
}
|
||||
resourceFlow {
|
||||
studentRepository.saveStudents(studentsWithSemesters)
|
||||
schoolsRepository.logSchoolLogin(loginData, studentsWithSemesters)
|
||||
}
|
||||
.logResourceStatus("registration")
|
||||
.onEach {
|
||||
when (it) {
|
||||
@ -254,11 +259,13 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
showProgress(true)
|
||||
showContent(false)
|
||||
}
|
||||
|
||||
is Resource.Success -> {
|
||||
syncManager.startOneTimeSyncWorker(quiet = true)
|
||||
view?.navigateToNext()
|
||||
logRegisterEvent(studentsWithSemesters)
|
||||
}
|
||||
|
||||
is Resource.Error -> {
|
||||
view?.apply {
|
||||
showProgress(false)
|
||||
|
@ -25,7 +25,8 @@ open class AppInfo @Inject constructor() {
|
||||
|
||||
open val systemModel: String get() = Build.MODEL
|
||||
|
||||
open val messagesBaseUrl = BuildConfig.MESSAGES_BASE_URL
|
||||
open val messagesBaseUrl: String = BuildConfig.MESSAGES_BASE_URL
|
||||
open val schoolsBaseUrl: String = BuildConfig.SCHOOLS_BASE_URL
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
open val systemLanguage: String
|
||||
|
@ -0,0 +1,27 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.play.core.integrity.IntegrityManagerFactory
|
||||
import com.google.android.play.core.integrity.IntegrityTokenRequest
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class IntegrityHelper @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
) {
|
||||
|
||||
suspend fun getIntegrityToken(nonce: String): String? {
|
||||
val integrityManager = IntegrityManagerFactory.create(context)
|
||||
|
||||
val integrityTokenResponse = integrityManager.requestIntegrityToken(
|
||||
IntegrityTokenRequest.builder()
|
||||
.setNonce(nonce)
|
||||
.build()
|
||||
)
|
||||
return integrityTokenResponse.await().token()
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import io.github.wulkanowy.data.pojos.RegisterStudent
|
||||
import io.github.wulkanowy.data.pojos.RegisterSymbol
|
||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.SchoolsRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||
@ -40,6 +41,9 @@ class LoginStudentSelectPresenterTest {
|
||||
@MockK
|
||||
lateinit var studentRepository: StudentRepository
|
||||
|
||||
@MockK
|
||||
lateinit var schoolsRepository: SchoolsRepository
|
||||
|
||||
@MockK(relaxed = true)
|
||||
lateinit var analytics: AnalyticsHelper
|
||||
|
||||
@ -110,6 +114,7 @@ class LoginStudentSelectPresenterTest {
|
||||
clearMocks(studentRepository, loginStudentSelectView)
|
||||
|
||||
coEvery { studentRepository.getSavedStudents(false) } returns emptyList()
|
||||
coEvery { schoolsRepository.logSchoolLogin(any(), any()) } just Runs
|
||||
|
||||
every { loginStudentSelectView.initView() } just Runs
|
||||
every { loginStudentSelectView.symbols } returns emptyMap()
|
||||
@ -120,6 +125,7 @@ class LoginStudentSelectPresenterTest {
|
||||
|
||||
presenter = LoginStudentSelectPresenter(
|
||||
studentRepository = studentRepository,
|
||||
schoolsRepository = schoolsRepository,
|
||||
loginErrorHandler = errorHandler,
|
||||
syncManager = syncManager,
|
||||
analytics = analytics,
|
||||
|
Loading…
x
Reference in New Issue
Block a user