shinkan-jinkendo/frontend/src/utils/api.js
Lars bd5a409fa7
All checks were successful
Deploy Development / deploy (push) Successful in 42s
Test Suite / pytest-backend (push) Successful in 44s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 15s
Test Suite / k6 /health Baseline (push) Successful in 35s
Test Suite / playwright-tests (push) Successful in 1m18s
Test Suite / pytest-backend (pull_request) Successful in 38s
Test Suite / lint-backend (pull_request) Successful in 0s
Test Suite / build-frontend (pull_request) Successful in 13s
Test Suite / k6 /health Baseline (pull_request) Successful in 38s
Test Suite / playwright-tests (pull_request) Successful in 1m12s
Add Admin User Content Management Features
- Introduced a new admin user content management endpoint for superadmins, allowing for moderation of user-generated content.
- Updated the backend to include new API functions for retrieving, patching, and deleting user content items.
- Enhanced the frontend with a new Admin User Content page and navigation link for easy access to user content management.
- Updated access layer documentation to reflect the new endpoint and its exempt status.
- Incremented version to 0.8.191 and updated changelog to document these additions in admin functionality.
2026-06-06 17:53:25 +02:00

1060 lines
30 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Shinkan Jinkendo API Client
*
* Zentrale API-Kommunikation mit automatischer Token-Injektion
*/
import { request, ACTIVE_CLUB_STORAGE_KEY, requestText } from '../api/client.js'
import * as exercises from '../api/exercises.js'
import * as planning from '../api/planning.js'
import * as skillProfiles from '../api/skillProfiles.js'
export { ACTIVE_CLUB_STORAGE_KEY }
export * from '../api/exercises.js'
export * from '../api/planning.js'
export * from '../api/skillProfiles.js'
// ============================================================================
// Auth
// ============================================================================
export async function login(email, password) {
return request('/api/auth/login', {
method: 'POST',
body: JSON.stringify({ email, password })
})
}
export async function register(email, password, name, extra = {}) {
return request('/api/auth/register', {
method: 'POST',
body: JSON.stringify({ email, password, name, ...extra }),
})
}
export async function logout() {
return request('/api/auth/logout', { method: 'POST' })
}
export async function getCurrentProfile() {
return request('/api/profiles/me')
}
/** Liste aller Profile nur für Plattform-Admins (Vereinsanlage). */
export async function listProfiles() {
return request('/api/profiles')
}
/** Alle Nutzer inkl. Vereinsmitgliedschaften — nur Portal-Admin (UI: Admin → Nutzer). */
export async function listAdminUsers() {
return request('/api/admin/users')
}
/** Superadmin: Metadaten zu nutzerangelegten Inhaltstypen. */
export async function getAdminUserContentMeta() {
return request('/api/admin/user-content/meta')
}
/** Superadmin: Aktivitätsübersicht je Nutzer (Anzahl Inhalte). */
export async function listAdminUserContentSummary() {
return request('/api/admin/user-content/users-summary')
}
/** Superadmin: Inhalte aller Nutzer (inkl. privat) — filterbar. */
export async function listAdminUserContentItems(params = {}) {
const qs = new URLSearchParams()
for (const [k, v] of Object.entries(params)) {
if (v !== undefined && v !== null && v !== '') qs.set(k, String(v))
}
const q = qs.toString()
return request(`/api/admin/user-content/items${q ? `?${q}` : ''}`)
}
/** Superadmin: Status/Sichtbarkeit eines Inhalts setzen. */
export async function patchAdminUserContentItem(contentType, itemId, body) {
return request(`/api/admin/user-content/items/${contentType}/${itemId}`, {
method: 'PATCH',
body: JSON.stringify(body),
})
}
/** Superadmin: Inhalt löschen. */
export async function deleteAdminUserContentItem(contentType, itemId) {
return request(`/api/admin/user-content/items/${contentType}/${itemId}`, { method: 'DELETE' })
}
/** Medien-Speicher (MEDIA_ROOT + relativer Unterordner) — GET: admin/superadmin, PUT: nur superadmin. */
export async function getPlatformMediaStorage() {
return request('/api/admin/platform-media-storage')
}
export async function putPlatformMediaStorage(payload) {
return request('/api/admin/platform-media-storage', {
method: 'PUT',
body: JSON.stringify(payload),
})
}
export async function updateProfile(profileId, data) {
return request(`/api/profiles/${profileId}`, {
method: 'PUT',
body: JSON.stringify(data),
})
}
/**
* Passwort anderer Konten: Standard leerer Body → E-Mail mit Reset-Link (wie Passwort vergessen).
* Nur Super-Admins dürfen `newPassword` setzen (direktes Überschreiben des Passwort-Hashes).
*/
export async function managementPasswordReset(profileId, newPassword = null) {
const body = {}
if (newPassword != null && String(newPassword).trim() !== '') {
body.new_password = newPassword
}
return request(`/api/profiles/${profileId}/management-password-reset`, {
method: 'POST',
body: JSON.stringify(body),
})
}
export async function changePassword(newPassword) {
return request('/api/auth/pin', {
method: 'PUT',
body: JSON.stringify({ pin: newPassword }),
})
}
/** GET /api/auth/verify/{token} — keine Auth nötig; Token gehört zur URL des Bestätigungslinks */
export async function verifyEmail(token) {
const t = encodeURIComponent(token)
return request(`/api/auth/verify/${t}`, {
method: 'GET',
})
}
export async function resendVerification(email) {
return request('/api/auth/resend-verification', {
method: 'POST',
body: JSON.stringify({ email }),
})
}
// ============================================================================
// Clubs & Groups
// ============================================================================
export async function listClubs() {
return request('/api/clubs')
}
export async function getClub(id) {
return request(`/api/clubs/${id}`)
}
export async function createClub(data) {
return request('/api/clubs', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateClub(id, data) {
return request(`/api/clubs/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteClub(id) {
return request(`/api/clubs/${id}`, { method: 'DELETE' })
}
/** Vereinsmitglieder (API für Admin ohne eigene UI) */
export async function listClubMembers(clubId, { includeInactive = false } = {}) {
const q = includeInactive ? '?include_inactive=true' : ''
return request(`/api/clubs/${clubId}/members${q}`)
}
export async function getClubMember(clubId, profileId) {
return request(`/api/clubs/${clubId}/members/${profileId}`)
}
export async function addClubMember(clubId, payload) {
return request(`/api/clubs/${clubId}/members`, {
method: 'POST',
body: JSON.stringify(payload),
})
}
export async function updateClubMember(clubId, profileId, payload) {
return request(`/api/clubs/${clubId}/members/${profileId}`, {
method: 'PUT',
body: JSON.stringify(payload),
})
}
export async function removeClubMember(clubId, profileId) {
return request(`/api/clubs/${clubId}/members/${profileId}`, { method: 'DELETE' })
}
/** Aktive Vereine (öffentlich, für Registrierungswahl). */
export async function listPublicClubsDirectory() {
return request('/api/clubs/public-directory')
}
/** Vereinsinternes Mitgliederverzeichnis (Trainer-/Co-Auswahl). */
export async function clubMembersDirectory(clubId) {
return request(`/api/clubs/${clubId}/members/directory`)
}
/** Eigene Beitrittsanträge. */
export async function getMyClubJoinRequests() {
return request('/api/me/club-join-requests')
}
export async function createClubJoinRequest(payload) {
return request('/api/me/club-join-requests', {
method: 'POST',
body: JSON.stringify(payload),
})
}
export async function withdrawClubJoinRequest(requestId) {
return request(`/api/me/club-join-requests/${requestId}`, { method: 'DELETE' })
}
/** Offene Anträge (Vereins-/Plattform-Admin). */
export async function listClubJoinRequests(clubId) {
return request(`/api/clubs/${clubId}/join-requests`)
}
export async function acceptClubJoinRequest(clubId, requestId, roles = ['trainer']) {
return request(`/api/clubs/${clubId}/join-requests/${requestId}/accept`, {
method: 'POST',
body: JSON.stringify({ roles }),
})
}
export async function rejectClubJoinRequest(clubId, requestId) {
return request(`/api/clubs/${clubId}/join-requests/${requestId}/reject`, {
method: 'POST',
body: JSON.stringify({}),
})
}
/** Aggregierter Posteingang: offene Beitrittsanträge für Vereins-/Plattform-Admins. */
export async function getInboxJoinRequests() {
return request('/api/me/inbox/join-requests')
}
export async function listDivisions(clubId) {
const query = clubId ? `?club_id=${clubId}` : ''
return request(`/api/divisions${query}`)
}
export async function createDivision(data) {
return request('/api/divisions', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateDivision(id, data) {
return request(`/api/divisions/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteDivision(id) {
return request(`/api/divisions/${id}`, { method: 'DELETE' })
}
export async function listTrainingGroups(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/groups${query ? '?' + query : ''}`)
}
export async function getTrainingGroup(id) {
return request(`/api/groups/${id}`)
}
export async function createTrainingGroup(data) {
return request('/api/groups', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateTrainingGroup(id, data) {
return request(`/api/groups/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteTrainingGroup(id) {
return request(`/api/groups/${id}`, { method: 'DELETE' })
}
// ============================================================================
// Skills & Methods
// ============================================================================
export async function listSkills(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/skills${query ? '?' + query : ''}`)
}
/** Admin: Fähigkeiten hierarchisch sortiert (Hauptkategorie → Kategorie → Sortierung) */
export async function listSkillsCatalog(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/skills/catalog${query ? '?' + query : ''}`)
}
export async function getSkill(id) {
return request(`/api/skills/${id}`)
}
export async function createSkill(data) {
return request('/api/skills', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateSkill(id, data) {
return request(`/api/skills/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteSkill(id) {
return request(`/api/skills/${id}`, { method: 'DELETE' })
}
export async function listMethods(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/methods${query ? '?' + query : ''}`)
}
export async function getMethod(id) {
return request(`/api/methods/${id}`)
}
export async function createMethod(data) {
return request('/api/methods', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateMethod(id, data) {
return request(`/api/methods/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteMethod(id) {
return request(`/api/methods/${id}`, { method: 'DELETE' })
}
// ============================================================================
// Catalogs (Admin-verwaltbare Stammdaten)
// ============================================================================
// Focus Areas
export async function listFocusAreas(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/focus-areas${query ? '?' + query : ''}`)
}
export async function createFocusArea(data) {
return request('/api/focus-areas', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateFocusArea(id, data) {
return request(`/api/focus-areas/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteFocusArea(id) {
return request(`/api/focus-areas/${id}`, { method: 'DELETE' })
}
// Admin Hierarchy (Tree View)
export async function getAdminHierarchy() {
return request('/api/admin/hierarchy')
}
// Superadmin: KI Skill-Retrieval-Profile (Migration 068, exercise_ai)
export async function listAiSkillRetrievalProfiles() {
return request('/api/admin/ai-skill-retrieval-profiles')
}
export async function getAiSkillRetrievalProfile(profileId) {
return request(`/api/admin/ai-skill-retrieval-profiles/${profileId}`)
}
export async function createAiSkillRetrievalProfile(data) {
return request('/api/admin/ai-skill-retrieval-profiles', {
method: 'POST',
body: JSON.stringify(data),
})
}
export async function updateAiSkillRetrievalProfile(profileId, data) {
return request(`/api/admin/ai-skill-retrieval-profiles/${profileId}`, {
method: 'PUT',
body: JSON.stringify(data),
})
}
export async function deleteAiSkillRetrievalProfile(profileId) {
return request(`/api/admin/ai-skill-retrieval-profiles/${profileId}`, { method: 'DELETE' })
}
/** Superadmin: Übungs-Anreicherung per KI (Batch Skills) */
export async function listExerciseEnrichmentCandidates(params = {}) {
const q = new URLSearchParams()
Object.entries(params).forEach(([k, v]) => {
if (v === undefined || v === null || v === '') return
if (typeof v === 'boolean') q.set(k, v ? 'true' : 'false')
else q.set(k, String(v))
})
const qs = q.toString()
return request(`/api/admin/exercise-enrichment/candidates${qs ? `?${qs}` : ''}`)
}
export async function previewExerciseEnrichment(body) {
return request('/api/admin/exercise-enrichment/preview', {
method: 'POST',
body: JSON.stringify(body),
})
}
export async function applyExerciseEnrichment(body) {
return request('/api/admin/exercise-enrichment/apply', {
method: 'POST',
body: JSON.stringify(body),
})
}
export async function listExerciseEnrichmentCandidateIds(params = {}) {
const q = new URLSearchParams()
Object.entries(params).forEach(([k, v]) => {
if (v === undefined || v === null || v === '') return
if (typeof v === 'boolean') q.set(k, v ? 'true' : 'false')
else q.set(k, String(v))
})
const qs = q.toString()
return request(`/api/admin/exercise-enrichment/candidate-ids${qs ? `?${qs}` : ''}`)
}
export async function analyzeExerciseEnrichment(body) {
return request('/api/admin/exercise-enrichment/analyze', {
method: 'POST',
body: JSON.stringify(body),
})
}
/** Superadmin: KI Prompt-Templates (ai_prompts) */
export async function listAdminAiPrompts() {
return request('/api/admin/ai-prompts')
}
export async function getAdminAiPrompt(promptId) {
return request(`/api/admin/ai-prompts/${promptId}`)
}
export async function updateAdminAiPrompt(promptId, data) {
return request(`/api/admin/ai-prompts/${promptId}`, {
method: 'PUT',
body: JSON.stringify(data),
})
}
export async function previewAdminAiPrompt(promptId, data) {
return request(`/api/admin/ai-prompts/${promptId}/preview`, {
method: 'POST',
body: JSON.stringify(data || {}),
})
}
export async function resetAdminAiPromptTemplate(promptId) {
return request(`/api/admin/ai-prompts/${promptId}/reset-template`, { method: 'POST' })
}
export async function getAdminAiPromptPlaceholdersCatalog() {
return request('/api/admin/ai-prompts/catalog/placeholders')
}
// ============================================================================
// Reifegradmodelle / Fähigkeitsmatrix
// ============================================================================
export async function listMaturityModels(filters = {}) {
const query = new URLSearchParams(
Object.entries(filters).filter(([, v]) => v !== undefined && v !== null && v !== '')
).toString()
return request(`/api/maturity-models${query ? '?' + query : ''}`)
}
export async function resolveMaturityModel(filters = {}) {
const query = new URLSearchParams(
Object.entries(filters).filter(([, v]) => v !== undefined && v !== null && v !== '')
).toString()
return request(`/api/maturity-models/resolve${query ? '?' + query : ''}`)
}
export async function getMaturityModel(id) {
return request(`/api/maturity-models/${id}`)
}
export async function createMaturityModel(data) {
return request('/api/maturity-models', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateMaturityModel(id, data) {
return request(`/api/maturity-models/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteMaturityModel(id) {
return request(`/api/maturity-models/${id}`, { method: 'DELETE' })
}
export async function addMaturityModelSkill(modelId, data) {
return request(`/api/maturity-models/${modelId}/skills`, {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function removeMaturityModelSkill(modelId, skillId) {
return request(`/api/maturity-models/${modelId}/skills/${skillId}`, { method: 'DELETE' })
}
export async function upsertMaturityModelSkillLevels(modelId, data) {
return request(`/api/maturity-models/${modelId}/skill-levels`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
/** Hierarchische Zuordnung Modell → Fokus / Stilrichtung / Trainingsstil (training_types) */
export async function listMaturityModelContextBindings() {
return request('/api/maturity-model-context-bindings')
}
export async function upsertMaturityModelContextBinding(data) {
return request('/api/maturity-model-context-bindings', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function deleteMaturityModelContextBinding(id) {
return request(`/api/maturity-model-context-bindings/${id}`, { method: 'DELETE' })
}
export async function importMaturityModelBundle(payload) {
return request('/api/maturity-models/import', {
method: 'POST',
body: JSON.stringify(payload)
})
}
export async function exportMaturityModelBundle(modelId) {
return request(`/api/maturity-models/${modelId}/export`)
}
export async function exportResolvedMaturityBundle(filters = {}) {
const query = new URLSearchParams(
Object.entries(filters).filter(([, v]) => v !== undefined && v !== null && v !== '')
).toString()
return request(`/api/maturity-models/export-resolved${query ? '?' + query : ''}`)
}
/** Komplett: Fähigkeitskatalog + Reifegradmodelle + Kontext-Bindings (slug-/namensbasiert auf Ziel-DB) */
export async function exportMatrixStackBundle() {
return request('/api/admin/matrix-stack/export')
}
export async function importMatrixStackBundle(payload) {
return request('/api/admin/matrix-stack/import', {
method: 'POST',
body: JSON.stringify(payload)
})
}
/** Superadmin: flacher Export für zentrale Pflege (Beschreibungen, Gewichtungen) */
export async function exportMatrixEditorBundle() {
return request('/api/admin/matrix-editor/export')
}
export async function exportMatrixEditorCsv(part) {
const format = part === 'skills' ? 'csv_skills' : 'csv_matrix'
return requestText(`/api/admin/matrix-editor/export?format=${format}`)
}
export async function importMatrixEditorBundle(payload) {
return request('/api/admin/matrix-editor/import', {
method: 'POST',
body: JSON.stringify(payload)
})
}
// Style Directions (formerly Training Styles)
export async function listStyleDirections(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/training-styles${query ? '?' + query : ''}`)
}
// Backward-compatibility alias
export const listTrainingStyles = listStyleDirections
export async function createStyleDirection(data) {
return request('/api/training-styles', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateStyleDirection(id, data) {
return request(`/api/training-styles/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteStyleDirection(id) {
return request(`/api/training-styles/${id}`, { method: 'DELETE' })
}
// Training Characters
export async function listTrainingCharacters(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/training-characters${query ? '?' + query : ''}`)
}
export async function createTrainingCharacter(data) {
return request('/api/training-characters', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateTrainingCharacter(id, data) {
return request(`/api/training-characters/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteTrainingCharacter(id) {
return request(`/api/training-characters/${id}`, { method: 'DELETE' })
}
// Training Types (Breitensport, Leistungssport, etc.)
export async function listTrainingTypes(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/training-types${query ? '?' + query : ''}`)
}
export async function createTrainingType(data) {
return request('/api/training-types', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateTrainingType(id, data) {
return request(`/api/training-types/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteTrainingType(id) {
return request(`/api/training-types/${id}`, { method: 'DELETE' })
}
// Skill main categories (Hauptgruppen im Fähigkeitskatalog)
export async function listSkillMainCategories() {
return request('/api/skill-main-categories')
}
export async function createSkillMainCategory(data) {
return request('/api/skill-main-categories', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateSkillMainCategory(id, data) {
return request(`/api/skill-main-categories/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteSkillMainCategory(id) {
return request(`/api/skill-main-categories/${id}`, { method: 'DELETE' })
}
// Skill Categories
export async function listSkillCategories(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/skill-categories${query ? '?' + query : ''}`)
}
export async function createSkillCategory(data) {
return request('/api/skill-categories', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateSkillCategory(id, data) {
return request(`/api/skill-categories/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteSkillCategory(id) {
return request(`/api/skill-categories/${id}`, { method: 'DELETE' })
}
// Trainer Focus Areas
export async function listTrainerFocusAreas(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/trainer-focus-areas${query ? '?' + query : ''}`)
}
export async function assignTrainerFocusArea(data) {
return request('/api/trainer-focus-areas', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function deleteTrainerFocusArea(id) {
return request(`/api/trainer-focus-areas/${id}`, { method: 'DELETE' })
}
// Target Groups (Zielgruppen)
export async function listTargetGroups(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/target-groups${query ? '?' + query : ''}`)
}
export async function createTargetGroup(data) {
return request('/api/target-groups', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateTargetGroup(id, data) {
return request(`/api/target-groups/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteTargetGroup(id) {
return request(`/api/target-groups/${id}`, { method: 'DELETE' })
}
// Style Direction → Target Groups (M:N Assignments)
export async function listStyleDirectionTargetGroups(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/training-style-target-groups${query ? '?' + query : ''}`)
}
export async function createStyleDirectionTargetGroup(data) {
return request('/api/training-style-target-groups', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateStyleDirectionTargetGroup(id, data) {
return request(`/api/training-style-target-groups/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteStyleDirectionTargetGroup(id) {
return request(`/api/training-style-target-groups/${id}`, { method: 'DELETE' })
}
export async function getStyleDirectionsHierarchy(filters = {}) {
const query = new URLSearchParams(filters).toString()
return request(`/api/training-styles/hierarchy${query ? '?' + query : ''}`)
}
// Trainer Contexts (Fokussierte Ansichten)
export async function listTrainerContexts() {
return request('/api/trainer-contexts')
}
export async function createTrainerContext(data) {
return request('/api/trainer-contexts', {
method: 'POST',
body: JSON.stringify(data)
})
}
export async function updateTrainerContext(id, data) {
return request(`/api/trainer-contexts/${id}`, {
method: 'PUT',
body: JSON.stringify(data)
})
}
export async function deleteTrainerContext(id) {
return request(`/api/trainer-contexts/${id}`, { method: 'DELETE' })
}
// ============================================================================
// Version & Health
// ============================================================================
export async function getVersion() {
return request('/api/version')
}
export async function healthCheck() {
return request('/health')
}
export const api = {
// Auth
login,
register,
logout,
getCurrentProfile,
listProfiles,
listAdminUsers,
getAdminUserContentMeta,
listAdminUserContentSummary,
listAdminUserContentItems,
patchAdminUserContentItem,
deleteAdminUserContentItem,
updateProfile,
managementPasswordReset,
changePassword,
verifyEmail,
resendVerification,
// Clubs & Groups
listClubs,
getClub,
createClub,
updateClub,
deleteClub,
listClubMembers,
getClubMember,
addClubMember,
updateClubMember,
removeClubMember,
listPublicClubsDirectory,
clubMembersDirectory,
getMyClubJoinRequests,
createClubJoinRequest,
withdrawClubJoinRequest,
listClubJoinRequests,
acceptClubJoinRequest,
rejectClubJoinRequest,
getInboxJoinRequests,
listDivisions,
createDivision,
updateDivision,
deleteDivision,
listTrainingGroups,
getTrainingGroup,
createTrainingGroup,
updateTrainingGroup,
deleteTrainingGroup,
// Skills & Methods
listSkills,
listSkillsCatalog,
getSkill,
createSkill,
updateSkill,
deleteSkill,
listMethods,
getMethod,
createMethod,
updateMethod,
deleteMethod,
// Exercises + Medien/Archiv (Progression, KI) → frontend/src/api/exercises.js
...exercises,
// Training Planning → frontend/src/api/planning.js
...planning,
// Fähigkeiten-Profile & Vorschläge (Phase 3) → frontend/src/api/skillProfiles.js
...skillProfiles,
// Catalogs
listFocusAreas,
createFocusArea,
updateFocusArea,
deleteFocusArea,
getAdminHierarchy,
listAiSkillRetrievalProfiles,
getAiSkillRetrievalProfile,
createAiSkillRetrievalProfile,
updateAiSkillRetrievalProfile,
deleteAiSkillRetrievalProfile,
listExerciseEnrichmentCandidates,
previewExerciseEnrichment,
applyExerciseEnrichment,
listExerciseEnrichmentCandidateIds,
analyzeExerciseEnrichment,
listAdminAiPrompts,
getAdminAiPrompt,
updateAdminAiPrompt,
previewAdminAiPrompt,
resetAdminAiPromptTemplate,
getAdminAiPromptPlaceholdersCatalog,
listStyleDirections,
listTrainingStyles,
createStyleDirection,
updateStyleDirection,
deleteStyleDirection,
listTrainingCharacters,
createTrainingCharacter,
updateTrainingCharacter,
deleteTrainingCharacter,
listTrainingTypes,
createTrainingType,
updateTrainingType,
deleteTrainingType,
listSkillMainCategories,
createSkillMainCategory,
updateSkillMainCategory,
deleteSkillMainCategory,
listSkillCategories,
createSkillCategory,
updateSkillCategory,
deleteSkillCategory,
listTrainerFocusAreas,
assignTrainerFocusArea,
deleteTrainerFocusArea,
listTargetGroups,
createTargetGroup,
updateTargetGroup,
deleteTargetGroup,
listStyleDirectionTargetGroups,
createStyleDirectionTargetGroup,
updateStyleDirectionTargetGroup,
deleteStyleDirectionTargetGroup,
listMaturityModels,
listMaturityModelContextBindings,
upsertMaturityModelContextBinding,
deleteMaturityModelContextBinding,
importMaturityModelBundle,
exportMaturityModelBundle,
exportResolvedMaturityBundle,
exportMatrixStackBundle,
importMatrixStackBundle,
exportMatrixEditorBundle,
exportMatrixEditorCsv,
importMatrixEditorBundle,
resolveMaturityModel,
getMaturityModel,
createMaturityModel,
updateMaturityModel,
deleteMaturityModel,
addMaturityModelSkill,
removeMaturityModelSkill,
upsertMaturityModelSkillLevels,
getStyleDirectionsHierarchy,
listTrainerContexts,
createTrainerContext,
updateTrainerContext,
deleteTrainerContext,
// System
getVersion,
healthCheck,
// MediaWiki Import
previewMediaWikiImport: (category, importType = 'exercise', limit = 10) =>
request(`/api/import/mediawiki/preview?category=${encodeURIComponent(category)}&import_type=${importType}&limit=${limit}`),
executeMediaWikiImport: (data) =>
request('/api/import/mediawiki/execute', {
method: 'POST',
body: JSON.stringify(data)
}),
getMediaWikiImportStatus: (logId) =>
request(`/api/import/mediawiki/status/${logId}`),
listMediaWikiImportLogs: () =>
request('/api/import/mediawiki/logs'),
deleteMediaWikiImportReference: (refId) =>
request(`/api/import/mediawiki/references/${refId}`, { method: 'DELETE' }),
// Legal Documents (public)
getPublishedLegalDocument: (documentType) =>
request(`/api/legal-documents/${documentType}/published`),
// Legal Documents (superadmin)
listLegalDocuments: (documentType) =>
request(`/api/admin/legal-documents${documentType ? `?document_type=${documentType}` : ''}`),
createLegalDocument: (data) =>
request('/api/admin/legal-documents', { method: 'POST', body: JSON.stringify(data) }),
getLegalDocument: (id) =>
request(`/api/admin/legal-documents/${id}`),
updateLegalDocument: (id, data) =>
request(`/api/admin/legal-documents/${id}`, { method: 'PUT', body: JSON.stringify(data) }),
publishLegalDocument: (id, changeNote) =>
request(`/api/admin/legal-documents/${id}/publish`, {
method: 'POST',
body: JSON.stringify({ change_note: changeNote }),
}),
archiveLegalDocument: (id) =>
request(`/api/admin/legal-documents/${id}/archive`, { method: 'POST' }),
copyLegalDocumentAsDraft: (id) =>
request(`/api/admin/legal-documents/${id}/copy-as-draft`, { method: 'POST' }),
getLegalDocumentAudit: (id) =>
request(`/api/admin/legal-documents/${id}/audit`),
// P-13: Content-Melde-Backend
submitContentReport: (body) =>
request('/api/content-reports', { method: 'POST', body: JSON.stringify(body) }),
getInboxContentReports: () =>
request('/api/me/inbox/content-reports'),
getContentReport: (id) =>
request(`/api/content-reports/${id}`),
patchContentReport: (id, body) =>
request(`/api/content-reports/${id}`, { method: 'PATCH', body: JSON.stringify(body) }),
setLegalHoldFromReport: (id, body) =>
request(`/api/content-reports/${id}/legal-hold`, { method: 'POST', body: JSON.stringify(body) }),
}
export default api