mirror of
https://github.com/wulkanowy/wulkanowy.git
synced 2025-02-07 17:14:37 +01:00
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'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
||||||
|
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
@ -78,6 +79,7 @@ android {
|
|||||||
versionNameSuffix "-dev"
|
versionNameSuffix "-dev"
|
||||||
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
ext.enableCrashlytics = project.hasProperty("enableFirebase")
|
||||||
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
|
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:1.10.3'
|
||||||
playImplementation 'com.google.android.play:core-ktx:1.8.1'
|
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.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.hms:hianalytics:6.12.0.300'
|
||||||
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301'
|
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.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import io.github.wulkanowy.data.api.AdminMessageService
|
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.AppDatabase
|
||||||
import io.github.wulkanowy.data.db.SharedPrefProvider
|
import io.github.wulkanowy.data.db.SharedPrefProvider
|
||||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||||
@ -82,19 +83,29 @@ internal class DataModule {
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun provideRetrofit(
|
fun provideAdminMessageService(
|
||||||
okHttpClient: OkHttpClient,
|
okHttpClient: OkHttpClient,
|
||||||
json: Json,
|
json: Json,
|
||||||
appInfo: AppInfo
|
appInfo: AppInfo
|
||||||
): Retrofit = Retrofit.Builder()
|
): AdminMessageService = Retrofit.Builder()
|
||||||
.baseUrl(appInfo.messagesBaseUrl)
|
.baseUrl(appInfo.messagesBaseUrl)
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
|
.create()
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@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
|
@Singleton
|
||||||
@Provides
|
@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.RegisterSymbol
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
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.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.data.resourceFlow
|
import io.github.wulkanowy.data.resourceFlow
|
||||||
import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException
|
import io.github.wulkanowy.sdk.scrapper.login.AccountPermissionException
|
||||||
@ -26,6 +27,7 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
class LoginStudentSelectPresenter @Inject constructor(
|
class LoginStudentSelectPresenter @Inject constructor(
|
||||||
studentRepository: StudentRepository,
|
studentRepository: StudentRepository,
|
||||||
|
private val schoolsRepository: SchoolsRepository,
|
||||||
private val loginErrorHandler: LoginErrorHandler,
|
private val loginErrorHandler: LoginErrorHandler,
|
||||||
private val syncManager: SyncManager,
|
private val syncManager: SyncManager,
|
||||||
private val analytics: AnalyticsHelper,
|
private val analytics: AnalyticsHelper,
|
||||||
@ -236,17 +238,20 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun registerStudents(students: List<LoginStudentSelectItem>) {
|
private fun registerStudents(students: List<LoginStudentSelectItem>) {
|
||||||
val studentsWithSemesters = students
|
val filteredStudents = students.filterIsInstance<LoginStudentSelectItem.Student>()
|
||||||
.filterIsInstance<LoginStudentSelectItem.Student>().map { item ->
|
val studentsWithSemesters = filteredStudents.map { item ->
|
||||||
item.student.mapToStudentWithSemesters(
|
item.student.mapToStudentWithSemesters(
|
||||||
user = registerUser,
|
user = registerUser,
|
||||||
symbol = item.symbol,
|
symbol = item.symbol,
|
||||||
scrapperDomainSuffix = loginData.domainSuffix,
|
scrapperDomainSuffix = loginData.domainSuffix,
|
||||||
unit = item.unit,
|
unit = item.unit,
|
||||||
colors = appInfo.defaultColorsForAvatar,
|
colors = appInfo.defaultColorsForAvatar,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
resourceFlow { studentRepository.saveStudents(studentsWithSemesters) }
|
resourceFlow {
|
||||||
|
studentRepository.saveStudents(studentsWithSemesters)
|
||||||
|
schoolsRepository.logSchoolLogin(loginData, studentsWithSemesters)
|
||||||
|
}
|
||||||
.logResourceStatus("registration")
|
.logResourceStatus("registration")
|
||||||
.onEach {
|
.onEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
@ -254,11 +259,13 @@ class LoginStudentSelectPresenter @Inject constructor(
|
|||||||
showProgress(true)
|
showProgress(true)
|
||||||
showContent(false)
|
showContent(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Success -> {
|
is Resource.Success -> {
|
||||||
syncManager.startOneTimeSyncWorker(quiet = true)
|
syncManager.startOneTimeSyncWorker(quiet = true)
|
||||||
view?.navigateToNext()
|
view?.navigateToNext()
|
||||||
logRegisterEvent(studentsWithSemesters)
|
logRegisterEvent(studentsWithSemesters)
|
||||||
}
|
}
|
||||||
|
|
||||||
is Resource.Error -> {
|
is Resource.Error -> {
|
||||||
view?.apply {
|
view?.apply {
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
|
@ -25,7 +25,8 @@ open class AppInfo @Inject constructor() {
|
|||||||
|
|
||||||
open val systemModel: String get() = Build.MODEL
|
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")
|
@Suppress("DEPRECATION")
|
||||||
open val systemLanguage: String
|
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.RegisterSymbol
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUnit
|
import io.github.wulkanowy.data.pojos.RegisterUnit
|
||||||
import io.github.wulkanowy.data.pojos.RegisterUser
|
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.repositories.StudentRepository
|
||||||
import io.github.wulkanowy.sdk.Sdk
|
import io.github.wulkanowy.sdk.Sdk
|
||||||
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
import io.github.wulkanowy.sdk.scrapper.Scrapper
|
||||||
@ -40,6 +41,9 @@ class LoginStudentSelectPresenterTest {
|
|||||||
@MockK
|
@MockK
|
||||||
lateinit var studentRepository: StudentRepository
|
lateinit var studentRepository: StudentRepository
|
||||||
|
|
||||||
|
@MockK
|
||||||
|
lateinit var schoolsRepository: SchoolsRepository
|
||||||
|
|
||||||
@MockK(relaxed = true)
|
@MockK(relaxed = true)
|
||||||
lateinit var analytics: AnalyticsHelper
|
lateinit var analytics: AnalyticsHelper
|
||||||
|
|
||||||
@ -110,6 +114,7 @@ class LoginStudentSelectPresenterTest {
|
|||||||
clearMocks(studentRepository, loginStudentSelectView)
|
clearMocks(studentRepository, loginStudentSelectView)
|
||||||
|
|
||||||
coEvery { studentRepository.getSavedStudents(false) } returns emptyList()
|
coEvery { studentRepository.getSavedStudents(false) } returns emptyList()
|
||||||
|
coEvery { schoolsRepository.logSchoolLogin(any(), any()) } just Runs
|
||||||
|
|
||||||
every { loginStudentSelectView.initView() } just Runs
|
every { loginStudentSelectView.initView() } just Runs
|
||||||
every { loginStudentSelectView.symbols } returns emptyMap()
|
every { loginStudentSelectView.symbols } returns emptyMap()
|
||||||
@ -120,6 +125,7 @@ class LoginStudentSelectPresenterTest {
|
|||||||
|
|
||||||
presenter = LoginStudentSelectPresenter(
|
presenter = LoginStudentSelectPresenter(
|
||||||
studentRepository = studentRepository,
|
studentRepository = studentRepository,
|
||||||
|
schoolsRepository = schoolsRepository,
|
||||||
loginErrorHandler = errorHandler,
|
loginErrorHandler = errorHandler,
|
||||||
syncManager = syncManager,
|
syncManager = syncManager,
|
||||||
analytics = analytics,
|
analytics = analytics,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user