Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
402a5436bc |
@@ -1,4 +1,13 @@
|
|||||||
const lunarisChangelog = [
|
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(
|
LunarisChange(
|
||||||
version: '2.3.8',
|
version: '2.3.8',
|
||||||
title: 'ABI-Aware Auto-Update — правильный APK для вашего процессора',
|
title: 'ABI-Aware Auto-Update — правильный APK для вашего процессора',
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../core/http/dio_client.dart';
|
import '../../core/http/dio_client.dart';
|
||||||
import '../di/backend_providers.dart';
|
|
||||||
import '../models/favorite_artist_item.dart';
|
import '../models/favorite_artist_item.dart';
|
||||||
import '../models/pawchive_account.dart';
|
import '../models/pawchive_account.dart';
|
||||||
import 'settings_service.dart';
|
import 'settings_service.dart';
|
||||||
@@ -98,10 +97,25 @@ class PawchiveSyncService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if redirect points back to login with flash error
|
// 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('Неверный логин или пароль');
|
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
|
// Verify session and fetch initial artists
|
||||||
final remoteArtists = await fetchRemoteFavoriteArtists(
|
final remoteArtists = await fetchRemoteFavoriteArtists(
|
||||||
baseUrl: normalizedBase,
|
baseUrl: normalizedBase,
|
||||||
@@ -118,6 +132,15 @@ class PawchiveSyncService {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
syncedArtistsCount: remoteArtists.length,
|
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) {
|
} catch (e) {
|
||||||
if (e is StateError || e is ArgumentError) rethrow;
|
if (e is StateError || e is ArgumentError) rethrow;
|
||||||
throw StateError('Ошибка входа в Pawchive: $e');
|
throw StateError('Ошибка входа в Pawchive: $e');
|
||||||
@@ -156,7 +179,17 @@ class PawchiveSyncService {
|
|||||||
isActive: true,
|
isActive: true,
|
||||||
syncedArtistsCount: remoteArtists.length,
|
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) {
|
} catch (e) {
|
||||||
|
if (e is StateError || e is ArgumentError) rethrow;
|
||||||
throw StateError('Сессия недействительна или истекла: $e');
|
throw StateError('Сессия недействительна или истекла: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +205,7 @@ class PawchiveSyncService {
|
|||||||
: baseUrl;
|
: baseUrl;
|
||||||
|
|
||||||
final response = await _dio.get<dynamic>(
|
final response = await _dio.get<dynamic>(
|
||||||
'$normalizedBase/account/favorites',
|
'$normalizedBase/api/v1/account/favorites',
|
||||||
queryParameters: {'type': 'artist'},
|
queryParameters: {'type': 'artist'},
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: {
|
headers: {
|
||||||
@@ -180,9 +213,17 @@ class PawchiveSyncService {
|
|||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'User-Agent': 'Lunaris/2.0.1 Flutter local booru browser',
|
'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;
|
final data = response.data;
|
||||||
if (data is! List) return const [];
|
if (data is! List) return const [];
|
||||||
|
|
||||||
@@ -344,7 +385,7 @@ class PawchiveSyncService {
|
|||||||
? account.baseUrl.substring(0, account.baseUrl.length - 1)
|
? account.baseUrl.substring(0, account.baseUrl.length - 1)
|
||||||
: account.baseUrl;
|
: account.baseUrl;
|
||||||
|
|
||||||
final path = '$normalizedBase/favorites/creator/$service/$artistId';
|
final path = '$normalizedBase/api/v1/favorites/creator/$service/$artistId';
|
||||||
final options = Options(
|
final options = Options(
|
||||||
headers: {
|
headers: {
|
||||||
'Cookie': 'session=$cleanCookie',
|
'Cookie': 'session=$cleanCookie',
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
name: gel_rule_app
|
name: gel_rule_app
|
||||||
description: Local backend/core layer for a Flutter booru browser app.
|
description: Local backend/core layer for a Flutter booru browser app.
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
version: 2.3.8+48
|
version: 2.3.9+49
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.0 <4.0.0"
|
sdk: ">=3.3.0 <4.0.0"
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(addResult, isTrue);
|
expect(addResult, isTrue);
|
||||||
expect(lastMethod, equals('POST'));
|
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(
|
final removeResult = await service.toggleRemoteFavorite(
|
||||||
account: account,
|
account: account,
|
||||||
@@ -263,7 +263,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(removeResult, isTrue);
|
expect(removeResult, isTrue);
|
||||||
expect(lastMethod, equals('DELETE'));
|
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'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user