feat(import): generic transactional profile-import service + CLI
Core performs a GAME-AGNOSTIC transactional profile import; all FIFA17 semantics (manifest parse, wire ids, resourceId/nextItemId, squad extension v1, CardDefinitionId/OwnedItemId choice) stay in openfut-import-fifa17. Core sees only opaque ids and opaque extension bytes. services::import::apply_profile_import(pool, card_db, ProfileImportRequest): - ONE SQLite transaction installs profile + club + all owned cards + canonical squad + one opaque game extension; commits together or not at all. - Definition preflight (pre-tx): every owned card_id MUST resolve in loaded production content, so ownership never points at absent content. - Squad all-or-nothing (pre-tx): every active-squad OwnedItemId MUST be in the imported ownership set. - OwnedItemId uniqueness + generic extension bounds enforced pre-tx. - Core computes the canonical squad fingerprint itself (never adapter-supplied) and persists the extension atomically, exactly as the live squad-write path. Rerun identity via profiles.import_fingerprint (migration 0018, nullable): - identical source_fingerprint on an already-imported game -> idempotent no-op; - differing token -> fail (needs explicit update mode); - pre-existing non-imported profile -> never clobbered. So a crash after identity-seeding re-runs cleanly with no cleanup/reminting. CLI: 'openfut-core import <request.json>' loads production content packs, parses a generic request, applies. squad_fingerprint made pub(crate) for reuse. 8 import-service tests (happy path, idempotent rerun, fingerprint mismatch, missing-definition no-write, squad-not-owned, dup OwnedItemId, non-imported clobber guard, empty-owned). clippy -D warnings clean; full suite 159 green.
This commit is contained in:
@@ -497,7 +497,7 @@ pub async fn replace_squad_with_extension(
|
||||
/// computed; non-cryptographic (FNV-1a-64) — a stale-extension guard, not a
|
||||
/// security boundary. The encoding is sorted + delimited so it never depends on
|
||||
/// row/iteration order.
|
||||
fn squad_fingerprint<'a>(
|
||||
pub(crate) fn squad_fingerprint<'a>(
|
||||
squad_id: &str,
|
||||
formation: &str,
|
||||
slots: impl Iterator<Item = (i64, &'a str, bool, bool)>,
|
||||
|
||||
Reference in New Issue
Block a user