0046b8d695
#1 JWT middleware: - pgz_sport_api.py: starlette middleware require_jwt_on_admin runs before every /api/admin/* route. Even routes that lack Depends(require_user) cannot be reached without a valid Bearer token (verifies signature, exp, typ='access', revocation via user_sessions). OPTIONS passes for CORS. #2 Invitation flow: - pgz_sport.user_action_tokens table (token_hash, user_id, kind, expires_at, used_at, created_by, ip, meta). Single-use, raw token never persisted. - POST /api/admin/users/{id}/invite — issues 'invite' token (TTL 7d), marks must_change_pwd, revokes existing sessions, returns invite_link. - GET /api/auth/setup-password?token=X — preflight (no consume). - POST /api/auth/setup-password — consumes token, sets password, sets email_verified=true. #3 Password reset flow: - POST /api/auth/forgot-password — generic 'ako račun postoji' response; issues 'reset' token (TTL 2h) only for active users. Token returned in response only on localhost or if PGZ_REVEAL_RESET_TOKEN=1. - GET /api/auth/reset-password?token=X — preflight. - POST /api/auth/reset-password — consumes token, sets new password, revokes all active sessions. #4 Audit coverage (auth events): - login.ok, login.fail (with reason), login.locked, login.2fa_required, login.2fa_fail, logout, auth.refresh, password.change, password.reset.ok, password.reset.fail, password.forgot.issue, password.forgot.miss, invite.consume.ok, invite.consume.fail, user.invite, user.create, user.update, user.delete, user.role.change, user.suspend, user.unsuspend, user.password.reset, 2fa.verify.ok, 2fa.verify.fail, 2fa.disable. #5 Live tests: 41/41 across 6 demo users (incl. fresh invited+deleted user). Phase 2 verifies 14 endpoints reject no-auth and accept valid Bearer.
222 lines
6.1 KiB
JSON
222 lines
6.1 KiB
JSON
{
|
|
"_meta": {
|
|
"version": 1,
|
|
"author": "dradulic@outlook.com",
|
|
"date": "2026-05-04",
|
|
"purpose": "Sport-aware enrichment routing for /v2/enrich/sportas. Each entry maps a sport name (lower-case, multiple aliases supported) to its national federation, optional PGŽ regional federation, and a list of search/scrape URLs. Used by routers/enrich_router.py and workers/enrichment_worker.py."
|
|
},
|
|
"_aliases": {
|
|
"kosarkaski": "košarka",
|
|
"košarkaški": "košarka",
|
|
"nogometni": "nogomet",
|
|
"rukometni": "rukomet",
|
|
"stoni tenis": "stolni tenis",
|
|
"stolnotenis": "stolni tenis",
|
|
"bocanje": "boćanje",
|
|
"boćanje (boules)": "boćanje",
|
|
"kuglacki": "kuglanje",
|
|
"vaterpolski": "vaterpolo",
|
|
"konjicki sport": "konjički sport",
|
|
"auto-sport": "auto sport",
|
|
"skijaski sport": "skijanje"
|
|
},
|
|
"boćanje": {
|
|
"national": {
|
|
"name": "HBS",
|
|
"long_name": "Hrvatski boćarski savez",
|
|
"url": "https://hrvatski-bocarski-savez.hr",
|
|
"search_url": "https://hrvatski-bocarski-savez.hr/?s={q}",
|
|
"profile_url_pattern": "https://hrvatski-bocarski-savez.hr/igraci/{slug}/"
|
|
},
|
|
"pgz": {
|
|
"name": "BS PGŽ",
|
|
"url": "https://hrvatski-bocarski-savez.hr/savez/zupanijski-savezi/"
|
|
}
|
|
},
|
|
"nogomet": {
|
|
"national": {
|
|
"name": "HNS",
|
|
"long_name": "Hrvatski nogometni savez",
|
|
"url": "https://hns-cff.hr",
|
|
"search_url": "https://semafor.hns.family/?s={q}",
|
|
"profile_search": "https://semafor.hns.family/igraci/?ime={q}",
|
|
"profile_url_pattern": "https://semafor.hns.family/igraci/{hns_pid}/{slug}/"
|
|
},
|
|
"pgz": {"name": "NS PGŽ", "url": "https://nogomet-pgz.hr"}
|
|
},
|
|
"košarka": {
|
|
"national": {
|
|
"name": "HKS",
|
|
"long_name": "Hrvatski košarkaški savez",
|
|
"url": "https://hks-cbf.hr",
|
|
"search_url": "https://hks-cbf.hr/?s={q}"
|
|
},
|
|
"pgz": {"name": "KS PGŽ", "url": "https://kosarka-pgz.hr"}
|
|
},
|
|
"rukomet": {
|
|
"national": {
|
|
"name": "HRS",
|
|
"long_name": "Hrvatski rukometni savez",
|
|
"url": "https://hrs.hr",
|
|
"search_url": "https://hrs.hr/?s={q}"
|
|
},
|
|
"pgz": {"name": "RS PGŽ", "url": "https://rs-pgz.hr"}
|
|
},
|
|
"odbojka": {
|
|
"national": {
|
|
"name": "HOS",
|
|
"long_name": "Hrvatski odbojkaški savez",
|
|
"url": "https://hos-cvf.hr",
|
|
"search_url": "https://hos-cvf.hr/?s={q}"
|
|
},
|
|
"pgz": {"name": "OS PGŽ", "url": "https://odbojkaski-savez-pgz.hr"}
|
|
},
|
|
"vaterpolo": {
|
|
"national": {
|
|
"name": "HVS",
|
|
"long_name": "Hrvatski vaterpolski savez",
|
|
"url": "https://hvs.hr",
|
|
"search_url": "https://hvs.hr/?s={q}"
|
|
}
|
|
},
|
|
"plivanje": {
|
|
"national": {
|
|
"name": "HPS",
|
|
"long_name": "Hrvatski plivački savez",
|
|
"url": "https://hps.hr",
|
|
"search_url": "https://hps.hr/?s={q}"
|
|
}
|
|
},
|
|
"atletika": {
|
|
"national": {
|
|
"name": "HAS",
|
|
"long_name": "Hrvatski atletski savez",
|
|
"url": "https://atletika.hr",
|
|
"search_url": "https://atletika.hr/?s={q}"
|
|
}
|
|
},
|
|
"tenis": {
|
|
"national": {
|
|
"name": "HTS",
|
|
"long_name": "Hrvatski teniski savez",
|
|
"url": "https://htsavez.hr",
|
|
"search_url": "https://htsavez.hr/?s={q}"
|
|
}
|
|
},
|
|
"judo": {
|
|
"national": {
|
|
"name": "HJS",
|
|
"long_name": "Hrvatski judo savez",
|
|
"url": "https://judo-savez.hr",
|
|
"search_url": "https://judo-savez.hr/?s={q}"
|
|
}
|
|
},
|
|
"karate": {
|
|
"national": {
|
|
"name": "HKaS",
|
|
"long_name": "Hrvatski karate savez",
|
|
"url": "https://karate.hr",
|
|
"search_url": "https://karate.hr/?s={q}"
|
|
}
|
|
},
|
|
"veslanje": {
|
|
"national": {
|
|
"name": "HVeS",
|
|
"long_name": "Hrvatski veslački savez",
|
|
"url": "https://veslacki-savez.hr",
|
|
"search_url": "https://veslacki-savez.hr/?s={q}"
|
|
}
|
|
},
|
|
"jedrenje": {
|
|
"national": {
|
|
"name": "HJedS",
|
|
"long_name": "Hrvatski jedriličarski savez",
|
|
"url": "https://hjs.hr",
|
|
"search_url": "https://hjs.hr/?s={q}"
|
|
}
|
|
},
|
|
"gimnastika": {
|
|
"national": {
|
|
"name": "HGS",
|
|
"long_name": "Hrvatski gimnastički savez",
|
|
"url": "https://gimnastika.hr",
|
|
"search_url": "https://gimnastika.hr/?s={q}"
|
|
}
|
|
},
|
|
"streličarstvo": {
|
|
"national": {
|
|
"name": "HStS",
|
|
"long_name": "Hrvatski streličarski savez",
|
|
"url": "https://hss.hr",
|
|
"search_url": "https://hss.hr/?s={q}"
|
|
}
|
|
},
|
|
"biciklizam": {
|
|
"national": {
|
|
"name": "HBciS",
|
|
"long_name": "Hrvatski biciklistički savez",
|
|
"url": "https://hbs.hr",
|
|
"search_url": "https://hbs.hr/?s={q}"
|
|
}
|
|
},
|
|
"stolni tenis": {
|
|
"national": {
|
|
"name": "HSTS",
|
|
"long_name": "Hrvatski stolnoteniski savez",
|
|
"url": "https://stolni-tenis.hr",
|
|
"search_url": "https://stolni-tenis.hr/?s={q}"
|
|
}
|
|
},
|
|
"triatlon": {
|
|
"national": {
|
|
"name": "HTrS",
|
|
"long_name": "Hrvatski triatlon savez",
|
|
"url": "https://triatlon.hr",
|
|
"search_url": "https://triatlon.hr/?s={q}"
|
|
}
|
|
},
|
|
"skijanje": {
|
|
"national": {
|
|
"name": "HZS",
|
|
"long_name": "Hrvatski skijaški savez",
|
|
"url": "https://skijaski-savez.hr",
|
|
"search_url": "https://skijaski-savez.hr/?s={q}"
|
|
}
|
|
},
|
|
"kuglanje": {
|
|
"national": {
|
|
"name": "HKgS",
|
|
"long_name": "Hrvatski kuglački savez",
|
|
"url": "https://kuglanje.hr",
|
|
"search_url": "https://kuglanje.hr/?s={q}"
|
|
}
|
|
},
|
|
"šah": {
|
|
"national": {
|
|
"name": "HŠS",
|
|
"long_name": "Hrvatski šahovski savez",
|
|
"url": "https://hsk.hr",
|
|
"search_url": "https://hsk.hr/?s={q}"
|
|
}
|
|
},
|
|
"konjički sport": {
|
|
"national": {
|
|
"name": "HKonjS",
|
|
"long_name": "Hrvatski konjički sportski savez",
|
|
"url": "https://konjs.hr"
|
|
}
|
|
},
|
|
"auto sport": {
|
|
"national": {
|
|
"name": "HAKS",
|
|
"long_name": "Hrvatski auto klub savez",
|
|
"url": "https://hsa.hr"
|
|
}
|
|
},
|
|
"_local_media_pgz": [
|
|
{"name": "Novi list", "search_url": "https://www.novilist.hr/?s={q}"},
|
|
{"name": "Glas Istre", "search_url": "https://www.glasistre.hr/pretraga?q={q}"},
|
|
{"name": "Rijeka.danas","search_url": "https://www.rijeka-danas.com/?s={q}"}
|
|
]
|
|
}
|