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,
);
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');
}
// Remote URL: redirect
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
@ -631,14 +637,20 @@ class PacksApiV2 {
objectId: imageValue,
);
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');
}
// Remote URL: redirect
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
@ -683,14 +695,20 @@ class PacksApiV2 {
objectId: coverValue,
);
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');
}
// Remote URL: redirect
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
@ -862,7 +880,10 @@ class PacksApiV2 {
// Remote voice: redirect to remote storage URL
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
@ -872,7 +893,10 @@ class PacksApiV2 {
objectId: voiceValue,
);
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');
}

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

View file

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

View file

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

View file

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

View file

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

View file

@ -30,12 +30,12 @@ class PackCardVertical extends StatelessWidget {
child: Semantics(
label: 'Pack: ${pack.title}. Tap to view details.',
button: true,
child: GestureDetector(
child: GestureDetector(
onTap: () {
if (pack.isAvailable) {
context.push('/pack/${pack.id}');
context.go('/pack/${pack.id}');
} else {
context.push('/purchase/${pack.id}');
context.go('/purchase/${pack.id}');
}
},
child: Container(

View file

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