paths
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions

This commit is contained in:
Dmitry 2026-01-24 15:31:47 +03:00
parent 87505dd01d
commit ce564924f2
16 changed files with 51 additions and 19 deletions

View file

@ -966,3 +966,4 @@ void main() {

View file

@ -282,3 +282,4 @@ Built with build_runner/jit in 1s; wrote 0 outputs.

View file

@ -322,3 +322,4 @@ import 'package:mnemo_cards_backend/database/database.dart';

View file

@ -31,3 +31,4 @@ GROUP BY is_blacklisted;

View file

@ -558,14 +558,20 @@ class PacksApiV2 {
objectId: imageValue, objectId: imageValue,
); );
if (presignedUrl != null) { if (presignedUrl != null) {
return Response.found(presignedUrl); return Response.found(
presignedUrl,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
return _notFound('Image not found in storage'); return _notFound('Image not found in storage');
} }
// Remote URL: redirect // Remote URL: redirect
if (CardImageStorage.isRemoteUrl(imageValue)) { if (CardImageStorage.isRemoteUrl(imageValue)) {
return Response.found(imageValue); return Response.found(
imageValue,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
// Not a UUID and not a remote URL - image not found // Not a UUID and not a remote URL - image not found
@ -631,14 +637,20 @@ class PacksApiV2 {
objectId: imageValue, objectId: imageValue,
); );
if (presignedUrl != null) { if (presignedUrl != null) {
return Response.found(presignedUrl); return Response.found(
presignedUrl,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
return _notFound('Back image not found in storage'); return _notFound('Back image not found in storage');
} }
// Remote URL: redirect // Remote URL: redirect
if (CardImageStorage.isRemoteUrl(imageValue)) { if (CardImageStorage.isRemoteUrl(imageValue)) {
return Response.found(imageValue); return Response.found(
imageValue,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
// Not a UUID and not a remote URL - image not found // Not a UUID and not a remote URL - image not found
@ -683,14 +695,20 @@ class PacksApiV2 {
objectId: coverValue, objectId: coverValue,
); );
if (presignedUrl != null) { if (presignedUrl != null) {
return Response.found(presignedUrl); return Response.found(
presignedUrl,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
return _notFound('Cover image not found in storage'); return _notFound('Cover image not found in storage');
} }
// Remote URL: redirect // Remote URL: redirect
if (CardImageStorage.isRemoteUrl(coverValue)) { if (CardImageStorage.isRemoteUrl(coverValue)) {
return Response.found(coverValue); return Response.found(
coverValue,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
// Not a UUID and not a remote URL - image not found // Not a UUID and not a remote URL - image not found
@ -862,7 +880,10 @@ class PacksApiV2 {
// Remote voice: redirect to remote storage URL // Remote voice: redirect to remote storage URL
if (VoiceStorage.isRemoteUrl(voiceValue)) { if (VoiceStorage.isRemoteUrl(voiceValue)) {
return Response.found(voiceValue); return Response.found(
voiceValue,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
// If it's a valid UUID (object ID in MinIO), redirect to presigned URL // If it's a valid UUID (object ID in MinIO), redirect to presigned URL
@ -872,7 +893,10 @@ class PacksApiV2 {
objectId: voiceValue, objectId: voiceValue,
); );
if (presignedUrl != null) { if (presignedUrl != null) {
return Response.found(presignedUrl); return Response.found(
presignedUrl,
headers: {'Cache-Control': 'public, max-age=86400'},
);
} }
return _notFound('Voice file not found in storage'); return _notFound('Voice file not found in storage');
} }

View file

@ -51,3 +51,4 @@ VACUUM FULL ANALYZE payments;

View file

@ -124,3 +124,4 @@ DROP TYPE IF EXISTS grant_type CASCADE;

View file

@ -196,3 +196,4 @@ PRINT 'Migration 003 completed successfully!';

View file

@ -56,3 +56,4 @@ echo " - favicon.png (32x32)"

View file

@ -282,7 +282,7 @@ class _PackDetailsPageState extends State<PackDetailsPage> {
} }
log('Launching test: ${test.name}', name: 'PackDetailsPage'); log('Launching test: ${test.name}', name: 'PackDetailsPage');
context.push('/game/${test.id}', extra: '/pack/${widget.packId}'); context.go('/game/${test.id}', extra: '/pack/${widget.packId}');
} }
@override @override
@ -412,7 +412,7 @@ class _PackDetailsPageState extends State<PackDetailsPage> {
try { try {
await Future<void>.delayed(const Duration(milliseconds: 100)); await Future<void>.delayed(const Duration(milliseconds: 100));
if (mounted) { if (mounted) {
await context.push('/purchase/${widget.packId}'); context.go('/purchase/${widget.packId}');
} }
} finally { } finally {
if (mounted) { if (mounted) {

View file

@ -142,7 +142,7 @@ class _TasksPageState extends State<TasksPage> with TickerProviderStateMixin {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
FloatingActionButton( FloatingActionButton(
onPressed: () => context.push('/tasks/create'), onPressed: () => context.go('/tasks/create'),
tooltip: 'Создать задание', tooltip: 'Создать задание',
heroTag: 'create_task', heroTag: 'create_task',
child: const Icon(Icons.add), child: const Icon(Icons.add),

View file

@ -219,7 +219,7 @@ class _TestPageState extends State<TestPage> {
} }
void _playGame(BuildContext context) { void _playGame(BuildContext context) {
context.push('/game/${widget.testId}'); context.go('/game/${widget.testId}');
} }
void _handleBack() { void _handleBack() {

View file

@ -21,7 +21,7 @@ class GameCard extends StatelessWidget {
onTap ?? onTap ??
() { () {
// Navigate to game page // Navigate to game page
context.push('/game/${game.id}'); context.go('/game/${game.id}');
}, },
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View file

@ -37,9 +37,9 @@ class PackCard extends StatelessWidget {
GestureDetector( GestureDetector(
onTap: () { onTap: () {
if (pack.isAvailable) { if (pack.isAvailable) {
context.push('/pack/${pack.id}'); context.go('/pack/${pack.id}');
} else { } else {
context.push('/purchase/${pack.id}'); context.go('/purchase/${pack.id}');
} }
}, },
child: Container( child: Container(

View file

@ -33,9 +33,9 @@ class PackCardVertical extends StatelessWidget {
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
if (pack.isAvailable) { if (pack.isAvailable) {
context.push('/pack/${pack.id}'); context.go('/pack/${pack.id}');
} else { } else {
context.push('/purchase/${pack.id}'); context.go('/purchase/${pack.id}');
} }
}, },
child: Container( child: Container(

View file

@ -35,7 +35,7 @@ class TaskCard extends StatelessWidget {
onTap ?? onTap ??
() { () {
// Default navigation to task details // Default navigation to task details
context.push('/tasks/${task.id}'); context.go('/tasks/${task.id}');
}, },
child: Container( child: Container(
margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 4.0), margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 4.0),