Merge branch 'bugfix/2.5.3'

This commit is contained in:
Mikołaj Pich 2024-03-24 23:43:51 +01:00
commit 2e71c50894
No known key found for this signature in database
64 changed files with 3281 additions and 393 deletions

View File

@ -27,8 +27,8 @@ android {
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 34 targetSdkVersion 34
versionCode 151 versionCode 152
versionName "2.5.2" versionName "2.5.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy" resValue "string", "app_name", "Wulkanowy"
@ -164,7 +164,7 @@ play {
defaultToAppBundles = false defaultToAppBundles = false
track = 'production' track = 'production'
releaseStatus = ReleaseStatus.IN_PROGRESS releaseStatus = ReleaseStatus.IN_PROGRESS
userFraction = 0.50d userFraction = 0.20d
updatePriority = 3 updatePriority = 3
enabled.set(false) enabled.set(false)
} }
@ -195,7 +195,7 @@ ext {
} }
dependencies { dependencies {
implementation 'io.github.wulkanowy:sdk:2.5.2' implementation 'io.github.wulkanowy:sdk:2.5.3'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'

File diff suppressed because it is too large Load Diff

View File

@ -18,17 +18,13 @@ 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
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AppInfo import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.RemoteConfigHelper
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.create import retrofit2.create
import timber.log.Timber
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Singleton import javax.inject.Singleton
@ -36,23 +32,6 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
internal class DataModule { internal class DataModule {
@Singleton
@Provides
fun provideSdk(
chuckerInterceptor: ChuckerInterceptor,
remoteConfig: RemoteConfigHelper,
webkitCookieManagerProxy: WebkitCookieManagerProxy,
) = Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
userAgentTemplate = remoteConfig.userAgentTemplate
setSimpleHttpLogger { Timber.d(it) }
setAdditionalCookieManager(webkitCookieManagerProxy)
// for debug only
addInterceptor(chuckerInterceptor, network = true)
}
@Singleton @Singleton
@Provides @Provides
fun provideChuckerCollector( fun provideChuckerCollector(

View File

@ -0,0 +1,113 @@
package io.github.wulkanowy.data
import com.chuckerteam.chucker.api.ChuckerInterceptor
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.RemoteConfigHelper
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class WulkanowySdkFactory @Inject constructor(
private val chuckerInterceptor: ChuckerInterceptor,
private val remoteConfig: RemoteConfigHelper,
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
private val studentDb: StudentDao,
) {
private val eduOneMutex = Mutex()
private val sdk = Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
userAgentTemplate = remoteConfig.userAgentTemplate
setSimpleHttpLogger { Timber.d(it) }
setAdditionalCookieManager(webkitCookieManagerProxy)
// for debug only
addInterceptor(chuckerInterceptor, network = true)
}
fun create() = sdk
suspend fun create(student: Student, semester: Semester? = null): Sdk {
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
return buildSdk(student, semester, overrideIsEduOne)
}
private fun buildSdk(student: Student, semester: Semester?, isStudentEduOne: Boolean): Sdk {
return create().apply {
email = student.email
password = student.password
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
classId = student.classId
emptyCookieJarInterceptor = true
isEduOne = isStudentEduOne
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
mobileBaseUrl = student.mobileBaseUrl
} else {
scrapperBaseUrl = student.scrapperBaseUrl
domainSuffix = student.scrapperDomainSuffix
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
}
mode = Sdk.Mode.valueOf(student.loginMode)
mobileBaseUrl = student.mobileBaseUrl
keyId = student.certificateKey
privatePem = student.privateKey
if (semester != null) {
diaryId = semester.diaryId
kindergartenDiaryId = semester.kindergartenDiaryId
schoolYear = semester.schoolYear
unitId = semester.unitId
}
}
}
private suspend fun checkEduOneAndMigrateIfNecessary(student: Student): Boolean {
if (student.isEduOne != null) return student.isEduOne
eduOneMutex.withLock {
val studentFromDatabase = studentDb.loadById(student.id)
if (studentFromDatabase?.isEduOne != null) {
Timber.d("Migration eduOne: already done")
return studentFromDatabase.isEduOne
}
Timber.d("Migration eduOne: flag missing. Running migration...")
val initializedSdk = buildSdk(
student = student,
semester = null,
isStudentEduOne = false, // doesn't matter
)
val newCurrentStudent = runCatching { initializedSdk.getCurrentStudent() }
.onFailure { Timber.e(it, "Migration eduOne: can't get current student") }
.getOrNull()
if (newCurrentStudent == null) {
Timber.d("Migration eduOne: failed, so skipping")
return false
}
Timber.d("Migration eduOne: success. New isEduOne flag: ${newCurrentStudent.isEduOne}")
val studentIsEduOne = StudentIsEduOne(
id = student.id,
isEduOne = newCurrentStudent.isEduOne
)
studentDb.update(studentIsEduOne)
return newCurrentStudent.isEduOne
}
}
}

View File

@ -120,6 +120,7 @@ import io.github.wulkanowy.data.db.migrations.Migration55
import io.github.wulkanowy.data.db.migrations.Migration57 import io.github.wulkanowy.data.db.migrations.Migration57
import io.github.wulkanowy.data.db.migrations.Migration58 import io.github.wulkanowy.data.db.migrations.Migration58
import io.github.wulkanowy.data.db.migrations.Migration6 import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration63
import io.github.wulkanowy.data.db.migrations.Migration7 import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8 import io.github.wulkanowy.data.db.migrations.Migration8
import io.github.wulkanowy.data.db.migrations.Migration9 import io.github.wulkanowy.data.db.migrations.Migration9
@ -175,6 +176,7 @@ import javax.inject.Singleton
AutoMigration(from = 59, to = 60), AutoMigration(from = 59, to = 60),
AutoMigration(from = 60, to = 61), AutoMigration(from = 60, to = 61),
AutoMigration(from = 61, to = 62), AutoMigration(from = 61, to = 62),
AutoMigration(from = 62, to = 63, spec = Migration63::class),
], ],
version = AppDatabase.VERSION_SCHEMA, version = AppDatabase.VERSION_SCHEMA,
exportSchema = true exportSchema = true
@ -183,7 +185,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 62 const val VERSION_SCHEMA = 63
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf( fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(), Migration2(),

View File

@ -10,6 +10,7 @@ import androidx.room.Update
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentIsAuthorized import io.github.wulkanowy.data.db.entities.StudentIsAuthorized
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
import io.github.wulkanowy.data.db.entities.StudentName import io.github.wulkanowy.data.db.entities.StudentName
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import javax.inject.Singleton import javax.inject.Singleton
@ -27,6 +28,9 @@ abstract class StudentDao {
@Update(entity = Student::class) @Update(entity = Student::class)
abstract suspend fun update(studentIsAuthorized: StudentIsAuthorized) abstract suspend fun update(studentIsAuthorized: StudentIsAuthorized)
@Update(entity = Student::class)
abstract suspend fun update(studentIsEduOne: StudentIsEduOne)
@Update(entity = Student::class) @Update(entity = Student::class)
abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar) abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)

View File

@ -82,8 +82,8 @@ data class Student(
@ColumnInfo(name = "is_authorized", defaultValue = "0") @ColumnInfo(name = "is_authorized", defaultValue = "0")
val isAuthorized: Boolean, val isAuthorized: Boolean,
@ColumnInfo(name = "is_edu_one", defaultValue = "0") @ColumnInfo(name = "is_edu_one", defaultValue = "NULL")
val isEduOne: Boolean, val isEduOne: Boolean?,
) : Serializable { ) : Serializable {
@ -95,3 +95,22 @@ data class Student(
@ColumnInfo(name = "avatar_color") @ColumnInfo(name = "avatar_color")
var avatarColor = 0L var avatarColor = 0L
} }
@Entity
data class StudentIsAuthorized(
@PrimaryKey
var id: Long,
@ColumnInfo(name = "is_authorized", defaultValue = "NULL")
val isAuthorized: Boolean?,
) : Serializable
@Entity
data class StudentIsEduOne(
@PrimaryKey
var id: Long,
@ColumnInfo(name = "is_edu_one", defaultValue = "NULL")
val isEduOne: Boolean?,
) : Serializable

View File

@ -1,16 +0,0 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity
data class StudentIsAuthorized(
@ColumnInfo(name = "is_authorized", defaultValue = "0")
val isAuthorized: Boolean,
) : Serializable {
@PrimaryKey
var id: Long = 0
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.AutoMigrationSpec
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration63 : AutoMigrationSpec {
override fun onPostMigrate(db: SupportSQLiteDatabase) {
db.execSQL("UPDATE Students SET is_edu_one = NULL WHERE is_edu_one = 0")
}
}

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
@ -7,14 +8,11 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -28,7 +26,7 @@ import javax.inject.Singleton
class AttendanceRepository @Inject constructor( class AttendanceRepository @Inject constructor(
private val attendanceDb: AttendanceDao, private val attendanceDb: AttendanceDao,
private val timetableDb: TimetableDao, private val timetableDb: TimetableDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -59,8 +57,7 @@ class AttendanceRepository @Inject constructor(
val lessons = timetableDb.load( val lessons = timetableDb.load(
semester.diaryId, semester.studentId, start.monday, end.sunday semester.diaryId, semester.studentId, start.monday, end.sunday
) )
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getAttendance(start.monday, end.sunday) .getAttendance(start.monday, end.sunday)
.mapToEntities(semester, lessons) .mapToEntities(semester, lessons)
}, },
@ -90,8 +87,10 @@ class AttendanceRepository @Inject constructor(
} }
suspend fun excuseForAbsence( suspend fun excuseForAbsence(
student: Student, semester: Semester, student: Student,
absenceList: List<Attendance>, reason: String? = null semester: Semester,
absenceList: List<Attendance>,
reason: String? = null
) { ) {
val items = absenceList.map { attendance -> val items = absenceList.map { attendance ->
Absent( Absent(
@ -99,8 +98,7 @@ class AttendanceRepository @Inject constructor(
timeId = attendance.timeId timeId = attendance.timeId
) )
} }
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.excuseForAbsence(items, reason) .excuseForAbsence(items, reason)
} }
} }

View File

@ -1,17 +1,15 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import androidx.room.withTransaction import androidx.room.withTransaction
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
@ -20,9 +18,9 @@ import javax.inject.Singleton
@Singleton @Singleton
class AttendanceSummaryRepository @Inject constructor( class AttendanceSummaryRepository @Inject constructor(
private val attendanceDb: AttendanceSummaryDao, private val attendanceDb: AttendanceSummaryDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
private val appDatabase: AppDatabase, private val appDatabase: AppDatabase,
private val wulkanowySdkFactory: WulkanowySdkFactory,
) { ) {
private val saveFetchResultMutex = Mutex() private val saveFetchResultMutex = Mutex()
@ -43,8 +41,7 @@ class AttendanceSummaryRepository @Inject constructor(
}, },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) }, query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getAttendanceSummary(subjectId) .getAttendanceSummary(subjectId)
.mapToEntities(semester, subjectId) .mapToEntities(semester, subjectId)
}, },

View File

@ -1,17 +1,15 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate import java.time.LocalDate
@ -21,7 +19,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class CompletedLessonsRepository @Inject constructor( class CompletedLessonsRepository @Inject constructor(
private val completedLessonsDb: CompletedLessonsDao, private val completedLessonsDb: CompletedLessonsDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -53,8 +51,7 @@ class CompletedLessonsRepository @Inject constructor(
) )
}, },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getCompletedLessons(start.monday, end.sunday) .getCompletedLessons(start.monday, end.sunday)
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,16 +1,14 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.ConferenceDao import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.entities.Conference import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -21,7 +19,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class ConferenceRepository @Inject constructor( class ConferenceRepository @Inject constructor(
private val conferenceDb: ConferenceDao, private val conferenceDb: ConferenceDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -46,8 +44,7 @@ class ConferenceRepository @Inject constructor(
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate) conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
}, },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getConferences() .getConferences()
.mapToEntities(semester) .mapToEntities(semester)
.filter { it.date >= startDate } .filter { it.date >= startDate }

View File

@ -1,18 +1,16 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.endExamsDay import io.github.wulkanowy.utils.endExamsDay
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.startExamsDay import io.github.wulkanowy.utils.startExamsDay
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -23,7 +21,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class ExamRepository @Inject constructor( class ExamRepository @Inject constructor(
private val examDb: ExamDao, private val examDb: ExamDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -56,8 +54,7 @@ class ExamRepository @Inject constructor(
) )
}, },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getExams(start.startExamsDay, start.endExamsDay) .getExams(start.startExamsDay, start.endExamsDay)
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradeDescriptiveDao import io.github.wulkanowy.data.db.dao.GradeDescriptiveDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.GradeSummaryDao
@ -10,11 +11,8 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.toLocalDate import io.github.wulkanowy.utils.toLocalDate
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -30,7 +28,7 @@ class GradeRepository @Inject constructor(
private val gradeDb: GradeDao, private val gradeDb: GradeDao,
private val gradeSummaryDb: GradeSummaryDao, private val gradeSummaryDb: GradeSummaryDao,
private val gradeDescriptiveDb: GradeDescriptiveDao, private val gradeDescriptiveDb: GradeDescriptiveDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -63,8 +61,7 @@ class GradeRepository @Inject constructor(
} }
}, },
fetch = { fetch = {
val (details, summary, descriptive) = sdk.init(student) val (details, summary, descriptive) = wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getGrades(semester.semesterId) .getGrades(semester.semesterId)
Triple( Triple(

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
@ -12,11 +13,8 @@ import io.github.wulkanowy.data.mappers.mapPointsToStatisticsItems
import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems import io.github.wulkanowy.data.mappers.mapSemesterToStatisticItems
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import java.util.Locale import java.util.Locale
@ -28,7 +26,7 @@ class GradeStatisticsRepository @Inject constructor(
private val gradePartialStatisticsDb: GradePartialStatisticsDao, private val gradePartialStatisticsDb: GradePartialStatisticsDao,
private val gradePointsStatisticsDb: GradePointsStatisticsDao, private val gradePointsStatisticsDb: GradePointsStatisticsDao,
private val gradeSemesterStatisticsDb: GradeSemesterStatisticsDao, private val gradeSemesterStatisticsDb: GradeSemesterStatisticsDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -56,8 +54,7 @@ class GradeStatisticsRepository @Inject constructor(
}, },
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getGradesPartialStatistics(semester.semesterId) .getGradesPartialStatistics(semester.semesterId)
.mapToEntities(semester) .mapToEntities(semester)
}, },
@ -104,8 +101,7 @@ class GradeStatisticsRepository @Inject constructor(
}, },
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getGradesSemesterStatistics(semester.semesterId) .getGradesSemesterStatistics(semester.semesterId)
.mapToEntities(semester) .mapToEntities(semester)
}, },
@ -163,8 +159,7 @@ class GradeStatisticsRepository @Inject constructor(
}, },
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getGradesPointsStatistics(semester.semesterId) .getGradesPointsStatistics(semester.semesterId)
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,18 +1,16 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.HomeworkDao import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate import java.time.LocalDate
@ -22,7 +20,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class HomeworkRepository @Inject constructor( class HomeworkRepository @Inject constructor(
private val homeworkDb: HomeworkDao, private val homeworkDb: HomeworkDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -55,8 +53,7 @@ class HomeworkRepository @Inject constructor(
) )
}, },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getHomework(start.monday, end.sunday) .getHomework(start.monday, end.sunday)
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,12 +1,11 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.LuckyNumberDao import io.github.wulkanowy.data.db.dao.LuckyNumberDao
import io.github.wulkanowy.data.db.entities.LuckyNumber import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntity import io.github.wulkanowy.data.mappers.mapToEntity
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -18,7 +17,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class LuckyNumberRepository @Inject constructor( class LuckyNumberRepository @Inject constructor(
private val luckyNumberDb: LuckyNumberDao, private val luckyNumberDb: LuckyNumberDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
) { ) {
private val saveFetchResultMutex = Mutex() private val saveFetchResultMutex = Mutex()
@ -33,7 +32,9 @@ class LuckyNumberRepository @Inject constructor(
shouldFetch = { it == null || forceRefresh }, shouldFetch = { it == null || forceRefresh },
query = { luckyNumberDb.load(student.studentId, now()) }, query = { luckyNumberDb.load(student.studentId, now()) },
fetch = { fetch = {
sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) wulkanowySdkFactory.create(student)
.getLuckyNumber(student.schoolShortName)
?.mapToEntity(student)
}, },
saveFetchResult = { oldLuckyNumber, newLuckyNumber -> saveFetchResult = { oldLuckyNumber, newLuckyNumber ->
newLuckyNumber ?: return@networkBoundResource newLuckyNumber ?: return@networkBoundResource

View File

@ -4,6 +4,7 @@ import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.Resource import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.dao.MailboxDao import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
@ -29,11 +30,9 @@ import io.github.wulkanowy.data.pojos.MessageDraft
import io.github.wulkanowy.data.toFirstResult import io.github.wulkanowy.data.toFirstResult
import io.github.wulkanowy.data.waitForResult import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -48,7 +47,7 @@ class MessageRepository @Inject constructor(
private val messagesDb: MessagesDao, private val messagesDb: MessagesDao,
private val mutedMessageSendersDao: MutedMessageSendersDao, private val mutedMessageSendersDao: MutedMessageSendersDao,
private val messageAttachmentDao: MessageAttachmentDao, private val messageAttachmentDao: MessageAttachmentDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
private val sharedPrefProvider: SharedPrefProvider, private val sharedPrefProvider: SharedPrefProvider,
@ -82,10 +81,16 @@ class MessageRepository @Inject constructor(
} else messagesDb.loadMessagesWithMutedAuthor(mailbox.globalKey, folder.id) } else messagesDb.loadMessagesWithMutedAuthor(mailbox.globalKey, folder.id)
}, },
fetch = { fetch = {
sdk.init(student).getMessages( wulkanowySdkFactory.create(student)
.getMessages(
folder = Folder.valueOf(folder.name), folder = Folder.valueOf(folder.name),
mailboxKey = mailbox?.globalKey, mailboxKey = mailbox?.globalKey,
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email)) )
.mapToEntities(
student = student,
mailbox = mailbox,
allMailboxes = mailboxDao.loadAll(student.email)
)
}, },
saveFetchResult = { oldWithAuthors, new -> saveFetchResult = { oldWithAuthors, new ->
val old = oldWithAuthors.map { it.message } val old = oldWithAuthors.map { it.message }
@ -115,7 +120,8 @@ class MessageRepository @Inject constructor(
}, },
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) }, query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
fetch = { fetch = {
sdk.init(student).getMessageDetails( wulkanowySdkFactory.create(student)
.getMessageDetails(
messageKey = it!!.message.messageGlobalKey, messageKey = it!!.message.messageGlobalKey,
markAsRead = message.unread && markAsRead, markAsRead = message.unread && markAsRead,
) )
@ -159,7 +165,8 @@ class MessageRepository @Inject constructor(
recipients: List<Recipient>, recipients: List<Recipient>,
mailbox: Mailbox, mailbox: Mailbox,
) { ) {
sdk.init(student).sendMessage( wulkanowySdkFactory.create(student)
.sendMessage(
subject = subject, subject = subject,
content = content, content = content,
recipients = recipients.mapFromEntities(), recipients = recipients.mapFromEntities(),
@ -169,9 +176,8 @@ class MessageRepository @Inject constructor(
} }
suspend fun restoreMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) { suspend fun restoreMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) {
sdk.init(student).restoreMessages( wulkanowySdkFactory.create(student)
messages = messages.map { it.messageGlobalKey }, .restoreMessages(messages = messages.map { it.messageGlobalKey })
)
refreshFolders(student, mailbox) refreshFolders(student, mailbox)
} }
@ -182,7 +188,8 @@ class MessageRepository @Inject constructor(
suspend fun deleteMessages(student: Student, messages: List<Message>) { suspend fun deleteMessages(student: Student, messages: List<Message>) {
val firstMessage = messages.first() val firstMessage = messages.first()
sdk.init(student).deleteMessages( wulkanowySdkFactory.create(student)
.deleteMessages(
messages = messages.map { it.messageGlobalKey }, messages = messages.map { it.messageGlobalKey },
removeForever = firstMessage.folderId == TRASHED.id, removeForever = firstMessage.folderId == TRASHED.id,
) )
@ -230,7 +237,9 @@ class MessageRepository @Inject constructor(
}, },
query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) }, query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) },
fetch = { fetch = {
sdk.init(student).getMailboxes().mapToEntities(student) wulkanowySdkFactory.create(student)
.getMailboxes()
.mapToEntities(student)
}, },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
mailboxDao.deleteAll(old uniqueSubtract new) mailboxDao.deleteAll(old uniqueSubtract new)

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.MobileDeviceDao import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.entities.MobileDevice import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
@ -8,11 +9,8 @@ import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken import io.github.wulkanowy.data.mappers.mapToMobileDeviceToken
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.pojos.MobileDeviceToken import io.github.wulkanowy.data.pojos.MobileDeviceToken
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
@ -21,7 +19,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class MobileDeviceRepository @Inject constructor( class MobileDeviceRepository @Inject constructor(
private val mobileDb: MobileDeviceDao, private val mobileDb: MobileDeviceDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -42,8 +40,7 @@ class MobileDeviceRepository @Inject constructor(
}, },
query = { mobileDb.loadAll(student.userLoginId) }, query = { mobileDb.loadAll(student.userLoginId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getRegisteredDevices() .getRegisteredDevices()
.mapToEntities(student) .mapToEntities(student)
}, },
@ -57,16 +54,14 @@ class MobileDeviceRepository @Inject constructor(
) )
suspend fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice) { suspend fun unregisterDevice(student: Student, semester: Semester, device: MobileDevice) {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.unregisterDevice(device.deviceId) .unregisterDevice(device.deviceId)
mobileDb.deleteAll(listOf(device)) mobileDb.deleteAll(listOf(device))
} }
suspend fun getToken(student: Student, semester: Semester): MobileDeviceToken { suspend fun getToken(student: Student, semester: Semester): MobileDeviceToken {
return sdk.init(student) return wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getToken() .getToken()
.mapToMobileDeviceToken() .mapToMobileDeviceToken()
} }

View File

@ -1,16 +1,14 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.NoteDao import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.toLocalDate import io.github.wulkanowy.utils.toLocalDate
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@ -21,7 +19,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class NoteRepository @Inject constructor( class NoteRepository @Inject constructor(
private val noteDb: NoteDao, private val noteDb: NoteDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -45,8 +43,7 @@ class NoteRepository @Inject constructor(
}, },
query = { noteDb.loadAll(student.studentId) }, query = { noteDb.loadAll(student.studentId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getNotes() .getNotes()
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.RecipientDao import io.github.wulkanowy.data.db.dao.RecipientDao
import io.github.wulkanowy.data.db.entities.Mailbox import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.MailboxType import io.github.wulkanowy.data.db.entities.MailboxType
@ -7,10 +8,8 @@ import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -18,14 +17,15 @@ import javax.inject.Singleton
@Singleton @Singleton
class RecipientRepository @Inject constructor( class RecipientRepository @Inject constructor(
private val recipientDb: RecipientDao, private val recipientDb: RecipientDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val cacheKey = "recipient" private val cacheKey = "recipient"
suspend fun refreshRecipients(student: Student, mailbox: Mailbox, type: MailboxType) { suspend fun refreshRecipients(student: Student, mailbox: Mailbox, type: MailboxType) {
val new = sdk.init(student).getRecipients(mailbox.globalKey) val new = wulkanowySdkFactory.create(student)
.getRecipients(mailbox.globalKey)
.mapToEntities(mailbox.globalKey) .mapToEntities(mailbox.globalKey)
val old = recipientDb.loadAll(type, mailbox.globalKey) val old = recipientDb.loadAll(type, mailbox.globalKey)
@ -60,7 +60,7 @@ class RecipientRepository @Inject constructor(
): List<Recipient> { ): List<Recipient> {
mailbox ?: return emptyList() mailbox ?: return emptyList()
return sdk.init(student) return wulkanowySdkFactory.create(student)
.getMessageReplayDetails(message.messageGlobalKey) .getMessageReplayDetails(message.messageGlobalKey)
.sender .sender
.let(::listOf) .let(::listOf)

View File

@ -1,17 +1,23 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.data.WulkanowySdkFactory
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class RecoverRepository @Inject constructor(private val sdk: Sdk) { class RecoverRepository @Inject constructor(
private val wulkanowySdkFactory: WulkanowySdkFactory
) {
suspend fun getReCaptchaSiteKey(host: String, symbol: String): Pair<String, String> { suspend fun getReCaptchaSiteKey(host: String, symbol: String): Pair<String, String> =
return sdk.getPasswordResetCaptchaCode(host, symbol) wulkanowySdkFactory.create()
} .getPasswordResetCaptchaCode(host, symbol)
suspend fun sendRecoverRequest( suspend fun sendRecoverRequest(
url: String, symbol: String, email: String, reCaptchaResponse: String url: String,
): String = sdk.sendPasswordResetRequest(url, symbol, email, reCaptchaResponse) symbol: String,
email: String,
reCaptchaResponse: String
): String = wulkanowySdkFactory.create()
.sendPasswordResetRequest(url, symbol, email, reCaptchaResponse)
} }

View File

@ -1,14 +1,13 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
@ -18,7 +17,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class SchoolAnnouncementRepository @Inject constructor( class SchoolAnnouncementRepository @Inject constructor(
private val schoolAnnouncementDb: SchoolAnnouncementDao, private val schoolAnnouncementDb: SchoolAnnouncementDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -41,7 +40,7 @@ class SchoolAnnouncementRepository @Inject constructor(
schoolAnnouncementDb.loadAll(student.userLoginId) schoolAnnouncementDb.loadAll(student.userLoginId)
}, },
fetch = { fetch = {
val sdk = sdk.init(student) val sdk = wulkanowySdkFactory.create(student)
val lastAnnouncements = sdk.getLastAnnouncements().mapToEntities(student) val lastAnnouncements = sdk.getLastAnnouncements().mapToEntities(student)
val directorInformation = sdk.getDirectorInformation().mapToEntities(student) val directorInformation = sdk.getDirectorInformation().mapToEntities(student)
lastAnnouncements + directorInformation lastAnnouncements + directorInformation

View File

@ -1,15 +1,13 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.SchoolDao import io.github.wulkanowy.data.db.dao.SchoolDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntity import io.github.wulkanowy.data.mappers.mapToEntity
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -17,7 +15,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class SchoolRepository @Inject constructor( class SchoolRepository @Inject constructor(
private val schoolDb: SchoolDao, private val schoolDb: SchoolDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -40,8 +38,7 @@ class SchoolRepository @Inject constructor(
}, },
query = { schoolDb.load(semester.studentId, semester.classId) }, query = { schoolDb.load(semester.studentId, semester.classId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getSchool() .getSchool()
.mapToEntity(semester) .mapToEntity(semester)
}, },

View File

@ -1,17 +1,15 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.api.SchoolsService import io.github.wulkanowy.data.api.SchoolsService
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.pojos.IntegrityRequest import io.github.wulkanowy.data.pojos.IntegrityRequest
import io.github.wulkanowy.data.pojos.LoginEvent 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.ui.modules.login.LoginData
import io.github.wulkanowy.utils.IntegrityHelper import io.github.wulkanowy.utils.IntegrityHelper
import io.github.wulkanowy.utils.getCurrentOrLast import io.github.wulkanowy.utils.getCurrentOrLast
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeout
import timber.log.Timber import timber.log.Timber
import java.util.UUID import java.util.UUID
@ -23,7 +21,7 @@ import kotlin.time.Duration.Companion.seconds
class SchoolsRepository @Inject constructor( class SchoolsRepository @Inject constructor(
private val integrityHelper: IntegrityHelper, private val integrityHelper: IntegrityHelper,
private val schoolsService: SchoolsService, private val schoolsService: SchoolsService,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
) { ) {
suspend fun logSchoolLogin(loginData: LoginData, students: List<StudentWithSemesters>) { suspend fun logSchoolLogin(loginData: LoginData, students: List<StudentWithSemesters>) {
@ -40,10 +38,9 @@ class SchoolsRepository @Inject constructor(
private suspend fun logLogin(loginData: LoginData, student: Student, semester: Semester) { private suspend fun logLogin(loginData: LoginData, student: Student, semester: Semester) {
val requestId = UUID.randomUUID().toString() val requestId = UUID.randomUUID().toString()
val token = integrityHelper.getIntegrityToken(requestId) ?: return val token = integrityHelper.getIntegrityToken(requestId) ?: return
val updatedStudent = student.copy(password = loginData.password)
val schoolInfo = sdk val schoolInfo = wulkanowySdkFactory.create(updatedStudent, semester)
.init(student.copy(password = loginData.password))
.switchSemester(semester)
.getSchool() .getSchool()
schoolsService.logLoginEvent( schoolsService.logLoginEvent(

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
@ -7,7 +8,6 @@ import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.DispatchersProvider import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.getCurrentOrLast import io.github.wulkanowy.utils.getCurrentOrLast
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.isCurrent import io.github.wulkanowy.utils.isCurrent
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -18,7 +18,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class SemesterRepository @Inject constructor( class SemesterRepository @Inject constructor(
private val semesterDb: SemesterDao, private val semesterDb: SemesterDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val dispatchers: DispatchersProvider, private val dispatchers: DispatchersProvider,
) { ) {
@ -60,7 +60,10 @@ class SemesterRepository @Inject constructor(
} }
private suspend fun refreshSemesters(student: Student) { private suspend fun refreshSemesters(student: Student) {
val new = sdk.init(student).getSemesters().mapToEntities(student.studentId) val new = wulkanowySdkFactory.create(student)
.getSemesters()
.mapToEntities(student.studentId)
if (new.isEmpty()) return Timber.i("Empty semester list!") if (new.isEmpty()) return Timber.i("Empty semester list!")
val old = semesterDb.loadAll(student.studentId, student.classId) val old = semesterDb.loadAll(student.studentId, student.classId)

View File

@ -1,13 +1,11 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.StudentInfoDao import io.github.wulkanowy.data.db.dao.StudentInfoDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntity import io.github.wulkanowy.data.mappers.mapToEntity
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -15,7 +13,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class StudentInfoRepository @Inject constructor( class StudentInfoRepository @Inject constructor(
private val studentInfoDao: StudentInfoDao, private val studentInfoDao: StudentInfoDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
) { ) {
private val saveFetchResultMutex = Mutex() private val saveFetchResultMutex = Mutex()
@ -30,9 +28,9 @@ class StudentInfoRepository @Inject constructor(
shouldFetch = { it == null || forceRefresh }, shouldFetch = { it == null || forceRefresh },
query = { studentInfoDao.loadStudentInfo(student.studentId) }, query = { studentInfoDao.loadStudentInfo(student.studentId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester) .getStudentInfo()
.getStudentInfo().mapToEntity(semester) .mapToEntity(semester)
}, },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
if (old != null && new != old) { if (old != null && new != old) {

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import androidx.room.withTransaction import androidx.room.withTransaction
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.dao.StudentDao
@ -11,15 +12,14 @@ import io.github.wulkanowy.data.db.entities.StudentName
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToPojo import io.github.wulkanowy.data.mappers.mapToPojo
import io.github.wulkanowy.data.pojos.RegisterUser import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.DispatchersProvider import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.getCurrentOrLast
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.security.Scrambler import io.github.wulkanowy.utils.security.Scrambler
import io.github.wulkanowy.utils.switchSemester
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -28,7 +28,7 @@ class StudentRepository @Inject constructor(
private val dispatchers: DispatchersProvider, private val dispatchers: DispatchersProvider,
private val studentDb: StudentDao, private val studentDb: StudentDao,
private val semesterDb: SemesterDao, private val semesterDb: SemesterDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val appDatabase: AppDatabase, private val appDatabase: AppDatabase,
private val scrambler: Scrambler, private val scrambler: Scrambler,
) { ) {
@ -39,7 +39,7 @@ class StudentRepository @Inject constructor(
pin: String, pin: String,
symbol: String, symbol: String,
token: String token: String
): RegisterUser = sdk ): RegisterUser = wulkanowySdkFactory.create()
.getStudentsFromHebe(token, pin, symbol, "") .getStudentsFromHebe(token, pin, symbol, "")
.mapToPojo(null) .mapToPojo(null)
@ -49,7 +49,7 @@ class StudentRepository @Inject constructor(
scrapperBaseUrl: String, scrapperBaseUrl: String,
domainSuffix: String, domainSuffix: String,
symbol: String symbol: String
): RegisterUser = sdk ): RegisterUser = wulkanowySdkFactory.create()
.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, domainSuffix, symbol) .getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, domainSuffix, symbol)
.mapToPojo(password) .mapToPojo(password)
@ -58,7 +58,7 @@ class StudentRepository @Inject constructor(
password: String, password: String,
scrapperBaseUrl: String, scrapperBaseUrl: String,
symbol: String symbol: String
): RegisterUser = sdk ): RegisterUser = wulkanowySdkFactory.create()
.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol) .getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol)
.mapToPojo(password) .mapToPojo(password)
@ -102,23 +102,44 @@ class StudentRepository @Inject constructor(
return student return student
} }
suspend fun checkCurrentStudentAuthorizationStatus() { suspend fun updateCurrentStudentAuthStatus() {
Timber.i("Check isAuthorized: started")
val student = getCurrentStudent() val student = getCurrentStudent()
if (student.isAuthorized) {
if (!student.isAuthorized) { Timber.i("Check isAuthorized: already authorized")
val currentSemester = semesterDb.loadAll( return
studentId = student.studentId,
classId = student.classId,
).getCurrentOrLast()
val initializedSdk = sdk.init(student).switchSemester(currentSemester)
val isAuthorized = initializedSdk.getCurrentStudent()?.isAuthorized ?: false
if (isAuthorized) {
studentDb.update(StudentIsAuthorized(isAuthorized = true).apply {
id = student.id
})
} else throw NoAuthorizationException()
} }
val initializedSdk = wulkanowySdkFactory.create(student)
val newCurrentStudent = runCatching { initializedSdk.getCurrentStudent() }
.onFailure { Timber.e(it, "Check isAuthorized: error occurred") }
.getOrNull()
if (newCurrentStudent == null) {
Timber.d("Check isAuthorized: current user is null")
return
}
val currentStudentSemesters = semesterDb.loadAll(student.studentId, student.classId)
if (currentStudentSemesters.isEmpty()) {
Timber.d("Check isAuthorized: apply empty semesters workaround")
semesterDb.insertSemesters(
items = newCurrentStudent.semesters.mapToEntities(student.studentId),
)
}
if (!newCurrentStudent.isAuthorized) {
Timber.i("Check isAuthorized: authorization required")
throw NoAuthorizationException()
}
val studentIsAuthorized = StudentIsAuthorized(
id = student.id,
isAuthorized = true
)
Timber.i("Check isAuthorized: already authorized, update local status")
studentDb.update(studentIsAuthorized)
} }
suspend fun getCurrentStudent(decryptPass: Boolean = true): Student { suspend fun getCurrentStudent(decryptPass: Boolean = true): Student {
@ -170,20 +191,24 @@ class StudentRepository @Inject constructor(
.distinctBy { it.student.studentName }.size == 1 .distinctBy { it.student.studentName }.size == 1
suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) = suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) =
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.authorizePermission(pesel) .authorizePermission(pesel)
suspend fun refreshStudentName(student: Student, semester: Semester) { suspend fun refreshStudentAfterAuthorize(student: Student, semester: Semester) {
val newCurrentApiStudent = sdk.init(student) val newCurrentApiStudent = wulkanowySdkFactory
.switchSemester(semester) .create(student, semester)
.getCurrentStudent() ?: return .getCurrentStudent()
?: return Timber.d("Can't find student with id ${student.studentId}")
val studentName = StudentName( val studentName = StudentName(
studentName = "${newCurrentApiStudent.studentName} ${newCurrentApiStudent.studentSurname}" studentName = "${newCurrentApiStudent.studentName} ${newCurrentApiStudent.studentSurname}"
).apply { id = student.id } ).apply { id = student.id }
studentDb.update(studentName) studentDb.update(studentName)
semesterDb.removeOldAndSaveNew(
oldItems = semesterDb.loadAll(student.studentId, semester.classId),
newItems = newCurrentApiStudent.semesters.mapToEntities(newCurrentApiStudent.studentId)
)
} }
suspend fun deleteStudentsAssociatedWithAccount(student: Student) { suspend fun deleteStudentsAssociatedWithAccount(student: Student) {
@ -199,4 +224,3 @@ class StudentRepository @Inject constructor(
} }
class NoAuthorizationException : Exception() class NoAuthorizationException : Exception()

View File

@ -1,15 +1,13 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.SubjectDao import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
@ -18,7 +16,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class SubjectRepository @Inject constructor( class SubjectRepository @Inject constructor(
private val subjectDao: SubjectDao, private val subjectDao: SubjectDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -39,8 +37,7 @@ class SubjectRepository @Inject constructor(
}, },
query = { subjectDao.loadAll(semester.diaryId, semester.studentId) }, query = { subjectDao.loadAll(semester.diaryId, semester.studentId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getSubjects() .getSubjects()
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,15 +1,13 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.TeacherDao import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
@ -18,7 +16,7 @@ import javax.inject.Singleton
@Singleton @Singleton
class TeacherRepository @Inject constructor( class TeacherRepository @Inject constructor(
private val teacherDb: TeacherDao, private val teacherDb: TeacherDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -39,8 +37,7 @@ class TeacherRepository @Inject constructor(
}, },
query = { teacherDb.loadAll(semester.studentId, semester.classId) }, query = { teacherDb.loadAll(semester.studentId, semester.classId) },
fetch = { fetch = {
sdk.init(student) wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getTeachers() .getTeachers()
.mapToEntities(semester) .mapToEntities(semester)
}, },

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
@ -11,14 +12,11 @@ import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.pojos.TimetableFull import io.github.wulkanowy.data.pojos.TimetableFull
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.switchSemester
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@ -33,7 +31,7 @@ class TimetableRepository @Inject constructor(
private val timetableDb: TimetableDao, private val timetableDb: TimetableDao,
private val timetableAdditionalDb: TimetableAdditionalDao, private val timetableAdditionalDb: TimetableAdditionalDao,
private val timetableHeaderDb: TimetableHeaderDao, private val timetableHeaderDb: TimetableHeaderDao,
private val sdk: Sdk, private val wulkanowySdkFactory: WulkanowySdkFactory,
private val schedulerHelper: TimetableNotificationSchedulerHelper, private val schedulerHelper: TimetableNotificationSchedulerHelper,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
@ -74,8 +72,7 @@ class TimetableRepository @Inject constructor(
}, },
query = { getFullTimetableFromDatabase(student, semester, start, end) }, query = { getFullTimetableFromDatabase(student, semester, start, end) },
fetch = { fetch = {
val timetableFull = sdk.init(student) val timetableFull = wulkanowySdkFactory.create(student, semester)
.switchSemester(semester)
.getTimetable(start.monday, end.sunday) .getTimetable(start.monday, end.sunday)
timetableFull.mapToEntities(semester) timetableFull.mapToEntities(semester)

View File

@ -17,6 +17,7 @@ import io.github.wulkanowy.data.repositories.SemesterRepository
import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureUnavailableException
import io.github.wulkanowy.services.sync.channels.DebugChannel import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.works.Work import io.github.wulkanowy.services.sync.works.Work
import io.github.wulkanowy.utils.DispatchersProvider import io.github.wulkanowy.utils.DispatchersProvider
@ -48,6 +49,7 @@ class SyncWorker @AssistedInject constructor(
val semester = semesterRepository.getCurrentSemester(student, true) val semester = semesterRepository.getCurrentSemester(student, true)
student to semester student to semester
} catch (e: Throwable) { } catch (e: Throwable) {
Timber.e(e)
return@withContext getResultFromErrors(listOf(e)) return@withContext getResultFromErrors(listOf(e))
} }
@ -59,7 +61,7 @@ class SyncWorker @AssistedInject constructor(
null null
} catch (e: Throwable) { } catch (e: Throwable) {
Timber.w("${work::class.java.simpleName} result: An exception ${e.message} occurred") Timber.w("${work::class.java.simpleName} result: An exception ${e.message} occurred")
if (e is FeatureDisabledException || e is FeatureNotAvailableException) { if (e is FeatureDisabledException || e is FeatureNotAvailableException || e is FeatureUnavailableException) {
null null
} else { } else {
Timber.e(e) Timber.e(e)

View File

@ -5,6 +5,7 @@ import io.github.wulkanowy.data.repositories.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler import io.github.wulkanowy.ui.base.ErrorHandler
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class AuthPresenter @Inject constructor( class AuthPresenter @Inject constructor(
@ -57,8 +58,9 @@ class AuthPresenter @Inject constructor(
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
val isSuccess = studentRepository.authorizePermission(student, semester, pesel) val isSuccess = studentRepository.authorizePermission(student, semester, pesel)
Timber.d("Auth succeed: $isSuccess")
if (isSuccess) { if (isSuccess) {
studentRepository.refreshStudentName(student, semester) studentRepository.refreshStudentAfterAuthorize(student, semester)
} }
isSuccess isSuccess
} }
@ -68,6 +70,7 @@ class AuthPresenter @Inject constructor(
view?.showContent(true) view?.showContent(true)
} }
.onSuccess { .onSuccess {
Timber.d("Auth fully succeed: $it")
if (it) { if (it) {
view?.showSuccess(true) view?.showSuccess(true)
view?.showContent(false) view?.showContent(false)

View File

@ -10,8 +10,8 @@ import android.webkit.WebViewClient
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.databinding.DialogCaptchaBinding import io.github.wulkanowy.databinding.DialogCaptchaBinding
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.ui.base.BaseDialogFragment import io.github.wulkanowy.ui.base.BaseDialogFragment
import io.github.wulkanowy.utils.WebkitCookieManagerProxy import io.github.wulkanowy.utils.WebkitCookieManagerProxy
import timber.log.Timber import timber.log.Timber
@ -21,7 +21,7 @@ import javax.inject.Inject
class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() { class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
@Inject @Inject
lateinit var sdk: Sdk lateinit var wulkanowySdkFactory: WulkanowySdkFactory
@Inject @Inject
lateinit var webkitCookieManagerProxy: WebkitCookieManagerProxy lateinit var webkitCookieManagerProxy: WebkitCookieManagerProxy
@ -59,7 +59,7 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
webView = this webView = this
with(settings) { with(settings) {
javaScriptEnabled = true javaScriptEnabled = true
userAgentString = sdk.userAgent userAgentString = wulkanowySdkFactory.create().userAgent
} }
webViewClient = object : WebViewClient() { webViewClient = object : WebViewClient() {

View File

@ -7,7 +7,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.View.INVISIBLE import android.view.View.INVISIBLE
import android.view.View.VISIBLE import android.view.View.VISIBLE
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -31,14 +30,6 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
@Inject @Inject
lateinit var presenter: GradePresenter lateinit var presenter: GradePresenter
private val pagerAdapter by lazy {
BaseFragmentPagerAdapter(
fragmentManager = childFragmentManager,
pagesCount = 3,
lifecycle = lifecycle,
)
}
private var semesterSwitchMenu: MenuItem? = null private var semesterSwitchMenu: MenuItem? = null
companion object { companion object {
@ -52,6 +43,8 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
override val currentPageIndex get() = binding.gradeViewPager.currentItem override val currentPageIndex get() = binding.gradeViewPager.currentItem
private var pagerAdapter: BaseFragmentPagerAdapter? = null
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -71,13 +64,26 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
} }
override fun initView() { override fun initView() {
with(binding) {
gradeErrorRetry.setOnClickListener { presenter.onRetry() }
gradeErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
}
override fun initTabs(pageCount: Int) {
pagerAdapter = BaseFragmentPagerAdapter(
lifecycle = lifecycle,
pagesCount = pageCount,
fragmentManager = childFragmentManager
)
with(binding.gradeViewPager) { with(binding.gradeViewPager) {
adapter = pagerAdapter adapter = pagerAdapter
offscreenPageLimit = 3 offscreenPageLimit = 3
setOnSelectPageListener(presenter::onPageSelected) setOnSelectPageListener(presenter::onPageSelected)
} }
with(pagerAdapter) { with(pagerAdapter!!) {
containerId = binding.gradeViewPager.id containerId = binding.gradeViewPager.id
titleFactory = { titleFactory = {
when (it) { when (it) {
@ -99,11 +105,6 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
} }
binding.gradeTabLayout.elevation = requireContext().dpToPx(4f) binding.gradeTabLayout.elevation = requireContext().dpToPx(4f)
with(binding) {
gradeErrorRetry.setOnClickListener { presenter.onRetry() }
gradeErrorDetails.setOnClickListener { presenter.onDetailsClick() }
}
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -169,19 +170,20 @@ class GradeFragment : BaseFragment<FragmentGradeBinding>(R.layout.fragment_grade
} }
override fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) { override fun notifyChildLoadData(index: Int, semesterId: Int, forceRefresh: Boolean) {
(pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView) (pagerAdapter?.getFragmentInstance(index) as? GradeView.GradeChildView)
?.onParentLoadData(semesterId, forceRefresh) ?.onParentLoadData(semesterId, forceRefresh)
} }
override fun notifyChildParentReselected(index: Int) { override fun notifyChildParentReselected(index: Int) {
(pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentReselected() (pagerAdapter?.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentReselected()
} }
override fun notifyChildSemesterChange(index: Int) { override fun notifyChildSemesterChange(index: Int) {
(pagerAdapter.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentChangeSemester() (pagerAdapter?.getFragmentInstance(index) as? GradeView.GradeChildView)?.onParentChangeSemester()
} }
override fun onDestroyView() { override fun onDestroyView() {
pagerAdapter = null
presenter.onDetachView() presenter.onDetachView()
super.onDestroyView() super.onDestroyView()
} }

View File

@ -22,11 +22,8 @@ class GradePresenter @Inject constructor(
) : BasePresenter<GradeView>(errorHandler, studentRepository) { ) : BasePresenter<GradeView>(errorHandler, studentRepository) {
private var selectedIndex = 0 private var selectedIndex = 0
private var schoolYear = 0 private var schoolYear = 0
private var availableSemesters = emptyList<Semester>()
private var semesters = emptyList<Semester>()
private val loadedSemesterId = mutableMapOf<Int, Int>() private val loadedSemesterId = mutableMapOf<Int, Int>()
private lateinit var lastError: Throwable private lateinit var lastError: Throwable
@ -40,7 +37,7 @@ class GradePresenter @Inject constructor(
} }
fun onCreateMenu() { fun onCreateMenu() {
if (semesters.isEmpty()) view?.showSemesterSwitch(false) if (availableSemesters.isEmpty()) view?.showSemesterSwitch(false)
} }
fun onViewReselected() { fun onViewReselected() {
@ -49,8 +46,8 @@ class GradePresenter @Inject constructor(
} }
fun onSemesterSwitch(): Boolean { fun onSemesterSwitch(): Boolean {
if (semesters.isNotEmpty()) { if (availableSemesters.isNotEmpty()) {
view?.showSemesterDialog(selectedIndex - 1, semesters.take(2)) view?.showSemesterDialog(selectedIndex - 1, availableSemesters.take(2))
} }
return true return true
} }
@ -83,7 +80,7 @@ class GradePresenter @Inject constructor(
} }
fun onPageSelected(index: Int) { fun onPageSelected(index: Int) {
if (semesters.isNotEmpty()) loadChild(index) if (availableSemesters.isNotEmpty()) loadChild(index)
} }
fun onRetry() { fun onRetry() {
@ -101,16 +98,24 @@ class GradePresenter @Inject constructor(
private fun loadData() { private fun loadData() {
resourceFlow { resourceFlow {
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
semesterRepository.getSemesters(student, refreshOnNoCurrent = true) val semesters = semesterRepository.getSemesters(student, refreshOnNoCurrent = true)
student to semesters
} }
.logResourceStatus("load grade data") .logResourceStatus("load grade data")
.onResourceData { .onResourceData { (student, semesters) ->
val current = it.getCurrentOrLast() val currentSemester = semesters.getCurrentOrLast()
selectedIndex = if (selectedIndex == 0) current.semesterName else selectedIndex selectedIndex =
schoolYear = current.schoolYear if (selectedIndex == 0) currentSemester.semesterName else selectedIndex
semesters = it.filter { semester -> semester.diaryId == current.diaryId } schoolYear = currentSemester.schoolYear
view?.setCurrentSemesterName(current.semesterName, schoolYear) availableSemesters = semesters.filter { semester ->
semester.diaryId == currentSemester.diaryId
}
view?.run { view?.run {
initTabs(if (student.isEduOne == true) 2 else 3)
setCurrentSemesterName(currentSemester.semesterName, schoolYear)
Timber.i("Loading grade data: Attempt load index $currentPageIndex") Timber.i("Loading grade data: Attempt load index $currentPageIndex")
loadChild(currentPageIndex) loadChild(currentPageIndex)
showErrorView(false) showErrorView(false)
@ -131,10 +136,10 @@ class GradePresenter @Inject constructor(
} }
private fun loadChild(index: Int, forceRefresh: Boolean = false) { private fun loadChild(index: Int, forceRefresh: Boolean = false) {
Timber.d("Load grade tab child. Selected semester: $selectedIndex, semesters: ${semesters.joinToString { it.semesterName.toString() }}") Timber.d("Load grade tab child. Selected semester: $selectedIndex, semesters: ${availableSemesters.joinToString { it.semesterName.toString() }}")
val newSelectedSemesterId = try { val newSelectedSemesterId = try {
semesters.first { it.semesterName == selectedIndex }.semesterId availableSemesters.first { it.semesterName == selectedIndex }.semesterId
} catch (e: NoSuchElementException) { } catch (e: NoSuchElementException) {
Timber.e(e, "Selected semester no exists") Timber.e(e, "Selected semester no exists")
return return

View File

@ -9,6 +9,8 @@ interface GradeView : BaseView {
fun initView() fun initView()
fun initTabs(pageCount: Int)
fun showContent(show: Boolean) fun showContent(show: Boolean)
fun showProgress(show: Boolean) fun showProgress(show: Boolean)

View File

@ -98,8 +98,10 @@ class HomeworkAddDialog : BaseDialogFragment<DialogHomeworkAddBinding>(), Homewo
rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear, rangeEnd = LocalDate.now().lastSchoolDayInSchoolYear,
onDateSelected = { onDateSelected = {
date = it date = it
if (isAdded) {
binding.homeworkDialogDate.editText?.setText(date!!.toFormattedString()) binding.homeworkDialogDate.editText?.setText(date!!.toFormattedString())
} }
}
) )
} }

View File

@ -73,7 +73,7 @@ class MainPresenter @Inject constructor(
syncManager.startPeriodicSyncWorker() syncManager.startPeriodicSyncWorker()
checkAppSupport() checkAppSupport()
checkCurrentStudentAuthorizationStatus() updateCurrentStudentAuthStatus()
analytics.logEvent("app_open", "destination" to initDestination.toString()) analytics.logEvent("app_open", "destination" to initDestination.toString())
Timber.i("Main view was initialized with $initDestination") Timber.i("Main view was initialized with $initDestination")
@ -193,12 +193,10 @@ class MainPresenter @Inject constructor(
view?.showStudentAvatar(currentStudent) view?.showStudentAvatar(currentStudent)
} }
private fun checkCurrentStudentAuthorizationStatus() { private fun updateCurrentStudentAuthStatus() {
presenterScope.launch { presenterScope.launch {
runCatching { studentRepository.checkCurrentStudentAuthorizationStatus() } runCatching { studentRepository.updateCurrentStudentAuthStatus() }
.onFailure { errorHandler.dispatch(it) } .onFailure { errorHandler.dispatch(it) }
Timber.i("Current student authorization status checked")
} }
} }
} }

View File

@ -27,7 +27,7 @@ class TimetableAdapter @Inject constructor() :
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context) val inflater = LayoutInflater.from(parent.context)
return when (TimetableItemType.values()[viewType]) { return when (TimetableItemType.entries[viewType]) {
TimetableItemType.SMALL -> SmallViewHolder( TimetableItemType.SMALL -> SmallViewHolder(
ItemTimetableSmallBinding.inflate(inflater, parent, false) ItemTimetableSmallBinding.inflate(inflater, parent, false)
) )
@ -79,6 +79,7 @@ class TimetableAdapter @Inject constructor() :
with(binding) { with(binding) {
timetableSmallItemNumber.text = lesson.number.toString() timetableSmallItemNumber.text = lesson.number.toString()
timetableSmallItemNumber.isVisible = item.isLessonNumberVisible
timetableSmallItemSubject.text = lesson.subject timetableSmallItemSubject.text = lesson.subject
timetableSmallItemTimeStart.text = lesson.start.toFormattedString("HH:mm") timetableSmallItemTimeStart.text = lesson.start.toFormattedString("HH:mm")
timetableSmallItemRoom.text = lesson.room timetableSmallItemRoom.text = lesson.room
@ -97,6 +98,7 @@ class TimetableAdapter @Inject constructor() :
with(binding) { with(binding) {
timetableItemNumber.text = lesson.number.toString() timetableItemNumber.text = lesson.number.toString()
timetableItemNumber.isVisible = item.isLessonNumberVisible
timetableItemSubject.text = lesson.subject timetableItemSubject.text = lesson.subject
timetableItemGroup.text = lesson.group timetableItemGroup.text = lesson.group
timetableItemRoom.text = lesson.room timetableItemRoom.text = lesson.room

View File

@ -7,12 +7,14 @@ sealed class TimetableItem(val type: TimetableItemType) {
data class Small( data class Small(
val lesson: Timetable, val lesson: Timetable,
val isLessonNumberVisible: Boolean,
val onClick: (Timetable) -> Unit, val onClick: (Timetable) -> Unit,
) : TimetableItem(TimetableItemType.SMALL) ) : TimetableItem(TimetableItemType.SMALL)
data class Normal( data class Normal(
val lesson: Timetable, val lesson: Timetable,
val showGroupsInPlan: Boolean, val showGroupsInPlan: Boolean,
val isLessonNumberVisible: Boolean,
val timeLeft: TimeLeft?, val timeLeft: TimeLeft?,
val onClick: (Timetable) -> Unit, val onClick: (Timetable) -> Unit,
) : TimetableItem(TimetableItemType.NORMAL) ) : TimetableItem(TimetableItemType.NORMAL)

View File

@ -57,6 +57,7 @@ class TimetablePresenter @Inject constructor(
private var initialDate: LocalDate? = null private var initialDate: LocalDate? = null
private var isWeekendHasLessons: Boolean = false private var isWeekendHasLessons: Boolean = false
private var isEduOne: Boolean = false
var currentDate: LocalDate? = null var currentDate: LocalDate? = null
private set private set
@ -149,6 +150,7 @@ class TimetablePresenter @Inject constructor(
val student = studentRepository.getCurrentStudent() val student = studentRepository.getCurrentStudent()
val semester = semesterRepository.getCurrentSemester(student) val semester = semesterRepository.getCurrentSemester(student)
isEduOne = student.isEduOne == true
checkInitialAndCurrentDate(semester) checkInitialAndCurrentDate(semester)
timetableRepository.getTimetable( timetableRepository.getTimetable(
student = student, student = student,
@ -234,9 +236,8 @@ class TimetablePresenter @Inject constructor(
if (prefRepository.showWholeClassPlan == TimetableMode.ONLY_CURRENT_GROUP) { if (prefRepository.showWholeClassPlan == TimetableMode.ONLY_CURRENT_GROUP) {
it.isStudentPlan it.isStudentPlan
} else true } else true
}.sortedWith( }
compareBy({ item -> item.number }, { item -> !item.isStudentPlan }) .sortedWith(compareBy({ item -> item.start }, { item -> !item.isStudentPlan }))
)
var prevNum = when (prefRepository.showTimetableGaps) { var prevNum = when (prefRepository.showTimetableGaps) {
BETWEEN_AND_BEFORE_LESSONS -> 0 BETWEEN_AND_BEFORE_LESSONS -> 0
@ -257,13 +258,15 @@ class TimetablePresenter @Inject constructor(
lesson = it, lesson = it,
showGroupsInPlan = prefRepository.showGroupsInPlan, showGroupsInPlan = prefRepository.showGroupsInPlan,
timeLeft = filteredItems.getTimeLeftForLesson(it, i), timeLeft = filteredItems.getTimeLeftForLesson(it, i),
onClick = ::onTimetableItemSelected onClick = ::onTimetableItemSelected,
isLessonNumberVisible = !isEduOne
) )
add(normalLesson) add(normalLesson)
} else { } else {
val smallLesson = TimetableItem.Small( val smallLesson = TimetableItem.Small(
lesson = it, lesson = it,
onClick = ::onTimetableItemSelected onClick = ::onTimetableItemSelected,
isLessonNumberVisible = !isEduOne
) )
add(smallLesson) add(smallLesson)
} }

View File

@ -46,11 +46,8 @@ class TimetableWidgetFactory(
) : RemoteViewsService.RemoteViewsFactory { ) : RemoteViewsService.RemoteViewsFactory {
private var items = emptyList<TimetableWidgetItem>() private var items = emptyList<TimetableWidgetItem>()
private var timetableCanceledColor: Int? = null private var timetableCanceledColor: Int? = null
private var textColor: Int? = null private var textColor: Int? = null
private var timetableChangeColor: Int? = null private var timetableChangeColor: Int? = null
override fun getLoadingView() = null override fun getLoadingView() = null
@ -81,7 +78,7 @@ class TimetableWidgetFactory(
val lessons = getLessons(student, semester, date) val lessons = getLessons(student, semester, date)
val lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date) val lastSync = timetableRepository.getLastRefreshTimestamp(semester, date, date)
createItems(lessons, lastSync) createItems(lessons, lastSync, !(student.isEduOne ?: false))
} }
.onFailure { .onFailure {
items = listOf(TimetableWidgetItem.Error(it)) items = listOf(TimetableWidgetItem.Error(it))
@ -106,12 +103,13 @@ class TimetableWidgetFactory(
): List<Timetable> { ): List<Timetable> {
val timetable = timetableRepository.getTimetable(student, semester, date, date, false) val timetable = timetableRepository.getTimetable(student, semester, date, date, false)
val lessons = timetable.toFirstResult().dataOrThrow.lessons val lessons = timetable.toFirstResult().dataOrThrow.lessons
return lessons.sortedBy { it.number } return lessons.sortedBy { it.start }
} }
private fun createItems( private fun createItems(
lessons: List<Timetable>, lessons: List<Timetable>,
lastSync: Instant?, lastSync: Instant?,
isEduOne: Boolean
): List<TimetableWidgetItem> { ): List<TimetableWidgetItem> {
var prevNum = when (prefRepository.showTimetableGaps) { var prevNum = when (prefRepository.showTimetableGaps) {
BETWEEN_AND_BEFORE_LESSONS -> 0 BETWEEN_AND_BEFORE_LESSONS -> 0
@ -127,7 +125,7 @@ class TimetableWidgetFactory(
) )
add(emptyItem) add(emptyItem)
} }
add(TimetableWidgetItem.Normal(it)) add(TimetableWidgetItem.Normal(it, isEduOne))
prevNum = it.number prevNum = it.number
} }
add(TimetableWidgetItem.Synchronized(lastSync ?: Instant.MIN)) add(TimetableWidgetItem.Synchronized(lastSync ?: Instant.MIN))
@ -155,9 +153,11 @@ class TimetableWidgetFactory(
val lessonStartTime = lesson.start.toFormattedString(TIME_FORMAT_STYLE) val lessonStartTime = lesson.start.toFormattedString(TIME_FORMAT_STYLE)
val lessonEndTime = lesson.end.toFormattedString(TIME_FORMAT_STYLE) val lessonEndTime = lesson.end.toFormattedString(TIME_FORMAT_STYLE)
val lessonNumberVisibility = if (item.isLessonNumberVisible) VISIBLE else GONE
val remoteViews = RemoteViews(context.packageName, R.layout.item_widget_timetable).apply { val remoteViews = RemoteViews(context.packageName, R.layout.item_widget_timetable).apply {
setTextViewText(R.id.timetableWidgetItemNumber, lesson.number.toString()) setTextViewText(R.id.timetableWidgetItemNumber, lesson.number.toString())
setViewVisibility(R.id.timetableWidgetItemNumber, lessonNumberVisibility)
setTextViewText(R.id.timetableWidgetItemTimeStart, lessonStartTime) setTextViewText(R.id.timetableWidgetItemTimeStart, lessonStartTime)
setTextViewText(R.id.timetableWidgetItemTimeFinish, lessonEndTime) setTextViewText(R.id.timetableWidgetItemTimeFinish, lessonEndTime)
setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject) setTextViewText(R.id.timetableWidgetItemSubject, lesson.subject)

View File

@ -7,6 +7,7 @@ sealed class TimetableWidgetItem(val type: TimetableWidgetItemType) {
data class Normal( data class Normal(
val lesson: Timetable, val lesson: Timetable,
val isLessonNumberVisible: Boolean,
) : TimetableWidgetItem(TimetableWidgetItemType.NORMAL) ) : TimetableWidgetItem(TimetableWidgetItemType.NORMAL)
data class Empty( data class Empty(

View File

@ -1,43 +0,0 @@
package io.github.wulkanowy.utils
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import timber.log.Timber
fun Sdk.init(student: Student): Sdk {
email = student.email
password = student.password
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
classId = student.classId
isEduOne = student.isEduOne
emptyCookieJarInterceptor = true
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
mobileBaseUrl = student.mobileBaseUrl
} else {
scrapperBaseUrl = student.scrapperBaseUrl
domainSuffix = student.scrapperDomainSuffix
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
}
mode = Sdk.Mode.valueOf(student.loginMode)
mobileBaseUrl = student.mobileBaseUrl
keyId = student.certificateKey
privatePem = student.privateKey
Timber.d("Sdk in ${student.loginMode} mode reinitialized")
return this
}
fun Sdk.switchSemester(semester: Semester): Sdk {
return switchDiary(
diaryId = semester.diaryId,
kindergartenDiaryId = semester.kindergartenDiaryId,
schoolYear = semester.schoolYear,
unitId = semester.unitId,
)
}

View File

@ -1,7 +1,8 @@
Wersja 2.5.2 Wersja 2.5.3
— naprawiliśmy omyłkowe wyświetlanie ekranu z wymaganą autoryzacją numerem PESEL — naprawiliśmy wyświetlanie błędu "Brak uprawnień" po starcie aplikacji u użytkowników eduOne
— naprawiliśmy kilka problemów ze stabilnością — naprawiliśmy obsługę autoryzacji u użytkowników eduOne
— poprawiliśmy wyświetlanie kolorów we frekwencji — ukryliśmy numery lekcji i oceny klasy u użytkowników eduOne, bo VULCAN te funkcje usunął
— naprawiliśmy inne rzeczy u użytkowników eduOne (jak brak opisu oceny czy ładowanie danych na kilku ekranach)
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -93,9 +93,13 @@ class AdsHelper @Inject constructor(
private fun initializeMobileAds() { private fun initializeMobileAds() {
if (isMobileAdsInitializeCalled.getAndSet(true)) return if (isMobileAdsInitializeCalled.getAndSet(true)) return
try {
MobileAds.initialize(context) { MobileAds.initialize(context) {
isMobileAdsSdkInitialized.value = true isMobileAdsSdkInitialized.value = true
} }
} catch (e: Exception) {
Timber.e(e)
}
} }
suspend fun getSupportAd(): RewardedInterstitialAd? { suspend fun getSupportAd(): RewardedInterstitialAd? {

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy
import io.github.wulkanowy.data.WulkanowySdkFactory
import io.github.wulkanowy.sdk.Sdk
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
fun createWulkanowySdkFactoryMock(sdk: Sdk) = mockk<WulkanowySdkFactory>()
.apply {
every { create() } returns sdk
coEvery { create(any(), any()) } returns sdk
}

View File

@ -0,0 +1,129 @@
package io.github.wulkanowy.data
import android.os.Build
import dagger.hilt.android.testing.HiltTestApplication
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.RegisterStudent
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
class WulkanowySdkFactoryTest {
private lateinit var wulkanowySdkFactory: WulkanowySdkFactory
private lateinit var studentDao: StudentDao
private lateinit var sdk: Sdk
@Before
fun setUp() {
sdk = mockk(relaxed = true)
studentDao = mockk()
wulkanowySdkFactory = spyk(
WulkanowySdkFactory(
chuckerInterceptor = mockk(),
remoteConfig = mockk(relaxed = true),
webkitCookieManagerProxy = mockk(),
studentDb = studentDao
)
)
every { wulkanowySdkFactory.create() } returns sdk
}
@Test
fun `check sdk flag isEduOne when local student is eduone`() = runTest {
val student = getStudentEntity().copy(isEduOne = true)
wulkanowySdkFactory.create(student)
verify { sdk.isEduOne = true }
coVerify(exactly = 0) { sdk.getCurrentStudent() }
}
@Test
fun `check sdk flag isEduOne when local student is not eduone`() = runTest {
val student = getStudentEntity().copy(isEduOne = false)
wulkanowySdkFactory.create(student)
verify { sdk.isEduOne = false }
coVerify(exactly = 0) { sdk.getCurrentStudent() }
}
@Test
fun `check sdk flag isEduOne when local student is eduone null and remote student is eduone true`() =
runTest {
val studentToProcess = getStudentEntity().copy(isEduOne = null)
val registerStudent = studentToProcess.toRegisterStudent(isEduOne = true)
coEvery { studentDao.loadById(any()) } returns studentToProcess
coEvery { studentDao.update(any(StudentIsEduOne::class)) } just Runs
coEvery { sdk.getCurrentStudent() } returns registerStudent
wulkanowySdkFactory.create(studentToProcess)
verify { sdk.isEduOne = true }
coVerify { sdk.getCurrentStudent() }
}
@Test
fun `check sdk flag isEduOne when local student is eduone null and remote student is eduone false`() =
runTest {
val studentToProcess = getStudentEntity().copy(isEduOne = null)
val registerStudent = studentToProcess.toRegisterStudent(isEduOne = false)
coEvery { studentDao.loadById(any()) } returns studentToProcess
coEvery { studentDao.update(any(StudentIsEduOne::class)) } just Runs
coEvery { sdk.getCurrentStudent() } returns registerStudent
wulkanowySdkFactory.create(studentToProcess)
verify { sdk.isEduOne = false }
coVerify { sdk.getCurrentStudent() }
}
@Test
fun `check sdk flag isEduOne when sdk getCurrentStudent throws error`() =
runTest {
val studentToProcess = getStudentEntity().copy(isEduOne = null)
coEvery { studentDao.loadById(any()) } returns studentToProcess
coEvery { studentDao.update(any(StudentIsEduOne::class)) } just Runs
coEvery { sdk.getCurrentStudent() } throws Exception()
wulkanowySdkFactory.create(studentToProcess)
verify { sdk.isEduOne = false }
coVerify { sdk.getCurrentStudent() }
}
private fun Student.toRegisterStudent(isEduOne: Boolean) = RegisterStudent(
studentId = studentId,
studentName = studentName,
studentSecondName = studentName,
studentSurname = studentName,
className = className,
classId = classId,
isParent = isParent,
isAuthorized = isAuthorized,
semesters = emptyList(),
isEduOne = isEduOne,
)
}

View File

@ -21,10 +21,10 @@ abstract class AbstractMigrationTest {
@get:Rule @get:Rule
val helper: MigrationTestHelper = MigrationTestHelper( val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(), instrumentation = InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java, databaseClass = AppDatabase::class.java,
listOf(Migration55()), specs = listOf(Migration63()),
FrameworkSQLiteOpenHelperFactory() openFactory = FrameworkSQLiteOpenHelperFactory()
) )
fun runMigrationsAndValidate(migration: Migration) { fun runMigrationsAndValidate(migration: Migration) {

View File

@ -7,8 +7,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
import dagger.hilt.android.testing.HiltAndroidTest import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication import dagger.hilt.android.testing.HiltTestApplication
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.Sdk.ScrapperLoginType.* import io.github.wulkanowy.sdk.Sdk.ScrapperLoginType.ADFSLight
import kotlinx.coroutines.ExperimentalCoroutinesApi import io.github.wulkanowy.sdk.Sdk.ScrapperLoginType.ADFSLightScoped
import io.github.wulkanowy.sdk.Sdk.ScrapperLoginType.STANDARD
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -19,7 +20,6 @@ import kotlin.test.assertEquals
@HiltAndroidTest @HiltAndroidTest
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@OptIn(ExperimentalCoroutinesApi::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class) @Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
class Migration54Test : AbstractMigrationTest() { class Migration54Test : AbstractMigrationTest() {

View File

@ -0,0 +1,89 @@
package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import android.os.Build
import androidx.sqlite.db.SupportSQLiteDatabase
import dagger.hilt.android.testing.HiltAndroidTest
import dagger.hilt.android.testing.HiltTestApplication
import kotlinx.coroutines.test.runTest
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
@HiltAndroidTest
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.O_MR1], application = HiltTestApplication::class)
class Migration63Test : AbstractMigrationTest() {
@Test
fun `update is_edu_one to null if 0`() = runTest {
with(helper.createDatabase(dbName, 62)) {
createStudent(1, 0)
close()
}
helper.runMigrationsAndValidate(dbName, 63, true)
val database = getMigratedRoomDatabase()
val studentDb = database.studentDao
val student = studentDb.loadById(1)
assertNull(student!!.isEduOne)
database.close()
}
@Test
fun `check is_edu_one is stay same`() = runTest {
with(helper.createDatabase(dbName, 62)) {
createStudent(1, 1)
close()
}
helper.runMigrationsAndValidate(dbName, 63, true)
val database = getMigratedRoomDatabase()
val studentDb = database.studentDao
val student = studentDb.loadById(1)
val isEduOne = assertNotNull(student!!.isEduOne)
assertTrue(isEduOne)
database.close()
}
private fun SupportSQLiteDatabase.createStudent(id: Long, isEduOneValue: Int) {
insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("scrapper_base_url", "https://fakelog.cf")
put("mobile_base_url", "")
put("login_type", "SCRAPPER")
put("login_mode", "SCRAPPER")
put("certificate_key", "")
put("private_key", "")
put("is_parent", false)
put("email", "jan@fakelog.cf")
put("password", "******")
put("symbol", "symbol")
put("student_id", Random.nextInt())
put("user_login_id", 123)
put("user_name", "studentName")
put("student_name", "studentName")
put("school_id", "123")
put("school_short", "")
put("school_name", "")
put("class_name", "")
put("class_id", Random.nextInt())
put("is_current", false)
put("registration_date", "0")
put("id", id)
put("nick", "")
put("avatar_color", "")
put("is_edu_one", isEduOneValue)
})
}
}

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
@ -16,8 +17,8 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -30,8 +31,8 @@ import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance
class AttendanceRepositoryTest { class AttendanceRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var attendanceDb: AttendanceDao private lateinit var attendanceDb: AttendanceDao
@ -63,7 +64,8 @@ class AttendanceRepositoryTest {
every { refreshHelper.shouldBeRefreshed(any()) } returns false every { refreshHelper.shouldBeRefreshed(any()) } returns false
coEvery { timetableDb.load(any(), any(), any(), any()) } returns emptyList() coEvery { timetableDb.load(any(), any(), any(), any()) } returns emptyList()
attendanceRepository = AttendanceRepository(attendanceDb, timetableDb, sdk, refreshHelper) attendanceRepository =
AttendanceRepository(attendanceDb, timetableDb, wulkanowySdkFactory, refreshHelper)
} }
@Test @Test

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.errorOrNull import io.github.wulkanowy.data.errorOrNull
@ -15,8 +16,8 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -28,8 +29,8 @@ import io.github.wulkanowy.sdk.pojo.CompletedLesson as SdkCompletedLesson
class CompletedLessonsRepositoryTest { class CompletedLessonsRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var completedLessonDb: CompletedLessonsDao private lateinit var completedLessonDb: CompletedLessonsDao
@ -58,7 +59,7 @@ class CompletedLessonsRepositoryTest {
every { refreshHelper.shouldBeRefreshed(any()) } returns false every { refreshHelper.shouldBeRefreshed(any()) } returns false
completedLessonRepository = completedLessonRepository =
CompletedLessonsRepository(completedLessonDb, sdk, refreshHelper) CompletedLessonsRepository(completedLessonDb, wulkanowySdkFactory, refreshHelper)
} }
@Test @Test

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.errorOrNull import io.github.wulkanowy.data.errorOrNull
@ -15,8 +16,8 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -28,8 +29,8 @@ import io.github.wulkanowy.sdk.pojo.Exam as SdkExam
class ExamRemoteTest { class ExamRemoteTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var examDb: ExamDao private lateinit var examDb: ExamDao
@ -59,7 +60,7 @@ class ExamRemoteTest {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.shouldBeRefreshed(any()) } returns false every { refreshHelper.shouldBeRefreshed(any()) } returns false
examRepository = ExamRepository(examDb, sdk, refreshHelper) examRepository = ExamRepository(examDb, wulkanowySdkFactory, refreshHelper)
} }
@Test @Test

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradeDescriptiveDao import io.github.wulkanowy.data.db.dao.GradeDescriptiveDao
@ -18,8 +19,8 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -35,8 +36,8 @@ import io.github.wulkanowy.sdk.pojo.Grade as SdkGrade
class GradeRepositoryTest { class GradeRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var gradeDb: GradeDao private lateinit var gradeDb: GradeDao
@ -65,7 +66,7 @@ class GradeRepositoryTest {
gradeDb = gradeDb, gradeDb = gradeDb,
gradeSummaryDb = gradeSummaryDb, gradeSummaryDb = gradeSummaryDb,
gradeDescriptiveDb = gradeDescriptiveDb, gradeDescriptiveDb = gradeDescriptiveDb,
sdk = sdk, wulkanowySdkFactory = wulkanowySdkFactory,
refreshHelper = refreshHelper, refreshHelper = refreshHelper,
) )

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
@ -13,9 +14,14 @@ import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.GradeStatisticsItem import io.github.wulkanowy.sdk.pojo.GradeStatisticsItem
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.mockk.* import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -24,8 +30,8 @@ import org.junit.Test
class GradeStatisticsRepositoryTest { class GradeStatisticsRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var gradePartialStatisticsDb: GradePartialStatisticsDao private lateinit var gradePartialStatisticsDb: GradePartialStatisticsDao
@ -54,7 +60,7 @@ class GradeStatisticsRepositoryTest {
gradePartialStatisticsDb = gradePartialStatisticsDb, gradePartialStatisticsDb = gradePartialStatisticsDb,
gradePointsStatisticsDb = gradePointsStatisticsDb, gradePointsStatisticsDb = gradePointsStatisticsDb,
gradeSemesterStatisticsDb = gradeSemesterStatisticsDb, gradeSemesterStatisticsDb = gradeSemesterStatisticsDb,
sdk = sdk, wulkanowySdkFactory = wulkanowySdkFactory,
refreshHelper = refreshHelper, refreshHelper = refreshHelper,
) )
} }

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.LuckyNumberDao import io.github.wulkanowy.data.db.dao.LuckyNumberDao
import io.github.wulkanowy.data.errorOrNull import io.github.wulkanowy.data.errorOrNull
@ -12,8 +13,8 @@ import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -25,8 +26,8 @@ import io.github.wulkanowy.sdk.pojo.LuckyNumber as SdkLuckyNumber
class LuckyNumberRemoteTest { class LuckyNumberRemoteTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var luckyNumberDb: LuckyNumberDao private lateinit var luckyNumberDb: LuckyNumberDao
@ -43,7 +44,7 @@ class LuckyNumberRemoteTest {
fun setUp() { fun setUp() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
luckyNumberRepository = LuckyNumberRepository(luckyNumberDb, sdk) luckyNumberRepository = LuckyNumberRepository(luckyNumberDb, wulkanowySdkFactory)
} }
@Test @Test

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import android.content.Context import android.content.Context
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.dao.MailboxDao import io.github.wulkanowy.data.db.dao.MailboxDao
@ -28,10 +29,9 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import kotlinx.coroutines.ExperimentalCoroutinesApi import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -45,11 +45,10 @@ import java.time.Instant
import java.time.ZoneOffset import java.time.ZoneOffset
import kotlin.test.assertTrue import kotlin.test.assertTrue
@OptIn(ExperimentalCoroutinesApi::class)
class MessageRepositoryTest { class MessageRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var messageDb: MessagesDao private lateinit var messageDb: MessagesDao
@ -102,7 +101,7 @@ class MessageRepositoryTest {
messagesDb = messageDb, messagesDb = messageDb,
mutedMessageSendersDao = mutesDb, mutedMessageSendersDao = mutesDb,
messageAttachmentDao = messageAttachmentDao, messageAttachmentDao = messageAttachmentDao,
sdk = sdk, wulkanowySdkFactory = wulkanowySdkFactory,
context = context, context = context,
refreshHelper = refreshHelper, refreshHelper = refreshHelper,
sharedPrefProvider = sharedPrefProvider, sharedPrefProvider = sharedPrefProvider,

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.MobileDeviceDao import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.errorOrNull import io.github.wulkanowy.data.errorOrNull
@ -16,8 +17,8 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert import org.junit.Assert
@ -28,8 +29,8 @@ import java.time.ZonedDateTime.of
class MobileDeviceRepositoryTest { class MobileDeviceRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var mobileDeviceDb: MobileDeviceDao private lateinit var mobileDeviceDb: MobileDeviceDao
@ -53,7 +54,8 @@ class MobileDeviceRepositoryTest {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.shouldBeRefreshed(any()) } returns false every { refreshHelper.shouldBeRefreshed(any()) } returns false
mobileDeviceRepository = MobileDeviceRepository(mobileDeviceDb, sdk, refreshHelper) mobileDeviceRepository =
MobileDeviceRepository(mobileDeviceDb, wulkanowySdkFactory, refreshHelper)
} }
@Test @Test

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.db.dao.RecipientDao import io.github.wulkanowy.data.db.dao.RecipientDao
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.getMailboxEntity import io.github.wulkanowy.getMailboxEntity
@ -7,9 +8,14 @@ import io.github.wulkanowy.getStudentEntity
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.MailboxType import io.github.wulkanowy.sdk.pojo.MailboxType
import io.github.wulkanowy.utils.AutoRefreshHelper import io.github.wulkanowy.utils.AutoRefreshHelper
import io.mockk.* import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before
@ -18,8 +24,8 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
class RecipientLocalTest { class RecipientLocalTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var recipientDb: RecipientDao private lateinit var recipientDb: RecipientDao
@ -63,7 +69,7 @@ class RecipientLocalTest {
MockKAnnotations.init(this) MockKAnnotations.init(this)
every { refreshHelper.shouldBeRefreshed(any()) } returns false every { refreshHelper.shouldBeRefreshed(any()) } returns false
recipientRepository = RecipientRepository(recipientDb, sdk, refreshHelper) recipientRepository = RecipientRepository(recipientDb, wulkanowySdkFactory, refreshHelper)
} }
@Test @Test

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.TestDispatchersProvider import io.github.wulkanowy.TestDispatchersProvider
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.getSemesterEntity import io.github.wulkanowy.getSemesterEntity
@ -12,8 +13,8 @@ import io.mockk.Runs
import io.mockk.coEvery import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.spyk
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -24,8 +25,8 @@ import java.time.LocalDate.now
class SemesterRepositoryTest { class SemesterRepositoryTest {
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var semesterDb: SemesterDao private lateinit var semesterDb: SemesterDao
@ -38,7 +39,8 @@ class SemesterRepositoryTest {
fun initTest() { fun initTest() {
MockKAnnotations.init(this) MockKAnnotations.init(this)
semesterRepository = SemesterRepository(semesterDb, sdk, TestDispatchersProvider()) semesterRepository =
SemesterRepository(semesterDb, wulkanowySdkFactory, TestDispatchersProvider())
} }
@Test @Test

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.createWulkanowySdkFactoryMock
import io.github.wulkanowy.data.dataOrNull import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
@ -18,9 +19,9 @@ import io.mockk.coEvery
import io.mockk.coVerify import io.mockk.coVerify
import io.mockk.every import io.mockk.every
import io.mockk.impl.annotations.MockK import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.mockk.just import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.spyk
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -37,8 +38,8 @@ class TimetableRepositoryTest {
@MockK(relaxed = true) @MockK(relaxed = true)
private lateinit var timetableNotificationSchedulerHelper: TimetableNotificationSchedulerHelper private lateinit var timetableNotificationSchedulerHelper: TimetableNotificationSchedulerHelper
@SpyK private var sdk = spyk<Sdk>()
private var sdk = Sdk() private val wulkanowySdkFactory = createWulkanowySdkFactoryMock(sdk)
@MockK @MockK
private lateinit var timetableDb: TimetableDao private lateinit var timetableDb: TimetableDao
@ -71,7 +72,7 @@ class TimetableRepositoryTest {
timetableDb, timetableDb,
timetableAdditionalDao, timetableAdditionalDao,
timetableHeaderDao, timetableHeaderDao,
sdk, wulkanowySdkFactory,
timetableNotificationSchedulerHelper, timetableNotificationSchedulerHelper,
refreshHelper refreshHelper
) )