diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e13329..9fd836f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 (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 на сервер | низкий: чинит порчу данных, покрыто тестами diff --git a/app/src/main/java/ru/forbion/f7cloud/mobile/ui/AppMenuRepository.kt b/app/src/main/java/ru/forbion/f7cloud/mobile/ui/AppMenuRepository.kt index 4810194..220f592 100644 --- a/app/src/main/java/ru/forbion/f7cloud/mobile/ui/AppMenuRepository.kt +++ b/app/src/main/java/ru/forbion/f7cloud/mobile/ui/AppMenuRepository.kt @@ -19,7 +19,6 @@ object AppMenuRepository { val request = Request.Builder().url(url).applyOcsJson().get().build() return runCatching { client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { return emptyList() } diff --git a/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/AuthVerifier.kt b/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/AuthVerifier.kt index 9d70b84..0fd6794 100644 --- a/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/AuthVerifier.kt +++ b/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/AuthVerifier.kt @@ -18,6 +18,8 @@ object AuthVerifier { session.username, session.appPassword, session.trustAllCerts, + // login-верификация: 401 = «неверный пароль» со своим сообщением, НЕ session-expired + throwOnUnauthorized = false, ) val request = Request.Builder() .url("${session.serverUrl.trimEnd('/')}/ocs/v2.php/cloud/user?format=json") diff --git a/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/OcsUserResolver.kt b/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/OcsUserResolver.kt index 61401bf..3aadd45 100644 --- a/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/OcsUserResolver.kt +++ b/core/auth/src/main/java/ru/forbion/f7cloud/core/auth/OcsUserResolver.kt @@ -22,9 +22,6 @@ object OcsUserResolver { .applyOcsJson() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) { - throw UnauthorizedException() - } if (!response.isSuccessful || response.body == null) { error("User profile HTTP ${response.code}") } diff --git a/core/network/build.gradle b/core/network/build.gradle index e4eeb9a..739b055 100644 --- a/core/network/build.gradle +++ b/core/network/build.gradle @@ -28,4 +28,5 @@ dependencies { api 'com.squareup.okhttp3:okhttp:4.12.0' testImplementation 'junit:junit:4.13.2' + testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0' } diff --git a/core/network/src/main/java/ru/forbion/f7cloud/core/network/CalDavClient.kt b/core/network/src/main/java/ru/forbion/f7cloud/core/network/CalDavClient.kt index 415d006..280400a 100644 --- a/core/network/src/main/java/ru/forbion/f7cloud/core/network/CalDavClient.kt +++ b/core/network/src/main/java/ru/forbion/f7cloud/core/network/CalDavClient.kt @@ -189,7 +189,6 @@ object CalDavClient { .put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("CalDAV create event HTTP ${response.code}") } @@ -244,7 +243,6 @@ object CalDavClient { .delete() .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 204 && response.code != 404) { error("CalDAV delete event HTTP ${response.code}") } @@ -278,7 +276,6 @@ object CalDavClient { builder.header("If-None-Match", "*") } 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) { error("CalDAV put event HTTP ${response.code}") } @@ -314,7 +311,6 @@ object CalDavClient { .method("MKCALENDAR", body.toRequestBody("application/xml; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("CalDAV create calendar HTTP ${response.code}") } @@ -347,7 +343,6 @@ object CalDavClient { .method("MKCOL", body.toRequestBody("application/xml; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("CalDAV subscribe calendar HTTP ${response.code}") } @@ -405,7 +400,6 @@ object CalDavClient { .header("Destination", destinationHref) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("CalDAV move HTTP ${response.code}") } @@ -644,7 +638,6 @@ object CalDavClient { .put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("CalDAV create task HTTP ${response.code}") } @@ -691,7 +684,6 @@ object CalDavClient { .put(ics.toRequestBody("text/calendar; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 204) { error("CalDAV update task HTTP ${response.code}") } @@ -705,7 +697,6 @@ object CalDavClient { .delete() .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 204 && response.code != 404) { error("CalDAV delete task HTTP ${response.code}") } @@ -765,7 +756,6 @@ object CalDavClient { private fun execute(client: OkHttpClient, req: Request): String { client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() val code = response.code if (code !in 200..299 && code != 207) { error("CalDAV error HTTP $code") diff --git a/core/network/src/main/java/ru/forbion/f7cloud/core/network/CardDavClient.kt b/core/network/src/main/java/ru/forbion/f7cloud/core/network/CardDavClient.kt index 1b3dd30..2a95432 100644 --- a/core/network/src/main/java/ru/forbion/f7cloud/core/network/CardDavClient.kt +++ b/core/network/src/main/java/ru/forbion/f7cloud/core/network/CardDavClient.kt @@ -90,7 +90,6 @@ object CardDavClient { .put(vcard.toRequestBody("text/vcard; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("Не удалось создать контакт (HTTP ${response.code})") } @@ -163,7 +162,6 @@ object CardDavClient { .method("PROPFIND", body.toRequestBody("application/xml; charset=utf-8".toMediaType())) .build() client.newCall(req).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() val code = response.code if (code !in 200..299 && code != 207) { error("CardDAV error HTTP $code") diff --git a/core/network/src/main/java/ru/forbion/f7cloud/core/network/DavClient.kt b/core/network/src/main/java/ru/forbion/f7cloud/core/network/DavClient.kt index 4dcf45c..8db4251 100644 --- a/core/network/src/main/java/ru/forbion/f7cloud/core/network/DavClient.kt +++ b/core/network/src/main/java/ru/forbion/f7cloud/core/network/DavClient.kt @@ -27,9 +27,6 @@ object DavClient { .method("MKCOL", null) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) { - throw UnauthorizedException() - } if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("DAV MKCOL HTTP ${response.code}") } @@ -46,9 +43,6 @@ object DavClient { .put(body) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) { - throw UnauthorizedException() - } if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("DAV upload HTTP ${response.code}") } @@ -76,9 +70,6 @@ object DavClient { .method("PROPFIND", body.toRequestBody("application/xml; charset=utf-8".toMediaType())) .build() return client.newCall(request).execute().use { response -> - if (response.code == 401) { - throw UnauthorizedException() - } val code = response.code if (code !in 200..299 && code != 207) { error("DAV error HTTP $code") @@ -182,7 +173,6 @@ object DavClient { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 204) { error("DAV DELETE HTTP ${response.code}") } @@ -197,7 +187,6 @@ object DavClient { .header("Overwrite", "T") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 201 && response.code != 204) { error("DAV MOVE HTTP ${response.code}") } @@ -221,7 +210,6 @@ object DavClient { .method("PROPPATCH", body.toRequestBody("application/xml; charset=utf-8".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code !in 200..299 && response.code != 207) { error("DAV PROPPATCH HTTP ${response.code}") } diff --git a/core/network/src/main/java/ru/forbion/f7cloud/core/network/NetworkFactory.kt b/core/network/src/main/java/ru/forbion/f7cloud/core/network/NetworkFactory.kt index bc4bfa4..9694143 100644 --- a/core/network/src/main/java/ru/forbion/f7cloud/core/network/NetworkFactory.kt +++ b/core/network/src/main/java/ru/forbion/f7cloud/core/network/NetworkFactory.kt @@ -14,9 +14,10 @@ import java.util.concurrent.TimeUnit * - авторизованные варианты — через `base.newBuilder()` (шарят пул/диспатчер/кэш); * - экземпляры кэшируются по кредам+таймаутам → переиспользуются, соединения живут. * - * Публичный API НЕ менялся — все вызывающие (`newAuthedClient*`) работают как прежде. - * NB: 401→UnauthorizedException пока проверяется в репозиториях вручную; централизация - * через interceptor — отдельный шаг (меняет семантику исключений). + * Публичный API совместим — вызывающие (`newAuthedClient*`) работают как прежде. + * 401→UnauthorizedException централизован через interceptor (`throwOnUnauthorized`, по умолч. + * true) — ручные проверки в репозиториях убраны. Login-пути (AuthVerifier), где 401 = «неверный + * пароль» со своим сообщением, передают `throwOnUnauthorized = false`. */ object NetworkFactory { @Volatile @@ -38,8 +39,9 @@ object NetworkFactory { trustAllCerts: Boolean = false, callTimeoutSeconds: Long = 30, readTimeoutSeconds: Long = 30, + throwOnUnauthorized: Boolean = true, ): OkHttpClient { - val key = "$username|$appPassword|$trustAllCerts|$callTimeoutSeconds|$readTimeoutSeconds" + val key = "$username|$appPassword|$trustAllCerts|$callTimeoutSeconds|$readTimeoutSeconds|$throwOnUnauthorized" return clients.getOrPut(key) { base.newBuilder() // общий пул/диспатчер/кэш базового клиента .callTimeout(callTimeoutSeconds, TimeUnit.SECONDS) @@ -47,6 +49,7 @@ object NetworkFactory { .readTimeout(readTimeoutSeconds, TimeUnit.SECONDS) .applyUnsafeSslIfNeeded(trustAllCerts) .addInterceptor(BasicAuthInterceptor(username, appPassword)) + .apply { if (throwOnUnauthorized) addInterceptor(UnauthorizedInterceptor) } .build() } } diff --git a/core/network/src/main/java/ru/forbion/f7cloud/core/network/NotificationsRepository.kt b/core/network/src/main/java/ru/forbion/f7cloud/core/network/NotificationsRepository.kt index 8ec64a8..b3458f7 100644 --- a/core/network/src/main/java/ru/forbion/f7cloud/core/network/NotificationsRepository.kt +++ b/core/network/src/main/java/ru/forbion/f7cloud/core/network/NotificationsRepository.kt @@ -30,7 +30,6 @@ class NotificationsRepository { .header("Accept", "application/json") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Уведомления HTTP ${response.code}") } @@ -86,7 +85,6 @@ class NotificationsRepository { .header("Accept", "application/json") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) { error("Уведомления HTTP ${response.code}") } diff --git a/core/network/src/main/java/ru/forbion/f7cloud/core/network/UnauthorizedInterceptor.kt b/core/network/src/main/java/ru/forbion/f7cloud/core/network/UnauthorizedInterceptor.kt new file mode 100644 index 0000000..0320d15 --- /dev/null +++ b/core/network/src/main/java/ru/forbion/f7cloud/core/network/UnauthorizedInterceptor.kt @@ -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 + } +} diff --git a/core/network/src/test/java/ru/forbion/f7cloud/core/network/UnauthorizedInterceptorTest.kt b/core/network/src/test/java/ru/forbion/f7cloud/core/network/UnauthorizedInterceptorTest.kt new file mode 100644 index 0000000..5405ae0 --- /dev/null +++ b/core/network/src/test/java/ru/forbion/f7cloud/core/network/UnauthorizedInterceptorTest.kt @@ -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) } + } +} diff --git a/feature/calendar/src/main/java/ru/forbion/f7cloud/feature/calendar/CalendarApiClient.kt b/feature/calendar/src/main/java/ru/forbion/f7cloud/feature/calendar/CalendarApiClient.kt index 62222f8..a579eda 100644 --- a/feature/calendar/src/main/java/ru/forbion/f7cloud/feature/calendar/CalendarApiClient.kt +++ b/feature/calendar/src/main/java/ru/forbion/f7cloud/feature/calendar/CalendarApiClient.kt @@ -46,7 +46,6 @@ class CalendarApiClient { .applyOcsJson() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() val json = parseJsonObject(response.body?.string().orEmpty(), "autocomplete attendee") val data = json.optJSONArray("data") ?: json.optJSONObject("ocs")?.optJSONArray("data") ?: return emptyList() return buildList { @@ -77,7 +76,6 @@ class CalendarApiClient { .applyOcsJson() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() val json = parseJsonObject(response.body?.string().orEmpty(), "autocomplete location") val data = json.optJSONArray("data") ?: return emptyList() return buildList { @@ -104,7 +102,6 @@ class CalendarApiClient { .applyOcsJson() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Calendar config failed HTTP ${response.code}") } } @@ -124,7 +121,6 @@ class CalendarApiClient { .applyOcsJson() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() val json = parseJsonObject(response.body?.string().orEmpty(), "create talk room") val meta = json.ocsMeta() if (!isOcsSuccess(meta)) error("Не удалось создать комнату Talk") diff --git a/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckRepository.kt b/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckRepository.kt index 0cd37cb..4799e76 100644 --- a/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckRepository.kt +++ b/feature/deck/src/main/java/ru/forbion/f7cloud/feature/deck/DeckRepository.kt @@ -79,7 +79,6 @@ class DeckRepository { private fun getJson(client: okhttp3.OkHttpClient, url: String): Any { val request = Request.Builder().url(url).build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Deck API HTTP ${response.code}") } diff --git a/feature/f7support/src/main/java/ru/forbion/f7cloud/feature/f7support/SupportRepository.kt b/feature/f7support/src/main/java/ru/forbion/f7cloud/feature/f7support/SupportRepository.kt index 2b5c86e..3454cf9 100644 --- a/feature/f7support/src/main/java/ru/forbion/f7cloud/feature/f7support/SupportRepository.kt +++ b/feature/f7support/src/main/java/ru/forbion/f7cloud/feature/f7support/SupportRepository.kt @@ -26,7 +26,6 @@ class SupportRepository { .applyOcsJson() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Support config HTTP ${response.code}") } @@ -266,7 +265,6 @@ class SupportRepository { .post(payload.toRequestBody("application/json; charset=utf-8".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) { val body = response.body?.string().orEmpty() val err = runCatching { diff --git a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FileDownloadRepository.kt b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FileDownloadRepository.kt index 7faa2c6..09586ee 100644 --- a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FileDownloadRepository.kt +++ b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FileDownloadRepository.kt @@ -24,7 +24,6 @@ class FileDownloadRepository(private val context: Context) { .get() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Не удалось скачать файл (HTTP ${response.code})") } diff --git a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesApiRepository.kt b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesApiRepository.kt index a20b0e6..533b10a 100644 --- a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesApiRepository.kt +++ b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesApiRepository.kt @@ -22,7 +22,6 @@ class FilesApiRepository { val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/configs" val request = Request.Builder().url(url).get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Files config HTTP ${response.code}") } @@ -48,7 +47,6 @@ class FilesApiRepository { .put(value.toRequestBody("text/plain".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() 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 request = Request.Builder().url(url).get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { return FilesStorageStats() } @@ -78,7 +75,6 @@ class FilesApiRepository { "?path=$encodedPath&depth=$depth&format=json" val request = Request.Builder().url(url).applyOcsJson().get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { return emptyList() } @@ -99,7 +95,6 @@ class FilesApiRepository { val url = "${session.serverUrl.trimEnd('/')}/index.php/apps/files/api/v1/recent/" val request = Request.Builder().url(url).get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Recent files HTTP ${response.code}") } @@ -131,7 +126,6 @@ class FilesApiRepository { "?term=$encoded&format=json" val request = Request.Builder().url(url).applyOcsJson().get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { return emptyList() } @@ -188,7 +182,6 @@ class FilesApiRepository { .build() val request = Request.Builder().url(url).applyOcsJson().post(body).build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Не удалось создать ссылку (HTTP ${response.code})") } @@ -211,7 +204,6 @@ class FilesApiRepository { "?path=$encodedPath&reshares=true&format=json" val request = Request.Builder().url(url).applyOcsJson().get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) return emptyList() val root = parseJsonObject(response.body!!.string(), "общий доступ") 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" val request = Request.Builder().url(url).applyOcsJson().get().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code == 204 || !response.isSuccessful || response.body == null) return emptyList() val root = parseJsonObject(response.body!!.string(), "события") val data = root.optJSONObject("ocs")?.opt("data") diff --git a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesTemplatesRepository.kt b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesTemplatesRepository.kt index 0ddf7b8..69eaa7a 100644 --- a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesTemplatesRepository.kt +++ b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesTemplatesRepository.kt @@ -29,7 +29,6 @@ class FilesTemplatesRepository { .post(body) .build() return client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() parseOcsData(response) { data -> CreatedFile( fileId = data.optLong("fileid"), @@ -54,7 +53,6 @@ class FilesTemplatesRepository { .post(body) .build() return client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() parseOcsData(response) { data -> data.optString("template_path") } @@ -74,7 +72,6 @@ class FilesTemplatesRepository { .post(body) .build() return client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() parseOcsData(response) { data -> data.optString("url").ifBlank { error("Не удалось открыть описание папки") diff --git a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/RichdocumentsRepository.kt b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/RichdocumentsRepository.kt index 83ccce7..0b0323d 100644 --- a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/RichdocumentsRepository.kt +++ b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/RichdocumentsRepository.kt @@ -25,7 +25,6 @@ class RichdocumentsRepository { .post(body) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Richdocuments HTTP ${response.code}") } diff --git a/feature/mail/src/main/java/ru/forbion/f7cloud/feature/mail/MailRepository.kt b/feature/mail/src/main/java/ru/forbion/f7cloud/feature/mail/MailRepository.kt index e362fa8..331c4d9 100644 --- a/feature/mail/src/main/java/ru/forbion/f7cloud/feature/mail/MailRepository.kt +++ b/feature/mail/src/main/java/ru/forbion/f7cloud/feature/mail/MailRepository.kt @@ -121,7 +121,6 @@ class MailRepository { .put(payload.toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Mail API HTTP ${response.code}") } @@ -141,7 +140,6 @@ class MailRepository { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Mail API HTTP ${response.code}") } } @@ -160,7 +158,6 @@ class MailRepository { .post(payload.toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Mail API HTTP ${response.code}") } @@ -178,7 +175,6 @@ class MailRepository { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Mail API HTTP ${response.code}") } } @@ -221,7 +217,6 @@ class MailRepository { .patch(payload.toString().toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Mail API HTTP ${response.code}") } @@ -241,7 +236,6 @@ class MailRepository { .put(payload.toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Mail API HTTP ${response.code}") } } @@ -261,7 +255,6 @@ class MailRepository { .post("".toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Не удалось отправить (HTTP ${response.code})") } } @@ -275,7 +268,6 @@ class MailRepository { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Не удалось удалить (HTTP ${response.code})") } } @@ -301,7 +293,6 @@ class MailRepository { .put(body.toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Mail API HTTP ${response.code}") } } @@ -316,7 +307,6 @@ class MailRepository { .post("".toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Не удалось переместить (HTTP ${response.code})") } } @@ -337,7 +327,6 @@ class MailRepository { .post("".toRequestBody("application/json".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Не удалось отложить (HTTP ${response.code})") } } @@ -358,7 +347,6 @@ class MailRepository { } .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Не удалось изменить метку (HTTP ${response.code})") } } @@ -371,7 +359,6 @@ class MailRepository { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Mail API HTTP ${response.code}") } } @@ -387,7 +374,6 @@ class MailRepository { .header("OCS-APIRequest", "true") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Вложение HTTP ${response.code}") } @@ -422,7 +408,6 @@ class MailRepository { .post(body) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Не удалось загрузить вложение (HTTP ${response.code})") } @@ -478,7 +463,6 @@ class MailRepository { .post(payload.toString().toRequestBody("application/json".toMediaType())) .build() val messageId = client.newCall(createRequest).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Не удалось создать письмо (HTTP ${response.code})") } @@ -495,7 +479,6 @@ class MailRepository { .post("".toRequestBody("application/json".toMediaType())) .build() client.newCall(sendRequest).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) { error("Не удалось отправить письмо (HTTP ${response.code})") } @@ -738,7 +721,6 @@ class MailRepository { .header("Accept", "application/json") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code == 412) error("Mail API: CSRF — обновите приложение") if (!response.isSuccessful || response.body == null) { error("Mail API HTTP ${response.code}") diff --git a/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkAttachmentUploader.kt b/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkAttachmentUploader.kt index 1720123..292f470 100644 --- a/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkAttachmentUploader.kt +++ b/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkAttachmentUploader.kt @@ -59,7 +59,6 @@ object TalkAttachmentUploader { .header("Accept", "application/json") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) return DEFAULT_ATTACHMENT_FOLDER val data = JSONObject(response.body!!.string()) .optJSONObject("ocs") @@ -110,7 +109,6 @@ object TalkAttachmentUploader { val url = davFileUrl(session.serverUrl, davUserId, remotePath.trim('/')) val request = Request.Builder().url(url).head().build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() return response.isSuccessful } } @@ -136,7 +134,6 @@ object TalkAttachmentUploader { .method("MKCOL", ByteArray(0).toRequestBody(null)) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() // 405 = already exists } } @@ -156,7 +153,6 @@ object TalkAttachmentUploader { .put(bytes.toRequestBody(mediaType)) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) { error("Не удалось загрузить файл: HTTP ${response.code}") } @@ -190,7 +186,6 @@ object TalkAttachmentUploader { .post(body) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) { error("Не удалось отправить вложение в чат: HTTP ${response.code}") } diff --git a/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkRepository.kt b/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkRepository.kt index 84f6601..033ae2b 100644 --- a/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkRepository.kt +++ b/feature/talk/src/main/java/ru/forbion/f7cloud/feature/talk/TalkRepository.kt @@ -56,7 +56,6 @@ class TalkRepository { .post(payload.toRequestBody("application/json; charset=utf-8".toMediaType())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) { error("Talk read marker failed: HTTP ${response.code}") } @@ -166,7 +165,6 @@ class TalkRepository { builder.delete() } client.newCall(builder.build()).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Talk favorite failed: HTTP ${response.code}") } } @@ -181,7 +179,6 @@ class TalkRepository { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() 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())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (response.code != 201 && !response.isSuccessful) { error("Talk send failed: HTTP ${response.code}") } @@ -270,7 +266,6 @@ class TalkRepository { "DELETE" -> builder.delete() } client.newCall(builder.build()).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Talk request failed: HTTP ${response.code}") } } @@ -288,7 +283,6 @@ class TalkRepository { .put(body) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful) error("Talk edit failed: HTTP ${response.code}") } } @@ -323,7 +317,6 @@ class TalkRepository { .delete() .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() 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())) .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Talk request failed: HTTP ${response.code}") } @@ -371,7 +363,6 @@ class TalkRepository { .header("Accept", "application/json") .build() client.newCall(request).execute().use { response -> - if (response.code == 401) throw UnauthorizedException() if (!response.isSuccessful || response.body == null) { error("Talk request failed: HTTP ${response.code}") }