ref: removing api calls to separate functions
This commit is contained in:
parent
654acf1b77
commit
1286860d55
99
app/src/main/java/ru/sweetbread/unn/api/API.kt
Normal file
99
app/src/main/java/ru/sweetbread/unn/api/API.kt
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2025. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.sweetbread.unn.api
|
||||
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.withContext
|
||||
import ru.sweetbread.unn.db.cacheSchedule
|
||||
import ru.sweetbread.unn.db.loadSchedule
|
||||
import ru.sweetbread.unn.ui.layout.LoginData
|
||||
import java.time.LocalDate
|
||||
|
||||
|
||||
lateinit var PHPSESSID: String
|
||||
lateinit var CSRF: String
|
||||
lateinit var ME: User
|
||||
|
||||
|
||||
/**
|
||||
* Authorize user by [login] and [password]
|
||||
*
|
||||
* Also defines local vars [PHPSESSID] and [ME]
|
||||
*/
|
||||
suspend fun auth(
|
||||
login: String = LoginData.login,
|
||||
password: String = LoginData.password,
|
||||
forced: Boolean = false
|
||||
): Boolean {
|
||||
if (!forced) {
|
||||
if (::PHPSESSID.isInitialized and ::ME.isInitialized)
|
||||
return true
|
||||
}
|
||||
val id = getToken(login, password)
|
||||
if (id != null) {
|
||||
PHPSESSID = id
|
||||
getMyself(login)
|
||||
getCSRF()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Save info about current [User] in memory
|
||||
*/
|
||||
private suspend fun getMyself(login: String) = coroutineScope {
|
||||
val idDeferred = async { getId(login) }
|
||||
val userDeferred = async { getUser() }
|
||||
|
||||
val id = idDeferred.await()
|
||||
val user = userDeferred.await()
|
||||
|
||||
ME = User(
|
||||
unnId = id,
|
||||
userId = user.userId,
|
||||
type = Type.student,
|
||||
email = user.email,
|
||||
nameRu = user.nameRu,
|
||||
nameEn = user.nameEn,
|
||||
isMale = user.isMale,
|
||||
birthday = user.birthday,
|
||||
avatar = user.avatar
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getScheduleDay(
|
||||
type: Type = ME.type,
|
||||
id: Int = ME.unnId!!,
|
||||
date: LocalDate
|
||||
): ArrayList<ScheduleUnit> {
|
||||
|
||||
if ((type == ME.type) and (id == ME.unnId!!)) {
|
||||
val schedule = withContext(Dispatchers.IO) { loadSchedule(date) }
|
||||
Log.d("Schedule", schedule.joinToString())
|
||||
if (schedule.isNotEmpty())
|
||||
return schedule
|
||||
}
|
||||
|
||||
return getSchedule(type, id, date, date)
|
||||
}
|
||||
|
||||
suspend fun getSchedule(
|
||||
type: Type = ME.type,
|
||||
id: Int = ME.unnId!!,
|
||||
start: LocalDate,
|
||||
finish: LocalDate
|
||||
): ArrayList<ScheduleUnit> {
|
||||
val schedule = downloadSchedule(type, id, start, finish)
|
||||
|
||||
if ((type == ME.type) and (id == ME.unnId!!))
|
||||
cacheSchedule(schedule)
|
||||
|
||||
return schedule
|
||||
}
|
@ -3,9 +3,17 @@
|
||||
* Copyright (c) 2025. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.sweetbread.unn
|
||||
package ru.sweetbread.unn.api
|
||||
|
||||
import android.util.Log
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.android.Android
|
||||
import io.ktor.client.plugins.HttpRequestRetry
|
||||
import io.ktor.client.plugins.HttpTimeout
|
||||
import io.ktor.client.plugins.cache.HttpCache
|
||||
import io.ktor.client.plugins.logging.LogLevel
|
||||
import io.ktor.client.plugins.logging.Logger
|
||||
import io.ktor.client.plugins.logging.Logging
|
||||
import io.ktor.client.request.forms.submitForm
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.header
|
||||
@ -16,13 +24,8 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import ru.sweetbread.unn.db.cacheSchedule
|
||||
import ru.sweetbread.unn.db.cacheUser
|
||||
import ru.sweetbread.unn.db.loadSchedule
|
||||
import ru.sweetbread.unn.db.loadUserByBitrixId
|
||||
import ru.sweetbread.unn.ui.layout.LoginData
|
||||
import ru.sweetbread.unn.ui.layout.client
|
||||
import splitties.resources.appStr
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
@ -31,10 +34,6 @@ import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
|
||||
private lateinit var PHPSESSID: String
|
||||
private lateinit var CSRF: String
|
||||
lateinit var ME: User
|
||||
|
||||
const val portalURL = "https://portal.unn.ru"
|
||||
const val ruzapiURL = "$portalURL/ruzapi"
|
||||
const val vuzapiURL = "$portalURL/bitrix/vuz/api"
|
||||
@ -42,110 +41,29 @@ const val prtl2URL = "$portalURL/portal2/api"
|
||||
const val restURL = "$portalURL/rest"
|
||||
|
||||
|
||||
enum class Type(val s: String) {
|
||||
Student(appStr(R.string.student)),
|
||||
Group("group"),
|
||||
Lecturer(appStr(R.string.lecturer)),
|
||||
Auditorium("auditorium"),
|
||||
Employee(appStr(R.string.employee))
|
||||
}
|
||||
|
||||
enum class LecturerRank(val id: Int) {
|
||||
Assistant(R.string.assistant),
|
||||
Lecturer(R.string.lecturer),
|
||||
SLecturer(R.string.slecturer),
|
||||
AProfessor(R.string.aprofessor)
|
||||
}
|
||||
|
||||
class ScheduleUnit(
|
||||
val oid: Int,
|
||||
val auditorium: Auditorium,
|
||||
val date: LocalDate,
|
||||
val discipline: Discipline,
|
||||
val kindOfWork: KindOfWork,
|
||||
val lecturers: ArrayList<Lecturer>,
|
||||
val stream: String,
|
||||
val begin: LocalTime,
|
||||
val end: LocalTime
|
||||
)
|
||||
|
||||
class Auditorium(
|
||||
val name: String,
|
||||
val oid: Int,
|
||||
val floor: Int,
|
||||
val building: Building
|
||||
)
|
||||
|
||||
class Building(
|
||||
val name: String,
|
||||
val gid: Int,
|
||||
val oid: Int
|
||||
)
|
||||
|
||||
class Discipline(
|
||||
val name: String,
|
||||
val oid: Int,
|
||||
val type: Int
|
||||
)
|
||||
|
||||
class KindOfWork(
|
||||
val name: String,
|
||||
val oid: Int,
|
||||
val uid: String,
|
||||
val complexity: Int
|
||||
)
|
||||
|
||||
class Lecturer(
|
||||
val name: String,
|
||||
val rank: LecturerRank,
|
||||
val email: String,
|
||||
val unnId: Int,
|
||||
val uid: String
|
||||
)
|
||||
|
||||
class User(
|
||||
val unnId: Int?,
|
||||
val bitrixId: Int,
|
||||
val userId: Int,
|
||||
val type: Type,
|
||||
val email: String,
|
||||
val nameRu: String,
|
||||
val nameEn: String,
|
||||
val isMale: Boolean,
|
||||
val birthday: LocalDate,
|
||||
val avatar: AvatarSet
|
||||
)
|
||||
|
||||
class Post(
|
||||
val id: Int,
|
||||
val authorId: Int,
|
||||
val enableComments: Boolean,
|
||||
val numComments: Int,
|
||||
val date: LocalDateTime,
|
||||
val content: String
|
||||
)
|
||||
|
||||
class AvatarSet(
|
||||
val original: String,
|
||||
val thumbnail: String,
|
||||
val small: String
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* Authorize user by [login] and [password]
|
||||
*
|
||||
* Also defines local vars [PHPSESSID] and [ME]
|
||||
*/
|
||||
suspend fun auth(
|
||||
login: String = LoginData.login,
|
||||
password: String = LoginData.password,
|
||||
forced: Boolean = false
|
||||
): Boolean {
|
||||
if (!forced) {
|
||||
if (::PHPSESSID.isInitialized and ::ME.isInitialized)
|
||||
return true
|
||||
val client = HttpClient(Android) {
|
||||
install(HttpCache)
|
||||
install(Logging) {
|
||||
logger = object : Logger {
|
||||
override fun log(message: String) {
|
||||
Log.i("Ktor", message)
|
||||
}
|
||||
}
|
||||
level = LogLevel.ALL
|
||||
}
|
||||
install(HttpTimeout) {
|
||||
connectTimeoutMillis = 5000
|
||||
}
|
||||
install(HttpRequestRetry) {
|
||||
retryOnException(maxRetries = 3, retryOnTimeout = true)
|
||||
exponentialDelay()
|
||||
modifyRequest { request ->
|
||||
request.headers.append("x-retry-count", retryCount.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getToken(login: String, password: String): String? {
|
||||
val r = client.submitForm("$portalURL/auth/?login=yes",
|
||||
formParameters = parameters {
|
||||
append("AUTH_FORM", "Y")
|
||||
@ -155,52 +73,43 @@ suspend fun auth(
|
||||
append("USER_PASSWORD", password)
|
||||
}
|
||||
)
|
||||
if (r.status.value == 302) {
|
||||
PHPSESSID =
|
||||
"""PHPSESSID=([\w\d]+)""".toRegex().find(r.headers["Set-Cookie"]!!)!!.groupValues[1]
|
||||
getMyself(login)
|
||||
getCSRF()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
if (r.status.value == 302)
|
||||
return """PHPSESSID=([\w\d]+)""".toRegex().find(r.headers["Set-Cookie"]!!)!!.groupValues[1]
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Save info about current [User] in memory
|
||||
*/
|
||||
private suspend fun getMyself(login: String) {
|
||||
// WARNING: trailing / is important, 'cuz API devs are eating shit
|
||||
// TODO: make up another way to get unnId: this is not useful for lectures
|
||||
val studentinfo = JSONObject(client.get("$ruzapiURL/studentinfo/") {
|
||||
suspend fun getId(login: String): Int {
|
||||
return JSONObject(client.get("$ruzapiURL/studentinfo/") {
|
||||
header("Cookie", "PHPSESSID=$PHPSESSID")
|
||||
parameter("uns", login.drop(1))
|
||||
}.bodyAsText())
|
||||
}.bodyAsText()).getString("id").toInt()
|
||||
}
|
||||
|
||||
val user = JSONObject(
|
||||
client.get("$vuzapiURL/user") {
|
||||
suspend fun getUser(userId: Int? = null): User {
|
||||
// WARNING: trailing / is important, 'cuz API devs are eating shit
|
||||
// TODO: make up another way to get unnId: this is not useful for lectures
|
||||
val json = JSONObject(
|
||||
client.get("$vuzapiURL/user/${userId ?: ""}") {
|
||||
header("Cookie", "PHPSESSID=$PHPSESSID")
|
||||
}.bodyAsText()
|
||||
)
|
||||
|
||||
Log.d("studentInfo", studentinfo.toString(2))
|
||||
|
||||
ME = User(
|
||||
unnId = studentinfo.getString("id").toInt(),
|
||||
bitrixId = user.getInt("bitrix_id"), // TODO: remove
|
||||
userId = user.getInt("id"),
|
||||
type = when (studentinfo.getString("type")) {
|
||||
"lecturer" -> Type.Lecturer // ig,,,
|
||||
else -> Type.Student
|
||||
},
|
||||
email = user.getString("email"),
|
||||
nameRu = user.getString("fullname"),
|
||||
nameEn = user.getString("fullname_en"),
|
||||
isMale = user.getString("sex") == "M",
|
||||
return User(
|
||||
unnId = null,
|
||||
userId = json.getInt("id"),
|
||||
type = if (json.getJSONArray("profiles").getJSONObject(0)
|
||||
.getString("type") == "employee"
|
||||
) Type.employee else Type.student,
|
||||
email = json.getString("email"),
|
||||
nameRu = json.getString("fullname"),
|
||||
nameEn = json.getString("fullname_en"),
|
||||
isMale = json.getString("sex") == "M",
|
||||
birthday = Instant
|
||||
.parse(user.getString("birthdate"))
|
||||
.parse(json.getString("birthdate"))
|
||||
.atZone(ZoneId.of("Europe/Moscow"))
|
||||
.toLocalDate(),
|
||||
avatar = user.getJSONObject("photo").let {
|
||||
avatar = json.getJSONObject("photo").let {
|
||||
AvatarSet(
|
||||
it.getString("orig"),
|
||||
it.getString("thumbnail"),
|
||||
@ -210,23 +119,7 @@ private suspend fun getMyself(login: String) {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getScheduleDay(
|
||||
type: Type = ME.type,
|
||||
id: Int = ME.unnId!!,
|
||||
date: LocalDate
|
||||
): ArrayList<ScheduleUnit> {
|
||||
|
||||
if ((type == ME.type) and (id == ME.unnId!!)) {
|
||||
val schedule = withContext(Dispatchers.IO) { loadSchedule(date) }
|
||||
Log.d("Schedule", schedule.joinToString())
|
||||
if (schedule.isNotEmpty())
|
||||
return schedule
|
||||
}
|
||||
|
||||
return getSchedule(type, id, date, date)
|
||||
}
|
||||
|
||||
suspend fun getSchedule(
|
||||
suspend fun downloadSchedule(
|
||||
type: Type = ME.type,
|
||||
id: Int = ME.unnId!!,
|
||||
start: LocalDate,
|
||||
@ -234,13 +127,13 @@ suspend fun getSchedule(
|
||||
): ArrayList<ScheduleUnit> {
|
||||
val unnDatePattern = DateTimeFormatter.ofPattern("yyyy-MM-dd")
|
||||
|
||||
val r = client.get("$ruzapiURL/schedule/${type.s}/$id") {
|
||||
val r = client.get("$ruzapiURL/schedule/${type.name}/$id") {
|
||||
parameter("start", start.format(unnDatePattern))
|
||||
parameter("finish", finish.format(unnDatePattern))
|
||||
parameter("lng", "1")
|
||||
}
|
||||
val json = JSONArray(r.bodyAsText())
|
||||
|
||||
val json = JSONArray(r.bodyAsText())
|
||||
val out = arrayListOf<ScheduleUnit>()
|
||||
for (i in 0 until json.length()) {
|
||||
val unit = json.getJSONObject(i)
|
||||
@ -304,9 +197,6 @@ suspend fun getSchedule(
|
||||
)
|
||||
}
|
||||
|
||||
if ((type == ME.type) and (id == ME.unnId!!)) {
|
||||
cacheSchedule(out)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@ -318,6 +208,23 @@ suspend fun getCSRF() {
|
||||
CSRF = JSONObject(r.bodyAsText()).getString("sessid")
|
||||
}
|
||||
|
||||
suspend fun getUserByBitrixId(id: Int): User {
|
||||
withContext(Dispatchers.IO) {
|
||||
loadUserByBitrixId(id)
|
||||
}?.let { return it }
|
||||
|
||||
val userId = JSONObject(client.get("$vuzapiURL/user/bx/$id") {
|
||||
header("Cookie", "PHPSESSID=$PHPSESSID")
|
||||
}.bodyAsText()).getInt("id")
|
||||
|
||||
getUser(userId).let { user ->
|
||||
withContext(Dispatchers.IO) {
|
||||
cacheUser(user)
|
||||
}
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getBlogposts(): ArrayList<Post> {
|
||||
val r = client.get("$prtl2URL/news.php") {
|
||||
header("Cookie", "PHPSESSID=$PHPSESSID")
|
||||
@ -344,54 +251,3 @@ suspend fun getBlogposts(): ArrayList<Post> {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
suspend fun getUserByBitrixId(id: Int): User {
|
||||
withContext(Dispatchers.IO) {
|
||||
loadUserByBitrixId(id)
|
||||
}?.let { return it }
|
||||
|
||||
val userId = JSONObject(client.get("$vuzapiURL/user/bx/$id") {
|
||||
header("Cookie", "PHPSESSID=$PHPSESSID")
|
||||
}.bodyAsText()).getInt("id")
|
||||
|
||||
getUser(userId).let { user ->
|
||||
withContext(Dispatchers.IO) {
|
||||
cacheUser(user)
|
||||
}
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getUser(id: Int): User {
|
||||
val json = JSONObject(
|
||||
client.get("$vuzapiURL/user/$id") {
|
||||
header("Cookie", "PHPSESSID=$PHPSESSID")
|
||||
}.bodyAsText()
|
||||
)
|
||||
|
||||
Log.d("type", json.getJSONArray("profiles").getJSONObject(0).getString("type"))
|
||||
|
||||
return User(
|
||||
unnId = null,
|
||||
bitrixId = json.getInt("bitrix_id"),
|
||||
userId = json.getInt("id"),
|
||||
type = if (json.getJSONArray("profiles").getJSONObject(0)
|
||||
.getString("type") == "employee"
|
||||
) Type.Employee else Type.Student,
|
||||
email = json.getString("email"),
|
||||
nameRu = json.getString("fullname"),
|
||||
nameEn = json.getString("fullname_en"),
|
||||
isMale = json.getString("sex") == "M",
|
||||
birthday = Instant
|
||||
.parse(json.getString("birthdate"))
|
||||
.atZone(ZoneId.of("Europe/Moscow"))
|
||||
.toLocalDate(),
|
||||
avatar = json.getJSONObject("photo").let {
|
||||
AvatarSet(
|
||||
it.getString("orig"),
|
||||
it.getString("thumbnail"),
|
||||
it.getString("small"),
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
100
app/src/main/java/ru/sweetbread/unn/api/models.kt
Normal file
100
app/src/main/java/ru/sweetbread/unn/api/models.kt
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2025. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.sweetbread.unn.api
|
||||
|
||||
import ru.sweetbread.unn.R
|
||||
import splitties.resources.appStr
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
|
||||
enum class Type(val s: String) {
|
||||
student(appStr(R.string.student)),
|
||||
group("group"),
|
||||
lecturer(appStr(R.string.lecturer)),
|
||||
auditorium("auditorium"),
|
||||
employee(appStr(R.string.employee))
|
||||
}
|
||||
|
||||
enum class LecturerRank(val id: Int) {
|
||||
Assistant(R.string.assistant),
|
||||
Lecturer(R.string.lecturer),
|
||||
SLecturer(R.string.slecturer),
|
||||
AProfessor(R.string.aprofessor)
|
||||
}
|
||||
|
||||
class ScheduleUnit(
|
||||
val oid: Int,
|
||||
val auditorium: Auditorium,
|
||||
val date: LocalDate,
|
||||
val discipline: Discipline,
|
||||
val kindOfWork: KindOfWork,
|
||||
val lecturers: ArrayList<Lecturer>,
|
||||
val stream: String,
|
||||
val begin: LocalTime,
|
||||
val end: LocalTime
|
||||
)
|
||||
|
||||
class Auditorium(
|
||||
val name: String,
|
||||
val oid: Int,
|
||||
val floor: Int,
|
||||
val building: Building
|
||||
)
|
||||
|
||||
class Building(
|
||||
val name: String,
|
||||
val gid: Int,
|
||||
val oid: Int
|
||||
)
|
||||
|
||||
class Discipline(
|
||||
val name: String,
|
||||
val oid: Int,
|
||||
val type: Int
|
||||
)
|
||||
|
||||
class KindOfWork(
|
||||
val name: String,
|
||||
val oid: Int,
|
||||
val uid: String,
|
||||
val complexity: Int
|
||||
)
|
||||
|
||||
class Lecturer(
|
||||
val name: String,
|
||||
val rank: LecturerRank,
|
||||
val email: String,
|
||||
val unnId: Int,
|
||||
val uid: String
|
||||
)
|
||||
|
||||
class User(
|
||||
val unnId: Int?,
|
||||
val userId: Int,
|
||||
val type: Type,
|
||||
val email: String,
|
||||
val nameRu: String,
|
||||
val nameEn: String,
|
||||
val isMale: Boolean,
|
||||
val birthday: LocalDate,
|
||||
val avatar: AvatarSet
|
||||
)
|
||||
|
||||
class Post(
|
||||
val id: Int,
|
||||
val authorId: Int,
|
||||
val enableComments: Boolean,
|
||||
val numComments: Int,
|
||||
val date: LocalDateTime,
|
||||
val content: String
|
||||
)
|
||||
|
||||
class AvatarSet(
|
||||
val original: String,
|
||||
val thumbnail: String,
|
||||
val small: String
|
||||
)
|
@ -1,7 +1,17 @@
|
||||
/*
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2025. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.sweetbread.unn.db
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import splitties.arch.room.roomDb
|
||||
|
||||
val cacheDb = roomDb<AppDatabase>(name = "cache") {
|
||||
fallbackToDestructiveMigration(dropAllTables = true)
|
||||
}
|
||||
|
||||
@Database(entities = [
|
||||
UserDB::class,
|
||||
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2025. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.sweetbread.unn.db
|
||||
|
||||
import android.util.Log
|
||||
@ -9,14 +14,13 @@ import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.Query
|
||||
import ru.sweetbread.unn.Auditorium
|
||||
import ru.sweetbread.unn.Building
|
||||
import ru.sweetbread.unn.Discipline
|
||||
import ru.sweetbread.unn.KindOfWork
|
||||
import ru.sweetbread.unn.Lecturer
|
||||
import ru.sweetbread.unn.LecturerRank
|
||||
import ru.sweetbread.unn.ScheduleUnit
|
||||
import ru.sweetbread.unn.ui.layout.db
|
||||
import ru.sweetbread.unn.api.Auditorium
|
||||
import ru.sweetbread.unn.api.Building
|
||||
import ru.sweetbread.unn.api.Discipline
|
||||
import ru.sweetbread.unn.api.KindOfWork
|
||||
import ru.sweetbread.unn.api.Lecturer
|
||||
import ru.sweetbread.unn.api.LecturerRank
|
||||
import ru.sweetbread.unn.api.ScheduleUnit
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
@ -43,7 +47,7 @@ interface BuildingDao {
|
||||
}
|
||||
|
||||
fun cacheBuilding(building: Building) {
|
||||
db.buildingDao().insert(
|
||||
cacheDb.buildingDao().insert(
|
||||
BuildingDB(
|
||||
building.oid,
|
||||
building.name,
|
||||
@ -54,13 +58,13 @@ fun cacheBuilding(building: Building) {
|
||||
}
|
||||
|
||||
fun loadBuilding(oid: Int): Building? {
|
||||
return db.buildingDao().get(oid)?.let {
|
||||
return cacheDb.buildingDao().get(oid)?.let {
|
||||
if (LocalDateTime.parse(
|
||||
it.expiredAt,
|
||||
DateTimeFormatter.ISO_DATE_TIME
|
||||
) > LocalDateTime.now()
|
||||
) {
|
||||
db.buildingDao().delete(it)
|
||||
cacheDb.buildingDao().delete(it)
|
||||
return null
|
||||
}
|
||||
Building(
|
||||
@ -94,7 +98,7 @@ interface AuditoriumDao {
|
||||
|
||||
fun cacheAuditorium(auditorium: Auditorium) {
|
||||
cacheBuilding(auditorium.building)
|
||||
db.auditoriumDao().insert(
|
||||
cacheDb.auditoriumDao().insert(
|
||||
AuditoriumDB(
|
||||
auditorium.oid,
|
||||
auditorium.name,
|
||||
@ -106,13 +110,13 @@ fun cacheAuditorium(auditorium: Auditorium) {
|
||||
}
|
||||
|
||||
fun loadAuditorium(oid: Int): Auditorium? {
|
||||
return db.auditoriumDao().get(oid)?.let {
|
||||
return cacheDb.auditoriumDao().get(oid)?.let {
|
||||
if (LocalDateTime.parse(
|
||||
it.expiredAt,
|
||||
DateTimeFormatter.ISO_DATE_TIME
|
||||
) > LocalDateTime.now()
|
||||
) {
|
||||
db.auditoriumDao().delete(it)
|
||||
cacheDb.auditoriumDao().delete(it)
|
||||
return null
|
||||
}
|
||||
val building = loadBuilding(it.buildingOid) ?: return null
|
||||
@ -146,7 +150,7 @@ interface DisciplineDao {
|
||||
}
|
||||
|
||||
fun cacheDiscipline(discipline: Discipline) {
|
||||
db.disciplineDao().insert(
|
||||
cacheDb.disciplineDao().insert(
|
||||
DisciplineDB(
|
||||
discipline.oid,
|
||||
discipline.name,
|
||||
@ -157,13 +161,13 @@ fun cacheDiscipline(discipline: Discipline) {
|
||||
}
|
||||
|
||||
fun loadDiscipline(oid: Int): Discipline? {
|
||||
return db.disciplineDao().get(oid)?.let {
|
||||
return cacheDb.disciplineDao().get(oid)?.let {
|
||||
if (LocalDateTime.parse(
|
||||
it.expiredAt,
|
||||
DateTimeFormatter.ISO_DATE_TIME
|
||||
) > LocalDateTime.now()
|
||||
) {
|
||||
db.disciplineDao().delete(it)
|
||||
cacheDb.disciplineDao().delete(it)
|
||||
return null
|
||||
}
|
||||
|
||||
@ -197,7 +201,7 @@ interface KindOfWorkDao {
|
||||
}
|
||||
|
||||
fun cacheKindOfWork(kindOfWork: KindOfWork) {
|
||||
db.kindOfWorkDao().insert(
|
||||
cacheDb.kindOfWorkDao().insert(
|
||||
KindOfWorkDB(
|
||||
kindOfWork.oid,
|
||||
kindOfWork.name,
|
||||
@ -209,13 +213,13 @@ fun cacheKindOfWork(kindOfWork: KindOfWork) {
|
||||
}
|
||||
|
||||
fun loadKindOfWork(oid: Int): KindOfWork? {
|
||||
return db.kindOfWorkDao().get(oid)?.let {
|
||||
return cacheDb.kindOfWorkDao().get(oid)?.let {
|
||||
if (LocalDateTime.parse(
|
||||
it.expiredAt,
|
||||
DateTimeFormatter.ISO_DATE_TIME
|
||||
) > LocalDateTime.now()
|
||||
) {
|
||||
db.kindOfWorkDao().delete(it)
|
||||
cacheDb.kindOfWorkDao().delete(it)
|
||||
return null
|
||||
}
|
||||
|
||||
@ -251,7 +255,7 @@ interface LecturerDao {
|
||||
}
|
||||
|
||||
fun cacheLecturer(lecturer: Lecturer) {
|
||||
db.lecturerDao().insert(
|
||||
cacheDb.lecturerDao().insert(
|
||||
LecturerDB(
|
||||
lecturer.unnId,
|
||||
lecturer.name,
|
||||
@ -264,13 +268,13 @@ fun cacheLecturer(lecturer: Lecturer) {
|
||||
}
|
||||
|
||||
fun loadLecturer(unnId: Int): Lecturer? {
|
||||
return db.lecturerDao().get(unnId)?.let {
|
||||
return cacheDb.lecturerDao().get(unnId)?.let {
|
||||
if (LocalDateTime.parse(
|
||||
it.expiredAt,
|
||||
DateTimeFormatter.ISO_DATE_TIME
|
||||
) > LocalDateTime.now()
|
||||
) {
|
||||
db.lecturerDao().delete(it)
|
||||
cacheDb.lecturerDao().delete(it)
|
||||
return null
|
||||
}
|
||||
|
||||
@ -320,7 +324,7 @@ fun cacheSchedule(item: ScheduleUnit) {
|
||||
cacheKindOfWork(item.kindOfWork)
|
||||
cacheLecturer(item.lecturers[0])
|
||||
|
||||
db.scheduleDao().insert(
|
||||
cacheDb.scheduleDao().insert(
|
||||
ScheduleUnitDB(
|
||||
item.oid,
|
||||
item.date.format(DateTimeFormatter.ISO_DATE),
|
||||
@ -347,7 +351,7 @@ fun cacheSchedule(items: ArrayList<ScheduleUnit>) {
|
||||
}
|
||||
|
||||
fun loadSchedule(oid: Int): ScheduleUnit? {
|
||||
db.scheduleDao().getSchedule(oid)?.let {
|
||||
cacheDb.scheduleDao().getSchedule(oid)?.let {
|
||||
Log.d("load", it.oid.toString())
|
||||
if (LocalDateTime.parse(
|
||||
it.expiredAt,
|
||||
@ -355,7 +359,7 @@ fun loadSchedule(oid: Int): ScheduleUnit? {
|
||||
) < LocalDateTime.now()
|
||||
) {
|
||||
Log.d("delete", it.oid.toString())
|
||||
db.scheduleDao().delete(it)
|
||||
cacheDb.scheduleDao().delete(it)
|
||||
return null
|
||||
}
|
||||
|
||||
@ -375,10 +379,10 @@ fun loadSchedule(oid: Int): ScheduleUnit? {
|
||||
}
|
||||
|
||||
fun loadSchedule(date: LocalDate): ArrayList<ScheduleUnit> {
|
||||
db.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE))
|
||||
cacheDb.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE))
|
||||
.map { Log.d("meow", "${it.oid}: ${loadSchedule(it.oid)}") }
|
||||
return ArrayList(
|
||||
db.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE))
|
||||
cacheDb.scheduleDao().getSchedule(date.format(DateTimeFormatter.ISO_DATE))
|
||||
.mapNotNull { loadSchedule(it.oid) }
|
||||
)
|
||||
}
|
@ -1,3 +1,8 @@
|
||||
/*
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2025. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.sweetbread.unn.db
|
||||
|
||||
import android.util.Log
|
||||
@ -8,10 +13,9 @@ import androidx.room.Entity
|
||||
import androidx.room.Insert
|
||||
import androidx.room.PrimaryKey
|
||||
import androidx.room.Query
|
||||
import ru.sweetbread.unn.AvatarSet
|
||||
import ru.sweetbread.unn.Type
|
||||
import ru.sweetbread.unn.User
|
||||
import ru.sweetbread.unn.ui.layout.db
|
||||
import ru.sweetbread.unn.api.AvatarSet
|
||||
import ru.sweetbread.unn.api.Type
|
||||
import ru.sweetbread.unn.api.User
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
@ -20,7 +24,6 @@ import java.time.format.DateTimeFormatter
|
||||
data class UserDB(
|
||||
@PrimaryKey val userId: Int,
|
||||
@ColumnInfo val unnId: Int?,
|
||||
@ColumnInfo val bitrixId: Int,
|
||||
@ColumnInfo val type: Type,
|
||||
@ColumnInfo val email: String,
|
||||
@ColumnInfo val nameRu: String,
|
||||
@ -35,8 +38,8 @@ data class UserDB(
|
||||
|
||||
@Dao
|
||||
interface UserDao {
|
||||
@Query("SELECT * FROM userDB WHERE bitrixId = :bitrixId LIMIT 1")
|
||||
fun getUserByBitrix(bitrixId: Int): UserDB?
|
||||
@Query("SELECT * FROM userDB WHERE userId = :userId LIMIT 1")
|
||||
fun getUserById(userId: Int): UserDB?
|
||||
|
||||
@Insert
|
||||
fun insert(user: UserDB)
|
||||
@ -48,11 +51,10 @@ interface UserDao {
|
||||
|
||||
fun cacheUser(user: User) {
|
||||
try {
|
||||
db.userDao().insert(
|
||||
cacheDb.userDao().insert(
|
||||
UserDB(
|
||||
user.userId,
|
||||
user.unnId,
|
||||
user.bitrixId,
|
||||
user.type,
|
||||
user.email,
|
||||
user.nameRu,
|
||||
@ -70,7 +72,7 @@ fun cacheUser(user: User) {
|
||||
}
|
||||
|
||||
fun loadUserByBitrixId(bitrixId: Int): User? {
|
||||
val user = db.userDao().getUserByBitrix(bitrixId)
|
||||
val user = cacheDb.userDao().getUserById(bitrixId)
|
||||
Log.d("UserDB", user?.nameEn ?: "None")
|
||||
if (user == null) return null
|
||||
if (LocalDateTime.parse(
|
||||
@ -78,12 +80,11 @@ fun loadUserByBitrixId(bitrixId: Int): User? {
|
||||
DateTimeFormatter.ISO_LOCAL_DATE_TIME
|
||||
) < LocalDateTime.now()
|
||||
) {
|
||||
db.userDao().delete(user)
|
||||
cacheDb.userDao().delete(user)
|
||||
return null
|
||||
} else {
|
||||
return User(
|
||||
user.unnId,
|
||||
user.bitrixId,
|
||||
user.userId,
|
||||
user.type,
|
||||
user.email,
|
||||
|
@ -55,14 +55,14 @@ import coil.request.ImageRequest
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import ru.sweetbread.unn.AvatarSet
|
||||
import ru.sweetbread.unn.Post
|
||||
import ru.sweetbread.unn.R
|
||||
import ru.sweetbread.unn.Type
|
||||
import ru.sweetbread.unn.User
|
||||
import ru.sweetbread.unn.getBlogposts
|
||||
import ru.sweetbread.unn.getUserByBitrixId
|
||||
import ru.sweetbread.unn.portalURL
|
||||
import ru.sweetbread.unn.api.AvatarSet
|
||||
import ru.sweetbread.unn.api.Post
|
||||
import ru.sweetbread.unn.api.Type
|
||||
import ru.sweetbread.unn.api.User
|
||||
import ru.sweetbread.unn.api.getBlogposts
|
||||
import ru.sweetbread.unn.api.getUserByBitrixId
|
||||
import ru.sweetbread.unn.api.portalURL
|
||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
@ -73,8 +73,7 @@ import java.time.format.FormatStyle
|
||||
val defUser = User(
|
||||
null,
|
||||
123,
|
||||
123,
|
||||
Type.Student,
|
||||
Type.student,
|
||||
"cool.email@domain.com",
|
||||
"Джон Сигма Омегович",
|
||||
"Jon Sigma Omega",
|
||||
@ -241,7 +240,9 @@ fun UserItemPreview() {
|
||||
Modifier
|
||||
.width(300.dp)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(MaterialTheme.colorScheme.primaryContainer), defUser, Type.Student.s
|
||||
.background(MaterialTheme.colorScheme.primaryContainer),
|
||||
defUser,
|
||||
Type.student.s
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -55,15 +55,15 @@ import com.kizitonwose.calendar.core.WeekDay
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.sweetbread.unn.Auditorium
|
||||
import ru.sweetbread.unn.Building
|
||||
import ru.sweetbread.unn.Discipline
|
||||
import ru.sweetbread.unn.KindOfWork
|
||||
import ru.sweetbread.unn.Lecturer
|
||||
import ru.sweetbread.unn.LecturerRank
|
||||
import ru.sweetbread.unn.R
|
||||
import ru.sweetbread.unn.ScheduleUnit
|
||||
import ru.sweetbread.unn.getScheduleDay
|
||||
import ru.sweetbread.unn.api.Auditorium
|
||||
import ru.sweetbread.unn.api.Building
|
||||
import ru.sweetbread.unn.api.Discipline
|
||||
import ru.sweetbread.unn.api.KindOfWork
|
||||
import ru.sweetbread.unn.api.Lecturer
|
||||
import ru.sweetbread.unn.api.LecturerRank
|
||||
import ru.sweetbread.unn.api.ScheduleUnit
|
||||
import ru.sweetbread.unn.api.getScheduleDay
|
||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||
import splitties.resources.appStr
|
||||
import splitties.resources.appStrArray
|
||||
|
@ -44,7 +44,7 @@ import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import ru.sweetbread.unn.R
|
||||
import ru.sweetbread.unn.auth
|
||||
import ru.sweetbread.unn.api.auth
|
||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||
import splitties.activities.start
|
||||
import splitties.preferences.Preferences
|
||||
|
@ -6,7 +6,6 @@
|
||||
package ru.sweetbread.unn.ui.layout
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.background
|
||||
@ -60,50 +59,16 @@ import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import coil.compose.AsyncImage
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.android.Android
|
||||
import io.ktor.client.plugins.HttpRequestRetry
|
||||
import io.ktor.client.plugins.HttpTimeout
|
||||
import io.ktor.client.plugins.cache.HttpCache
|
||||
import io.ktor.client.plugins.logging.LogLevel
|
||||
import io.ktor.client.plugins.logging.Logger
|
||||
import io.ktor.client.plugins.logging.Logging
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.sweetbread.unn.ME
|
||||
import ru.sweetbread.unn.R
|
||||
import ru.sweetbread.unn.db.AppDatabase
|
||||
import ru.sweetbread.unn.portalURL
|
||||
import ru.sweetbread.unn.api.ME
|
||||
import ru.sweetbread.unn.api.portalURL
|
||||
import ru.sweetbread.unn.ui.composes.Blogposts
|
||||
import ru.sweetbread.unn.ui.composes.Schedule
|
||||
import ru.sweetbread.unn.ui.theme.UNNTheme
|
||||
import splitties.arch.room.roomDb
|
||||
import splitties.resources.appStr
|
||||
import splitties.toast.toast
|
||||
|
||||
val client = HttpClient(Android) {
|
||||
install(HttpCache)
|
||||
install(Logging) {
|
||||
logger = object : Logger {
|
||||
override fun log(message: String) {
|
||||
Log.i("Ktor", message)
|
||||
}
|
||||
}
|
||||
level = LogLevel.ALL
|
||||
}
|
||||
install(HttpTimeout) {
|
||||
connectTimeoutMillis = 5000
|
||||
}
|
||||
install(HttpRequestRetry) {
|
||||
retryOnException(maxRetries = 3, retryOnTimeout = true)
|
||||
exponentialDelay()
|
||||
modifyRequest { request ->
|
||||
request.headers.append("x-retry-count", retryCount.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val db = roomDb<AppDatabase>(name = "database")
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
Loading…
x
Reference in New Issue
Block a user