fixrs
This commit is contained in:
parent
a807d0f90f
commit
c678479137
16 changed files with 861 additions and 1544 deletions
|
|
@ -315,6 +315,12 @@ jobs:
|
|||
echo "🔄 Running pre-deploy version bump..."
|
||||
./tools/deploy/bump-version.sh
|
||||
|
||||
- name: Push Version Bump
|
||||
run: |
|
||||
echo "📤 Pushing version bump to remote..."
|
||||
git push
|
||||
echo "✅ Version bump pushed"
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global http.postBuffer 52428800
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,10 +1,12 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:mnemo_cards_backend/api/authorize/helpers.dart';
|
||||
import 'package:mnemo_cards_backend/api/v2/jwt_service.dart';
|
||||
import 'package:mnemo_cards_backend/api/user/google_api.dart';
|
||||
import 'package:mnemo_cards_backend/auth/telegram_auth_code_service.dart';
|
||||
import 'package:mnemo_cards_backend/user/telegram.dart';
|
||||
import 'package:mnemo_cards_backend/user/user_manager.dart';
|
||||
import 'package:mnemo_cards_backend/user/user_model.dart';
|
||||
import 'package:shelf/shelf.dart';
|
||||
|
|
@ -228,6 +230,48 @@ class AuthApiV2 {
|
|||
/// POST /api/v2/auth/oauth/telegram
|
||||
/// Authenticate with Telegram auth code from bot
|
||||
/// Body: { code: string }
|
||||
@Route.post('/auth/telegram/web-app')
|
||||
@OpenApiRoute()
|
||||
Future<Response> authenticateTelegramWebApp(Request request) async {
|
||||
try {
|
||||
final body = await request.readAsString();
|
||||
final json = jsonDecode(body) as Map<String, dynamic>;
|
||||
final initData = json['initData'] as String?;
|
||||
|
||||
if (initData == null || initData.isEmpty) {
|
||||
return _badRequest('Telegram Web App init data is required');
|
||||
}
|
||||
|
||||
// Use the existing telegram utils to get user ID
|
||||
final telegramUtils = TelegramUtils();
|
||||
final userId = await telegramUtils.getUserId(initData);
|
||||
|
||||
if (userId == null) {
|
||||
return _badRequest('Invalid Telegram Web App data');
|
||||
}
|
||||
|
||||
// Find or create user based on telegram user ID
|
||||
var user = await _userManager.findByTelegramId(userId);
|
||||
if (user == null) {
|
||||
// Create new user if doesn't exist
|
||||
user = await _userManager.createFromTelegramData(userId, initData);
|
||||
}
|
||||
|
||||
// Generate tokens
|
||||
final tokens = await _jwtService.generateTokens(user);
|
||||
|
||||
return _ok({
|
||||
'user': await user.toDto(),
|
||||
'accessToken': tokens.accessToken,
|
||||
'refreshToken': tokens.refreshToken,
|
||||
'expiresIn': tokens.expiresIn,
|
||||
});
|
||||
} catch (e, s) {
|
||||
log('Telegram Web App auth error', error: e, stackTrace: s);
|
||||
return _badRequest('Authentication failed: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@Route.post('/auth/oauth/telegram')
|
||||
@OpenApiRoute()
|
||||
Future<Response> authenticateTelegram(Request request) async {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ Router _$AuthApiV2Router(AuthApiV2 service) {
|
|||
r'/auth/telegram/code-status/<code>',
|
||||
service.getTelegramCodeStatus,
|
||||
);
|
||||
router.add(
|
||||
'POST',
|
||||
r'/auth/telegram/web-app',
|
||||
service.authenticateTelegramWebApp,
|
||||
);
|
||||
router.add(
|
||||
'POST',
|
||||
r'/auth/oauth/telegram',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
platform :osx, '10.14'
|
||||
platform :osx, '10.15'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0920;
|
||||
LastUpgradeCheck = 1430;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C80D4294CF70F00263BE5 = {
|
||||
|
|
@ -553,7 +553,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
|
@ -632,7 +632,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
|
|
@ -679,7 +679,7 @@
|
|||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.15;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1430"
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
@ -59,6 +59,7 @@
|
|||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
import Cocoa
|
||||
import FlutterMacOS
|
||||
|
||||
@NSApplicationMain
|
||||
@main
|
||||
class AppDelegate: FlutterAppDelegate {
|
||||
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -39,13 +39,25 @@ class AuthService {
|
|||
|
||||
// Get init data from Telegram Web App
|
||||
final webAppData = TelegramWebApp.instance;
|
||||
final initData = webAppData.initData.toString();
|
||||
if (initData.isEmpty) {
|
||||
String? initData;
|
||||
|
||||
try {
|
||||
// Try different ways to get init data
|
||||
if (webAppData.initData != null) {
|
||||
initData = webAppData.initData.toString();
|
||||
} else if (webAppData.initDataUnsafe != null) {
|
||||
initData = webAppData.initDataUnsafe.toString();
|
||||
}
|
||||
} catch (e) {
|
||||
log('Error getting init data from Telegram Web App', error: e, name: 'AuthService');
|
||||
}
|
||||
|
||||
if (initData == null || initData.isEmpty) {
|
||||
log('No Telegram Web App init data available', name: 'AuthService');
|
||||
return null;
|
||||
}
|
||||
|
||||
log('Telegram Web App init data received, sending to backend', name: 'AuthService');
|
||||
log('Telegram Web App init data received: $initData', name: 'AuthService');
|
||||
|
||||
// Authenticate with backend using Telegram Web App data
|
||||
final authResponse = await _httpRepository.authenticateWithTelegramWebApp(
|
||||
|
|
|
|||
|
|
@ -413,12 +413,8 @@ class HttpRepositoryV2 {
|
|||
final refreshToken = data['refreshToken'] as String;
|
||||
final expiresIn = data['expiresIn'] as int?;
|
||||
|
||||
// Save tokens
|
||||
await saveTokens(
|
||||
accessToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
expiresIn: expiresIn,
|
||||
);
|
||||
await saveTokens(accessToken: accessToken, refreshToken: refreshToken, expiresIn: expiresIn,);
|
||||
|
||||
|
||||
final expiresAt = expiresIn != null
|
||||
? DateTime.now().add(Duration(seconds: expiresIn))
|
||||
|
|
|
|||
|
|
@ -64,8 +64,7 @@ class _AuthPageState extends State<AuthPage> {
|
|||
// Notify router about auth change
|
||||
appScope.userScopeHolder.notifyAuthChanged();
|
||||
|
||||
// Navigate to home
|
||||
router.go('/home');
|
||||
// Router will automatically redirect to /home when authentication state changes
|
||||
} else {
|
||||
setState(() {
|
||||
_errorMessage = 'Login cancelled';
|
||||
|
|
@ -86,9 +85,9 @@ class _AuthPageState extends State<AuthPage> {
|
|||
}
|
||||
|
||||
Future<void> _onTelegramLoginSuccess(BuildContext context) async {
|
||||
// Get router before async operations to avoid context issues
|
||||
final router = GoRouter.of(context);
|
||||
router.go('/home');
|
||||
// Router will automatically redirect to /home when authentication state changes
|
||||
// No manual navigation needed - let the GoRouter handle the redirect
|
||||
log('Telegram login successful - router will handle redirect to home', name: 'AuthPage');
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ class _SignInWithTelegramState extends State<SignInWithTelegram> {
|
|||
isClaimed: true,
|
||||
expiresAt: DateTime.now(),
|
||||
);
|
||||
_autoLoginAttempted = true; // Mark as attempted to prevent re-attempts
|
||||
});
|
||||
|
||||
// Clear code field
|
||||
|
|
@ -190,9 +191,16 @@ class _SignInWithTelegramState extends State<SignInWithTelegram> {
|
|||
widget.onError('Срок действия кода истёк. Сгенерируйте новый.');
|
||||
} else if (status.isConsumed) {
|
||||
_stopCodePolling();
|
||||
} else if (status.isReadyForLogin && !_autoLoginAttempted && mounted) {
|
||||
} else if (status.isReadyForLogin && !_autoLoginAttempted && mounted) {
|
||||
log('Auto-login triggered for code: ${status.code}', name: 'SignInWithTelegram');
|
||||
_autoLoginAttempted = true;
|
||||
await _loginWithTelegram();
|
||||
|
||||
// Small delay to ensure UI updates are processed before navigation
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
if (mounted) {
|
||||
await _loginWithTelegram();
|
||||
}
|
||||
}
|
||||
} catch (e, s) {
|
||||
log(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:developer';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
||||
|
|
@ -438,7 +439,8 @@ class _PackDetailsPageState extends State<PackDetailsPage> {
|
|||
return Column(
|
||||
children: [
|
||||
// Модуль "проверка знаний" для мобильных
|
||||
_buildMobileTestsSection(packColor),
|
||||
// Hide tests section for mobile devices for now
|
||||
// _buildMobileTestsSection(packColor),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
|
|
@ -855,29 +857,19 @@ class _PackDetailsPageState extends State<PackDetailsPage> {
|
|||
|
||||
final imageUrl = ApiConfigV2.getCardImageUrl(widget.packId, card.id);
|
||||
|
||||
return Image.network(
|
||||
imageUrl,
|
||||
return CachedNetworkImage(
|
||||
imageUrl: imageUrl,
|
||||
fit: BoxFit.cover,
|
||||
gaplessPlayback: true,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress == null) {
|
||||
return child;
|
||||
}
|
||||
return Center(
|
||||
child: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
value: loadingProgress.expectedTotalBytes != null
|
||||
? loadingProgress.cumulativeBytesLoaded /
|
||||
loadingProgress.expectedTotalBytes!
|
||||
: null,
|
||||
),
|
||||
maxWidthDiskCache: 2048,
|
||||
maxHeightDiskCache: 2048,
|
||||
progressIndicatorBuilder: (context, child, loadingProgress) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
);
|
||||
},
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
errorWidget: (context, url, error) {
|
||||
return Center(
|
||||
child: Icon(
|
||||
Icons.broken_image,
|
||||
|
|
@ -886,6 +878,9 @@ class _PackDetailsPageState extends State<PackDetailsPage> {
|
|||
),
|
||||
);
|
||||
},
|
||||
// Плавное появление загруженного изображения
|
||||
fadeInDuration: const Duration(milliseconds: 100),
|
||||
fadeOutDuration: const Duration(milliseconds: 100),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,6 +144,30 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.12.0"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
cached_network_image_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
cached_network_image_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -501,6 +525,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_cache_manager:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_cache_manager
|
||||
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
flutter_colorpicker:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -892,6 +924,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1176,6 +1216,46 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.1"
|
||||
sqflite:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite
|
||||
sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
sqflite_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_android
|
||||
sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2+2"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.6"
|
||||
sqflite_darwin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_darwin
|
||||
sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
sqflite_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_platform_interface
|
||||
sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -1216,6 +1296,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
synchronized:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: synchronized
|
||||
sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.0"
|
||||
telegram_web_app:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ dependencies:
|
|||
shimmer: ^3.0.0
|
||||
auto_size_text: ^3.0.0
|
||||
fl_chart: ^0.68.0
|
||||
cached_network_image: ^3.4.1
|
||||
|
||||
# Utils
|
||||
universal_image: ^1.0.10
|
||||
|
|
|
|||
Loading…
Reference in a new issue