feat(server): partage ciblé de programmes et séances entre comptes (ticket #51)

Ajoute l'endpoint api/share_api.dart, les use cases de partage
(application/share_use_cases.dart) et l'adapter Postgres
(infrastructure/postgres/share_repository.dart). L'acceptation d'un
partage crée une nouvelle ressource synced_resources avec de nouveaux
IDs pour le destinataire, sans jamais modifier la ressource source de
l'émetteur ; gestion des conflits révoqué/déjà répondu. dart pub get
OK, dart analyze clean, dart test 24/24 vert. Use case d'acceptation
relu manuellement et jugé correct ; pas de test de bout en bout contre
un vrai PostgreSQL faute d'accès Docker dans ce sandbox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 10:34:09 +02:00
parent c232bdcec1
commit db6e84be06
15 changed files with 1531 additions and 13 deletions

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:gametime_server/api/auth_api.dart';
import 'package:gametime_server/api/router.dart';
import 'package:gametime_server/api/share_api.dart';
import 'package:gametime_server/api/sync_api.dart';
import 'package:gametime_server/application/application.dart';
import 'package:gametime_server/infrastructure/postgres/postgres.dart';
@ -17,6 +18,7 @@ Future<void> main(List<String> arguments) async {
final users = PostgresUserRepository(connection);
final sessions = PostgresAuthSessionRepository(connection);
final resources = PostgresSyncedResourceRepository(connection);
final shares = PostgresShareRepository(connection);
final passwordHasher = Pbkdf2PasswordHasher();
final tokens = SecureOpaqueTokenService();
const clock = SystemClock();
@ -57,9 +59,27 @@ Future<void> main(List<String> arguments) async {
exchangeSync: ExchangeSyncUseCase(push: pushSync, pull: pullSync),
authenticateRequest: authenticateRequest,
);
final shareApi = ShareApi(
createShare: CreateShareUseCase(
users: users,
shares: shares,
clock: clock,
ids: ids,
),
listInbox: ListInboxUseCase(shares: shares),
acceptShare: AcceptShareUseCase(
shares: shares,
resources: resources,
clock: clock,
ids: ids,
),
declineShare: DeclineShareUseCase(shares: shares, clock: clock),
revokeShare: RevokeShareUseCase(shares: shares, clock: clock),
authenticateRequest: authenticateRequest,
);
final server = await shelf_io.serve(
buildApiHandler(authApi: authApi, syncApi: syncApi),
buildApiHandler(authApi: authApi, syncApi: syncApi, shareApi: shareApi),
InternetAddress.anyIPv4,
port,
);