Этап 1: единый OkHttpClient ч.2 — 401 централизован через interceptor
- UnauthorizedInterceptor (401→UnauthorizedException) в NetworkFactory, флаг throwOnUnauthorized (по умолчанию true). - Удалены 75 ручных проверок if(code==401) throw в 16 репозиториях. - AuthVerifier (login-верификация) исключён: throwOnUnauthorized=false — 401 = 'неверный пароль' со своим сообщением, не session-expired. - Побочно: 401 теперь ловится единообразно ВЕЗДЕ (включая пути, что раньше забывали проверку). - +3 MockWebServer-теста (401 бросает; 200/403 проходят) — всего 18 тестов. Проверено: 18 тестов зелёные + assembleRelease BUILD SUCCESSFUL, APK 53 МБ.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Формат: `ГГГГ-ММ-ДД | версия | изменение | контракты | риск`
|
Формат: `ГГГГ-ММ-ДД | версия | изменение | контракты | риск`
|
||||||
|
|
||||||
|
- 2026-07-07 | v0.5.114 (122) | Этап 1 (единый OkHttpClient, ч.2 — 401 централизован): добавлен UnauthorizedInterceptor (401→UnauthorizedException) в NetworkFactory (флаг throwOnUnauthorized, по умолч. true). Удалены 75 ручных проверок `if(code==401) throw` в 16 репозиториях. Login-верификация (AuthVerifier) исключена (throwOnUnauthorized=false: 401=«неверный пароль», не session-expired). Побочно: теперь 401 ловится единообразно ВЕЗДЕ, включая пути, что раньше проверку забывали. +3 теста (MockWebServer: 401 бросает, 200/403 проходят) — всего 18. Проверено сборкой | контракты не менялись; поведение 401 сохранено (interceptor бросает то же исключение) | средний: затрагивает обработку 401 во всех репозиториях; login-путь исключён явно, покрыто тестами
|
||||||
- 2026-07-07 | v0.5.114 (122) | Этап 1 (единый OkHttpClient, ч.1): NetworkFactory переписан — раньше создавал НОВЫЙ OkHttpClient на КАЖДЫЙ запрос (~32 места) → TLS-handshake + новый пул/диспатчер на запрос + утечка ExecutorService. Теперь один базовый клиент (общий ConnectionPool/Dispatcher + диск-кэш 20МБ), авторизованные варианты через base.newBuilder() (шарят пул/кэш), кэшируются по кредам+таймаутам. Публичный API НЕ менялся — 32 вызова не тронуты. Init диск-кэша — F7MobileApp.onCreate. +3 unit-теста (переиспользование клиента, общий пул). 401→interceptor НЕ делал (меняет семантику исключений — отдельный шаг) | контракты не менялись | средний: затрагивает ВСЕ сетевые вызовы (переиспользование соединений); поведение запросов то же, проверено 15 тестами + assembleRelease
|
- 2026-07-07 | v0.5.114 (122) | Этап 1 (единый OkHttpClient, ч.1): NetworkFactory переписан — раньше создавал НОВЫЙ OkHttpClient на КАЖДЫЙ запрос (~32 места) → TLS-handshake + новый пул/диспатчер на запрос + утечка ExecutorService. Теперь один базовый клиент (общий ConnectionPool/Dispatcher + диск-кэш 20МБ), авторизованные варианты через base.newBuilder() (шарят пул/кэш), кэшируются по кредам+таймаутам. Публичный API НЕ менялся — 32 вызова не тронуты. Init диск-кэша — F7MobileApp.onCreate. +3 unit-теста (переиспользование клиента, общий пул). 401→interceptor НЕ делал (меняет семантику исключений — отдельный шаг) | контракты не менялись | средний: затрагивает ВСЕ сетевые вызовы (переиспользование соединений); поведение запросов то же, проверено 15 тестами + assembleRelease
|
||||||
- 2026-07-07 | v0.5.114 (122) | Этап 1 (CI + GPL-публикация): добавлен Gitea Actions workflow .gitea/workflows/ci.yml (push/PR → тесты+lint+assembleDebug; тег v* → подписанный release + архив исходников в Gitea Release) — Gitea 1.26.1 поддерживает Actions. Скрипт scripts/package-source.sh (GPL corresponding source §6: архив всего дерева вкл. vendor GPL/LICENSE/NOTICE — проверен, 6.7 МБ) закрывает п.4c, работает и вручную. docs/CI.md. НЕ активно до регистрации self-hosted раннера на инфре B (нужен Gitea-админ для токена — инфра-шаг) | процесс сборки/релиза | нет: конфиг CI, кода приложения не трогает
|
- 2026-07-07 | v0.5.114 (122) | Этап 1 (CI + GPL-публикация): добавлен Gitea Actions workflow .gitea/workflows/ci.yml (push/PR → тесты+lint+assembleDebug; тег v* → подписанный release + архив исходников в Gitea Release) — Gitea 1.26.1 поддерживает Actions. Скрипт scripts/package-source.sh (GPL corresponding source §6: архив всего дерева вкл. vendor GPL/LICENSE/NOTICE — проверен, 6.7 МБ) закрывает п.4c, работает и вручную. docs/CI.md. НЕ активно до регистрации self-hosted раннера на инфре B (нужен Gitea-админ для токена — инфра-шаг) | процесс сборки/релиза | нет: конфиг CI, кода приложения не трогает
|
||||||
- 2026-07-07 | v0.5.114 (122) | Этап 1 (баги данных, test-first): заведена тестовая инфраструктура (core:network testImplementation junit) + первые 12 unit-тестов. Починено: (1) ICS-парсер дат — суффикс `Z` теперь UTC (был локальным), учитывается TZID, floating→локаль; (2) parseProps сохраняет параметры свойств — несколько ATTENDEE больше НЕ схлопываются, CN/PARTSTAT/ROLE читаются (была порча участников при редактировании→PUT на сервер); (3) unescape single-pass (последовательные replace ломались на `\\n`); (4) CalDavClient.parseIcsInstant делегирует в CalendarIcs — устранён рассинхрон календарь↔задачи; (5) QR-логин: маркер-парсер вместо split('&') — пароль с `&`/`:` больше не теряется; (6) курсор пагинации почты Int→Long (обрезка Unix-времени, ломалось ~2038). Проверено: 12 тестов зелёные + assembleRelease | контракты не менялись; исправлена запись битых ATTENDEE на сервер | низкий: чинит порчу данных, покрыто тестами
|
- 2026-07-07 | v0.5.114 (122) | Этап 1 (баги данных, test-first): заведена тестовая инфраструктура (core:network testImplementation junit) + первые 12 unit-тестов. Починено: (1) ICS-парсер дат — суффикс `Z` теперь UTC (был локальным), учитывается TZID, floating→локаль; (2) parseProps сохраняет параметры свойств — несколько ATTENDEE больше НЕ схлопываются, CN/PARTSTAT/ROLE читаются (была порча участников при редактировании→PUT на сервер); (3) unescape single-pass (последовательные replace ломались на `\\n`); (4) CalDavClient.parseIcsInstant делегирует в CalendarIcs — устранён рассинхрон календарь↔задачи; (5) QR-логин: маркер-парсер вместо split('&') — пароль с `&`/`:` больше не теряется; (6) курсор пагинации почты Int→Long (обрезка Unix-времени, ломалось ~2038). Проверено: 12 тестов зелёные + assembleRelease | контракты не менялись; исправлена запись битых ATTENDEE на сервер | низкий: чинит порчу данных, покрыто тестами
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ object AppMenuRepository {
|
|||||||
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
||||||
return runCatching {
|
return runCatching {
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ object AuthVerifier {
|
|||||||
session.username,
|
session.username,
|
||||||
session.appPassword,
|
session.appPassword,
|
||||||
session.trustAllCerts,
|
session.trustAllCerts,
|
||||||
|
// login-верификация: 401 = «неверный пароль» со своим сообщением, НЕ session-expired
|
||||||
|
throwOnUnauthorized = false,
|
||||||
)
|
)
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url("${session.serverUrl.trimEnd('/')}/ocs/v2.php/cloud/user?format=json")
|
.url("${session.serverUrl.trimEnd('/')}/ocs/v2.php/cloud/user?format=json")
|
||||||
|
|||||||
@@ -22,9 +22,6 @@ object OcsUserResolver {
|
|||||||
.applyOcsJson()
|
.applyOcsJson()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) {
|
|
||||||
throw UnauthorizedException()
|
|
||||||
}
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("User profile HTTP ${response.code}")
|
error("User profile HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,4 +28,5 @@ dependencies {
|
|||||||
api 'com.squareup.okhttp3:okhttp:4.12.0'
|
api 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,6 @@ object CalDavClient {
|
|||||||
.put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType()))
|
.put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("CalDAV create event HTTP ${response.code}")
|
error("CalDAV create event HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -244,7 +243,6 @@ object CalDavClient {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 204 && response.code != 404) {
|
if (response.code !in 200..299 && response.code != 204 && response.code != 404) {
|
||||||
error("CalDAV delete event HTTP ${response.code}")
|
error("CalDAV delete event HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -278,7 +276,6 @@ object CalDavClient {
|
|||||||
builder.header("If-None-Match", "*")
|
builder.header("If-None-Match", "*")
|
||||||
}
|
}
|
||||||
client.newCall(builder.build()).execute().use { response ->
|
client.newCall(builder.build()).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("CalDAV put event HTTP ${response.code}")
|
error("CalDAV put event HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -314,7 +311,6 @@ object CalDavClient {
|
|||||||
.method("MKCALENDAR", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
.method("MKCALENDAR", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("CalDAV create calendar HTTP ${response.code}")
|
error("CalDAV create calendar HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -347,7 +343,6 @@ object CalDavClient {
|
|||||||
.method("MKCOL", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
.method("MKCOL", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("CalDAV subscribe calendar HTTP ${response.code}")
|
error("CalDAV subscribe calendar HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -405,7 +400,6 @@ object CalDavClient {
|
|||||||
.header("Destination", destinationHref)
|
.header("Destination", destinationHref)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("CalDAV move HTTP ${response.code}")
|
error("CalDAV move HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -644,7 +638,6 @@ object CalDavClient {
|
|||||||
.put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType()))
|
.put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("CalDAV create task HTTP ${response.code}")
|
error("CalDAV create task HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -691,7 +684,6 @@ object CalDavClient {
|
|||||||
.put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType()))
|
.put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 204) {
|
||||||
error("CalDAV update task HTTP ${response.code}")
|
error("CalDAV update task HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -705,7 +697,6 @@ object CalDavClient {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 204 && response.code != 404) {
|
if (response.code !in 200..299 && response.code != 204 && response.code != 404) {
|
||||||
error("CalDAV delete task HTTP ${response.code}")
|
error("CalDAV delete task HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -765,7 +756,6 @@ object CalDavClient {
|
|||||||
|
|
||||||
private fun execute(client: OkHttpClient, req: Request): String {
|
private fun execute(client: OkHttpClient, req: Request): String {
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
val code = response.code
|
val code = response.code
|
||||||
if (code !in 200..299 && code != 207) {
|
if (code !in 200..299 && code != 207) {
|
||||||
error("CalDAV error HTTP $code")
|
error("CalDAV error HTTP $code")
|
||||||
|
|||||||
@@ -90,7 +90,6 @@ object CardDavClient {
|
|||||||
.put(vcard.toRequestBody("text/vcard; charset=utf-8".toMediaType()))
|
.put(vcard.toRequestBody("text/vcard; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("Не удалось создать контакт (HTTP ${response.code})")
|
error("Не удалось создать контакт (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
@@ -163,7 +162,6 @@ object CardDavClient {
|
|||||||
.method("PROPFIND", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
.method("PROPFIND", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(req).execute().use { response ->
|
client.newCall(req).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
val code = response.code
|
val code = response.code
|
||||||
if (code !in 200..299 && code != 207) {
|
if (code !in 200..299 && code != 207) {
|
||||||
error("CardDAV error HTTP $code")
|
error("CardDAV error HTTP $code")
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ object DavClient {
|
|||||||
.method("MKCOL", null)
|
.method("MKCOL", null)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) {
|
|
||||||
throw UnauthorizedException()
|
|
||||||
}
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("DAV MKCOL HTTP ${response.code}")
|
error("DAV MKCOL HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -46,9 +43,6 @@ object DavClient {
|
|||||||
.put(body)
|
.put(body)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) {
|
|
||||||
throw UnauthorizedException()
|
|
||||||
}
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("DAV upload HTTP ${response.code}")
|
error("DAV upload HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -76,9 +70,6 @@ object DavClient {
|
|||||||
.method("PROPFIND", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
.method("PROPFIND", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
return client.newCall(request).execute().use { response ->
|
return client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) {
|
|
||||||
throw UnauthorizedException()
|
|
||||||
}
|
|
||||||
val code = response.code
|
val code = response.code
|
||||||
if (code !in 200..299 && code != 207) {
|
if (code !in 200..299 && code != 207) {
|
||||||
error("DAV error HTTP $code")
|
error("DAV error HTTP $code")
|
||||||
@@ -182,7 +173,6 @@ object DavClient {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 204) {
|
||||||
error("DAV DELETE HTTP ${response.code}")
|
error("DAV DELETE HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -197,7 +187,6 @@ object DavClient {
|
|||||||
.header("Overwrite", "T")
|
.header("Overwrite", "T")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
if (response.code !in 200..299 && response.code != 201 && response.code != 204) {
|
||||||
error("DAV MOVE HTTP ${response.code}")
|
error("DAV MOVE HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -221,7 +210,6 @@ object DavClient {
|
|||||||
.method("PROPPATCH", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
.method("PROPPATCH", body.toRequestBody("application/xml; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code !in 200..299 && response.code != 207) {
|
if (response.code !in 200..299 && response.code != 207) {
|
||||||
error("DAV PROPPATCH HTTP ${response.code}")
|
error("DAV PROPPATCH HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ import java.util.concurrent.TimeUnit
|
|||||||
* - авторизованные варианты — через `base.newBuilder()` (шарят пул/диспатчер/кэш);
|
* - авторизованные варианты — через `base.newBuilder()` (шарят пул/диспатчер/кэш);
|
||||||
* - экземпляры кэшируются по кредам+таймаутам → переиспользуются, соединения живут.
|
* - экземпляры кэшируются по кредам+таймаутам → переиспользуются, соединения живут.
|
||||||
*
|
*
|
||||||
* Публичный API НЕ менялся — все вызывающие (`newAuthedClient*`) работают как прежде.
|
* Публичный API совместим — вызывающие (`newAuthedClient*`) работают как прежде.
|
||||||
* NB: 401→UnauthorizedException пока проверяется в репозиториях вручную; централизация
|
* 401→UnauthorizedException централизован через interceptor (`throwOnUnauthorized`, по умолч.
|
||||||
* через interceptor — отдельный шаг (меняет семантику исключений).
|
* true) — ручные проверки в репозиториях убраны. Login-пути (AuthVerifier), где 401 = «неверный
|
||||||
|
* пароль» со своим сообщением, передают `throwOnUnauthorized = false`.
|
||||||
*/
|
*/
|
||||||
object NetworkFactory {
|
object NetworkFactory {
|
||||||
@Volatile
|
@Volatile
|
||||||
@@ -38,8 +39,9 @@ object NetworkFactory {
|
|||||||
trustAllCerts: Boolean = false,
|
trustAllCerts: Boolean = false,
|
||||||
callTimeoutSeconds: Long = 30,
|
callTimeoutSeconds: Long = 30,
|
||||||
readTimeoutSeconds: Long = 30,
|
readTimeoutSeconds: Long = 30,
|
||||||
|
throwOnUnauthorized: Boolean = true,
|
||||||
): OkHttpClient {
|
): OkHttpClient {
|
||||||
val key = "$username|$appPassword|$trustAllCerts|$callTimeoutSeconds|$readTimeoutSeconds"
|
val key = "$username|$appPassword|$trustAllCerts|$callTimeoutSeconds|$readTimeoutSeconds|$throwOnUnauthorized"
|
||||||
return clients.getOrPut(key) {
|
return clients.getOrPut(key) {
|
||||||
base.newBuilder() // общий пул/диспатчер/кэш базового клиента
|
base.newBuilder() // общий пул/диспатчер/кэш базового клиента
|
||||||
.callTimeout(callTimeoutSeconds, TimeUnit.SECONDS)
|
.callTimeout(callTimeoutSeconds, TimeUnit.SECONDS)
|
||||||
@@ -47,6 +49,7 @@ object NetworkFactory {
|
|||||||
.readTimeout(readTimeoutSeconds, TimeUnit.SECONDS)
|
.readTimeout(readTimeoutSeconds, TimeUnit.SECONDS)
|
||||||
.applyUnsafeSslIfNeeded(trustAllCerts)
|
.applyUnsafeSslIfNeeded(trustAllCerts)
|
||||||
.addInterceptor(BasicAuthInterceptor(username, appPassword))
|
.addInterceptor(BasicAuthInterceptor(username, appPassword))
|
||||||
|
.apply { if (throwOnUnauthorized) addInterceptor(UnauthorizedInterceptor) }
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ class NotificationsRepository {
|
|||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Уведомления HTTP ${response.code}")
|
error("Уведомления HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -86,7 +85,6 @@ class NotificationsRepository {
|
|||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
error("Уведомления HTTP ${response.code}")
|
error("Уведомления HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package ru.forbion.f7cloud.core.network
|
||||||
|
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Единая точка обработки 401 для авторизованных запросов: бросает [UnauthorizedException]
|
||||||
|
* (session expired → logout). Заменяет ~70 ручных `if (code == 401) throw ...` по репозиториям.
|
||||||
|
*
|
||||||
|
* Подключается в [NetworkFactory] при `throwOnUnauthorized = true` (по умолчанию). Login-пути
|
||||||
|
* (проверка пароля при входе) НЕ используют этот interceptor — там 401 = «неверный пароль».
|
||||||
|
*/
|
||||||
|
object UnauthorizedInterceptor : Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val response = chain.proceed(chain.request())
|
||||||
|
if (response.code == 401) {
|
||||||
|
response.close() // не течём телом — дальше по цепочке оно не читается
|
||||||
|
throw UnauthorizedException()
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package ru.forbion.f7cloud.core.network
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.mockwebserver.MockResponse
|
||||||
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
/** Централизованная обработка 401: interceptor бросает UnauthorizedException вместо ручных проверок. */
|
||||||
|
class UnauthorizedInterceptorTest {
|
||||||
|
private lateinit var server: MockWebServer
|
||||||
|
|
||||||
|
@Before fun setUp() { server = MockWebServer().apply { start() } }
|
||||||
|
@After fun tearDown() { server.shutdown() }
|
||||||
|
|
||||||
|
private fun call(client: OkHttpClient) =
|
||||||
|
client.newCall(Request.Builder().url(server.url("/x")).build()).execute()
|
||||||
|
|
||||||
|
@Test(expected = UnauthorizedException::class)
|
||||||
|
fun `401 бросает UnauthorizedException`() {
|
||||||
|
server.enqueue(MockResponse().setResponseCode(401))
|
||||||
|
val client = OkHttpClient.Builder().addInterceptor(UnauthorizedInterceptor).build()
|
||||||
|
call(client)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun `не-401 проходит как обычно`() {
|
||||||
|
server.enqueue(MockResponse().setResponseCode(200).setBody("ok"))
|
||||||
|
val client = OkHttpClient.Builder().addInterceptor(UnauthorizedInterceptor).build()
|
||||||
|
call(client).use { assertEquals(200, it.code) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun `403 не трактуется как Unauthorized`() {
|
||||||
|
server.enqueue(MockResponse().setResponseCode(403))
|
||||||
|
val client = OkHttpClient.Builder().addInterceptor(UnauthorizedInterceptor).build()
|
||||||
|
call(client).use { assertEquals(403, it.code) }
|
||||||
|
}
|
||||||
|
}
|
||||||
-4
@@ -46,7 +46,6 @@ class CalendarApiClient {
|
|||||||
.applyOcsJson()
|
.applyOcsJson()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
val json = parseJsonObject(response.body?.string().orEmpty(), "autocomplete attendee")
|
val json = parseJsonObject(response.body?.string().orEmpty(), "autocomplete attendee")
|
||||||
val data = json.optJSONArray("data") ?: json.optJSONObject("ocs")?.optJSONArray("data") ?: return emptyList()
|
val data = json.optJSONArray("data") ?: json.optJSONObject("ocs")?.optJSONArray("data") ?: return emptyList()
|
||||||
return buildList {
|
return buildList {
|
||||||
@@ -77,7 +76,6 @@ class CalendarApiClient {
|
|||||||
.applyOcsJson()
|
.applyOcsJson()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
val json = parseJsonObject(response.body?.string().orEmpty(), "autocomplete location")
|
val json = parseJsonObject(response.body?.string().orEmpty(), "autocomplete location")
|
||||||
val data = json.optJSONArray("data") ?: return emptyList()
|
val data = json.optJSONArray("data") ?: return emptyList()
|
||||||
return buildList {
|
return buildList {
|
||||||
@@ -104,7 +102,6 @@ class CalendarApiClient {
|
|||||||
.applyOcsJson()
|
.applyOcsJson()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Calendar config failed HTTP ${response.code}")
|
if (!response.isSuccessful) error("Calendar config failed HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +121,6 @@ class CalendarApiClient {
|
|||||||
.applyOcsJson()
|
.applyOcsJson()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
val json = parseJsonObject(response.body?.string().orEmpty(), "create talk room")
|
val json = parseJsonObject(response.body?.string().orEmpty(), "create talk room")
|
||||||
val meta = json.ocsMeta()
|
val meta = json.ocsMeta()
|
||||||
if (!isOcsSuccess(meta)) error("Не удалось создать комнату Talk")
|
if (!isOcsSuccess(meta)) error("Не удалось создать комнату Talk")
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ class DeckRepository {
|
|||||||
private fun getJson(client: okhttp3.OkHttpClient, url: String): Any {
|
private fun getJson(client: okhttp3.OkHttpClient, url: String): Any {
|
||||||
val request = Request.Builder().url(url).build()
|
val request = Request.Builder().url(url).build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Deck API HTTP ${response.code}")
|
error("Deck API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
-2
@@ -26,7 +26,6 @@ class SupportRepository {
|
|||||||
.applyOcsJson()
|
.applyOcsJson()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Support config HTTP ${response.code}")
|
error("Support config HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -266,7 +265,6 @@ class SupportRepository {
|
|||||||
.post(payload.toRequestBody("application/json; charset=utf-8".toMediaType()))
|
.post(payload.toRequestBody("application/json; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
val body = response.body?.string().orEmpty()
|
val body = response.body?.string().orEmpty()
|
||||||
val err = runCatching {
|
val err = runCatching {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ class FileDownloadRepository(private val context: Context) {
|
|||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Не удалось скачать файл (HTTP ${response.code})")
|
error("Не удалось скачать файл (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ class FilesApiRepository {
|
|||||||
val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/configs"
|
val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/configs"
|
||||||
val request = Request.Builder().url(url).get().build()
|
val request = Request.Builder().url(url).get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Files config HTTP ${response.code}")
|
error("Files config HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -48,7 +47,6 @@ class FilesApiRepository {
|
|||||||
.put(value.toRequestBody("text/plain".toMediaType()))
|
.put(value.toRequestBody("text/plain".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Files config save HTTP ${response.code}")
|
if (!response.isSuccessful) error("Files config save HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +56,6 @@ class FilesApiRepository {
|
|||||||
val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/stats"
|
val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/stats"
|
||||||
val request = Request.Builder().url(url).get().build()
|
val request = Request.Builder().url(url).get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
return FilesStorageStats()
|
return FilesStorageStats()
|
||||||
}
|
}
|
||||||
@@ -78,7 +75,6 @@ class FilesApiRepository {
|
|||||||
"?path=$encodedPath&depth=$depth&format=json"
|
"?path=$encodedPath&depth=$depth&format=json"
|
||||||
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
@@ -99,7 +95,6 @@ class FilesApiRepository {
|
|||||||
val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/recent/"
|
val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/recent/"
|
||||||
val request = Request.Builder().url(url).get().build()
|
val request = Request.Builder().url(url).get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Recent files HTTP ${response.code}")
|
error("Recent files HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -131,7 +126,6 @@ class FilesApiRepository {
|
|||||||
"?term=$encoded&format=json"
|
"?term=$encoded&format=json"
|
||||||
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
return emptyList()
|
return emptyList()
|
||||||
}
|
}
|
||||||
@@ -188,7 +182,6 @@ class FilesApiRepository {
|
|||||||
.build()
|
.build()
|
||||||
val request = Request.Builder().url(url).applyOcsJson().post(body).build()
|
val request = Request.Builder().url(url).applyOcsJson().post(body).build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Не удалось создать ссылку (HTTP ${response.code})")
|
error("Не удалось создать ссылку (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
@@ -211,7 +204,6 @@ class FilesApiRepository {
|
|||||||
"?path=$encodedPath&reshares=true&format=json"
|
"?path=$encodedPath&reshares=true&format=json"
|
||||||
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) return emptyList()
|
if (!response.isSuccessful || response.body == null) return emptyList()
|
||||||
val root = parseJsonObject(response.body!!.string(), "общий доступ")
|
val root = parseJsonObject(response.body!!.string(), "общий доступ")
|
||||||
val data = root.optJSONObject("ocs")?.opt("data")
|
val data = root.optJSONObject("ocs")?.opt("data")
|
||||||
@@ -247,7 +239,6 @@ class FilesApiRepository {
|
|||||||
"?format=json&object_type=files&object_id=$fileId&limit=50&sort=desc"
|
"?format=json&object_type=files&object_id=$fileId&limit=50&sort=desc"
|
||||||
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
val request = Request.Builder().url(url).applyOcsJson().get().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code == 204 || !response.isSuccessful || response.body == null) return emptyList()
|
if (response.code == 204 || !response.isSuccessful || response.body == null) return emptyList()
|
||||||
val root = parseJsonObject(response.body!!.string(), "события")
|
val root = parseJsonObject(response.body!!.string(), "события")
|
||||||
val data = root.optJSONObject("ocs")?.opt("data")
|
val data = root.optJSONObject("ocs")?.opt("data")
|
||||||
|
|||||||
-3
@@ -29,7 +29,6 @@ class FilesTemplatesRepository {
|
|||||||
.post(body)
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
return client.newCall(request).execute().use { response ->
|
return client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
parseOcsData(response) { data ->
|
parseOcsData(response) { data ->
|
||||||
CreatedFile(
|
CreatedFile(
|
||||||
fileId = data.optLong("fileid"),
|
fileId = data.optLong("fileid"),
|
||||||
@@ -54,7 +53,6 @@ class FilesTemplatesRepository {
|
|||||||
.post(body)
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
return client.newCall(request).execute().use { response ->
|
return client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
parseOcsData(response) { data ->
|
parseOcsData(response) { data ->
|
||||||
data.optString("template_path")
|
data.optString("template_path")
|
||||||
}
|
}
|
||||||
@@ -74,7 +72,6 @@ class FilesTemplatesRepository {
|
|||||||
.post(body)
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
return client.newCall(request).execute().use { response ->
|
return client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
parseOcsData(response) { data ->
|
parseOcsData(response) { data ->
|
||||||
data.optString("url").ifBlank {
|
data.optString("url").ifBlank {
|
||||||
error("Не удалось открыть описание папки")
|
error("Не удалось открыть описание папки")
|
||||||
|
|||||||
-1
@@ -25,7 +25,6 @@ class RichdocumentsRepository {
|
|||||||
.post(body)
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Richdocuments HTTP ${response.code}")
|
error("Richdocuments HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,6 @@ class MailRepository {
|
|||||||
.put(payload.toRequestBody("application/json".toMediaType()))
|
.put(payload.toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Mail API HTTP ${response.code}")
|
error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -141,7 +140,6 @@ class MailRepository {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +158,6 @@ class MailRepository {
|
|||||||
.post(payload.toRequestBody("application/json".toMediaType()))
|
.post(payload.toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Mail API HTTP ${response.code}")
|
error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -178,7 +175,6 @@ class MailRepository {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +217,6 @@ class MailRepository {
|
|||||||
.patch(payload.toString().toRequestBody("application/json".toMediaType()))
|
.patch(payload.toString().toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Mail API HTTP ${response.code}")
|
error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -241,7 +236,6 @@ class MailRepository {
|
|||||||
.put(payload.toRequestBody("application/json".toMediaType()))
|
.put(payload.toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,7 +255,6 @@ class MailRepository {
|
|||||||
.post("".toRequestBody("application/json".toMediaType()))
|
.post("".toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Не удалось отправить (HTTP ${response.code})")
|
if (!response.isSuccessful) error("Не удалось отправить (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,7 +268,6 @@ class MailRepository {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Не удалось удалить (HTTP ${response.code})")
|
if (!response.isSuccessful) error("Не удалось удалить (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,7 +293,6 @@ class MailRepository {
|
|||||||
.put(body.toRequestBody("application/json".toMediaType()))
|
.put(body.toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +307,6 @@ class MailRepository {
|
|||||||
.post("".toRequestBody("application/json".toMediaType()))
|
.post("".toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Не удалось переместить (HTTP ${response.code})")
|
if (!response.isSuccessful) error("Не удалось переместить (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -337,7 +327,6 @@ class MailRepository {
|
|||||||
.post("".toRequestBody("application/json".toMediaType()))
|
.post("".toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Не удалось отложить (HTTP ${response.code})")
|
if (!response.isSuccessful) error("Не удалось отложить (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -358,7 +347,6 @@ class MailRepository {
|
|||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Не удалось изменить метку (HTTP ${response.code})")
|
if (!response.isSuccessful) error("Не удалось изменить метку (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,7 +359,6 @@ class MailRepository {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
if (!response.isSuccessful) error("Mail API HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,7 +374,6 @@ class MailRepository {
|
|||||||
.header("OCS-APIRequest", "true")
|
.header("OCS-APIRequest", "true")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Вложение HTTP ${response.code}")
|
error("Вложение HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -422,7 +408,6 @@ class MailRepository {
|
|||||||
.post(body)
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Не удалось загрузить вложение (HTTP ${response.code})")
|
error("Не удалось загрузить вложение (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
@@ -478,7 +463,6 @@ class MailRepository {
|
|||||||
.post(payload.toString().toRequestBody("application/json".toMediaType()))
|
.post(payload.toString().toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
val messageId = client.newCall(createRequest).execute().use { response ->
|
val messageId = client.newCall(createRequest).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Не удалось создать письмо (HTTP ${response.code})")
|
error("Не удалось создать письмо (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
@@ -495,7 +479,6 @@ class MailRepository {
|
|||||||
.post("".toRequestBody("application/json".toMediaType()))
|
.post("".toRequestBody("application/json".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(sendRequest).execute().use { response ->
|
client.newCall(sendRequest).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
error("Не удалось отправить письмо (HTTP ${response.code})")
|
error("Не удалось отправить письмо (HTTP ${response.code})")
|
||||||
}
|
}
|
||||||
@@ -738,7 +721,6 @@ class MailRepository {
|
|||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code == 412) error("Mail API: CSRF — обновите приложение")
|
if (response.code == 412) error("Mail API: CSRF — обновите приложение")
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Mail API HTTP ${response.code}")
|
error("Mail API HTTP ${response.code}")
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ object TalkAttachmentUploader {
|
|||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) return DEFAULT_ATTACHMENT_FOLDER
|
if (!response.isSuccessful || response.body == null) return DEFAULT_ATTACHMENT_FOLDER
|
||||||
val data = JSONObject(response.body!!.string())
|
val data = JSONObject(response.body!!.string())
|
||||||
.optJSONObject("ocs")
|
.optJSONObject("ocs")
|
||||||
@@ -110,7 +109,6 @@ object TalkAttachmentUploader {
|
|||||||
val url = davFileUrl(session.serverUrl, davUserId, remotePath.trim('/'))
|
val url = davFileUrl(session.serverUrl, davUserId, remotePath.trim('/'))
|
||||||
val request = Request.Builder().url(url).head().build()
|
val request = Request.Builder().url(url).head().build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
return response.isSuccessful
|
return response.isSuccessful
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +134,6 @@ object TalkAttachmentUploader {
|
|||||||
.method("MKCOL", ByteArray(0).toRequestBody(null))
|
.method("MKCOL", ByteArray(0).toRequestBody(null))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
// 405 = already exists
|
// 405 = already exists
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +153,6 @@ object TalkAttachmentUploader {
|
|||||||
.put(bytes.toRequestBody(mediaType))
|
.put(bytes.toRequestBody(mediaType))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
error("Не удалось загрузить файл: HTTP ${response.code}")
|
error("Не удалось загрузить файл: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -190,7 +186,6 @@ object TalkAttachmentUploader {
|
|||||||
.post(body)
|
.post(body)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
error("Не удалось отправить вложение в чат: HTTP ${response.code}")
|
error("Не удалось отправить вложение в чат: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ class TalkRepository {
|
|||||||
.post(payload.toRequestBody("application/json; charset=utf-8".toMediaType()))
|
.post(payload.toRequestBody("application/json; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) {
|
if (!response.isSuccessful) {
|
||||||
error("Talk read marker failed: HTTP ${response.code}")
|
error("Talk read marker failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -166,7 +165,6 @@ class TalkRepository {
|
|||||||
builder.delete()
|
builder.delete()
|
||||||
}
|
}
|
||||||
client.newCall(builder.build()).execute().use { response ->
|
client.newCall(builder.build()).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Talk favorite failed: HTTP ${response.code}")
|
if (!response.isSuccessful) error("Talk favorite failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +179,6 @@ class TalkRepository {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Talk mark unread failed: HTTP ${response.code}")
|
if (!response.isSuccessful) error("Talk mark unread failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +212,6 @@ class TalkRepository {
|
|||||||
.post(payload.toString().toRequestBody("application/json; charset=utf-8".toMediaType()))
|
.post(payload.toString().toRequestBody("application/json; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (response.code != 201 && !response.isSuccessful) {
|
if (response.code != 201 && !response.isSuccessful) {
|
||||||
error("Talk send failed: HTTP ${response.code}")
|
error("Talk send failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -270,7 +266,6 @@ class TalkRepository {
|
|||||||
"DELETE" -> builder.delete()
|
"DELETE" -> builder.delete()
|
||||||
}
|
}
|
||||||
client.newCall(builder.build()).execute().use { response ->
|
client.newCall(builder.build()).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Talk request failed: HTTP ${response.code}")
|
if (!response.isSuccessful) error("Talk request failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,7 +283,6 @@ class TalkRepository {
|
|||||||
.put(body)
|
.put(body)
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Talk edit failed: HTTP ${response.code}")
|
if (!response.isSuccessful) error("Talk edit failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,7 +317,6 @@ class TalkRepository {
|
|||||||
.delete()
|
.delete()
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful) error("Talk delete failed: HTTP ${response.code}")
|
if (!response.isSuccessful) error("Talk delete failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,7 +344,6 @@ class TalkRepository {
|
|||||||
.post(payload.toRequestBody("application/json; charset=utf-8".toMediaType()))
|
.post(payload.toRequestBody("application/json; charset=utf-8".toMediaType()))
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Talk request failed: HTTP ${response.code}")
|
error("Talk request failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
@@ -371,7 +363,6 @@ class TalkRepository {
|
|||||||
.header("Accept", "application/json")
|
.header("Accept", "application/json")
|
||||||
.build()
|
.build()
|
||||||
client.newCall(request).execute().use { response ->
|
client.newCall(request).execute().use { response ->
|
||||||
if (response.code == 401) throw UnauthorizedException()
|
|
||||||
if (!response.isSuccessful || response.body == null) {
|
if (!response.isSuccessful || response.body == null) {
|
||||||
error("Talk request failed: HTTP ${response.code}")
|
error("Talk request failed: HTTP ${response.code}")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user