Compare commits

..
1 Commits
4 changed files with 57 additions and 7 deletions
+9
View File
@@ -1,4 +1,13 @@
const lunarisChangelog = [
LunarisChange(
version: '2.3.9',
title: 'Исправление входа и синхронизации аккаунтов Pawchive',
bullets: [
'Исправлены API эндпоинты Pawchive: пути запросов избранных авторов и управления подписками приведены в соответствие со спецификацией API v1 (/api/v1/account/favorites, /api/v1/favorites/creator/...).',
'Устранена ошибка 404: авторизация по логину и паролю, а также по session cookie теперь успешно завершается и сразу синхронизирует всех авторов.',
'Информативные ошибки: понятные сообщения на русском при неверном пароле или сбое сети вместо сырых исключений Dio.',
],
),
LunarisChange(
version: '2.3.8',
title: 'ABI-Aware Auto-Update — правильный APK для вашего процессора',
@@ -3,7 +3,6 @@ import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/http/dio_client.dart';
import '../di/backend_providers.dart';
import '../models/favorite_artist_item.dart';
import '../models/pawchive_account.dart';
import 'settings_service.dart';
@@ -98,10 +97,25 @@ class PawchiveSyncService {
}
// Check if redirect points back to login with flash error
if (redirectLocation.contains('/account/login')) {
if (redirectLocation.contains('/account/login') ||
redirectLocation.contains('/login')) {
throw StateError('Неверный логин или пароль');
}
// Check for flash errors in session cookie if present
try {
final dotIdx = sessionValue.indexOf('.');
final payloadBase64 =
dotIdx != -1 ? sessionValue.substring(0, dotIdx) : sessionValue;
final normalizedB64 = base64Url.normalize(payloadBase64);
final decoded = utf8.decode(base64Url.decode(normalizedB64));
if (decoded.contains('is incorrect') || decoded.contains('_flashes')) {
throw StateError('Неверный логин или пароль');
}
} catch (e) {
if (e is StateError) rethrow;
}
// Verify session and fetch initial artists
final remoteArtists = await fetchRemoteFavoriteArtists(
baseUrl: normalizedBase,
@@ -118,6 +132,15 @@ class PawchiveSyncService {
isActive: true,
syncedArtistsCount: remoteArtists.length,
);
} on DioException catch (e) {
final code = e.response?.statusCode;
if (code == 401 || code == 403) {
throw StateError('Неверный логин или пароль');
} else if (code != null) {
throw StateError('Ошибка сервера Pawchive (HTTP $code)');
} else {
throw StateError('Ошибка сети: ${e.message ?? e.type.name}');
}
} catch (e) {
if (e is StateError || e is ArgumentError) rethrow;
throw StateError('Ошибка входа в Pawchive: $e');
@@ -156,7 +179,17 @@ class PawchiveSyncService {
isActive: true,
syncedArtistsCount: remoteArtists.length,
);
} on DioException catch (e) {
final code = e.response?.statusCode;
if (code == 401 || code == 403) {
throw StateError('Сессия недействительна или истекла');
} else if (code != null) {
throw StateError('Ошибка сервера Pawchive (HTTP $code)');
} else {
throw StateError('Ошибка сети: ${e.message ?? e.type.name}');
}
} catch (e) {
if (e is StateError || e is ArgumentError) rethrow;
throw StateError('Сессия недействительна или истекла: $e');
}
}
@@ -172,7 +205,7 @@ class PawchiveSyncService {
: baseUrl;
final response = await _dio.get<dynamic>(
'$normalizedBase/account/favorites',
'$normalizedBase/api/v1/account/favorites',
queryParameters: {'type': 'artist'},
options: Options(
headers: {
@@ -180,9 +213,17 @@ class PawchiveSyncService {
'Accept': 'application/json',
'User-Agent': 'Lunaris/2.0.1 Flutter local booru browser',
},
validateStatus: (status) => status != null && status < 500,
),
);
if (response.statusCode == 401 || response.statusCode == 403) {
throw StateError('Сессия истекла или недействительна');
}
if (response.statusCode != 200) {
throw StateError('Ошибка сервера Pawchive (HTTP ${response.statusCode})');
}
final data = response.data;
if (data is! List) return const [];
@@ -344,7 +385,7 @@ class PawchiveSyncService {
? account.baseUrl.substring(0, account.baseUrl.length - 1)
: account.baseUrl;
final path = '$normalizedBase/favorites/creator/$service/$artistId';
final path = '$normalizedBase/api/v1/favorites/creator/$service/$artistId';
final options = Options(
headers: {
'Cookie': 'session=$cleanCookie',
+1 -1
View File
@@ -1,7 +1,7 @@
name: gel_rule_app
description: Local backend/core layer for a Flutter booru browser app.
publish_to: "none"
version: 2.3.8+48
version: 2.3.9+49
environment:
sdk: ">=3.3.0 <4.0.0"
+2 -2
View File
@@ -253,7 +253,7 @@ void main() {
);
expect(addResult, isTrue);
expect(lastMethod, equals('POST'));
expect(lastPath, equals('https://pawchive.pw/favorites/creator/fanbox/12345'));
expect(lastPath, equals('https://pawchive.pw/api/v1/favorites/creator/fanbox/12345'));
final removeResult = await service.toggleRemoteFavorite(
account: account,
@@ -263,7 +263,7 @@ void main() {
);
expect(removeResult, isTrue);
expect(lastMethod, equals('DELETE'));
expect(lastPath, equals('https://pawchive.pw/favorites/creator/fanbox/12345'));
expect(lastPath, equals('https://pawchive.pw/api/v1/favorites/creator/fanbox/12345'));
});
});
}