- Introduced new maturity models feature with CRUD operations in the API. - Added routes and frontend components for managing maturity models. - Updated version to 0.7.1 with corresponding build date and schema version. - Enhanced admin navigation to include maturity models section. - Documented changes in the changelog for version 0.7.1.
142 lines
5.0 KiB
Python
142 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generiert Migration 023: Vollständiger Skills-Import mit Kategorisierung.
|
|
"""
|
|
import csv
|
|
from collections import defaultdict
|
|
|
|
# Lese CSV
|
|
import os
|
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
csv_path = os.path.join(script_dir, '..', '..', 'skills_mapping_clean.csv')
|
|
|
|
try:
|
|
with open(csv_path, 'r', encoding='utf-8') as f:
|
|
reader = csv.DictReader(f)
|
|
skills = list(reader)
|
|
except UnicodeDecodeError:
|
|
# Fallback zu latin-1 bei Encoding-Problemen
|
|
with open(csv_path, 'r', encoding='latin-1') as f:
|
|
reader = csv.DictReader(f)
|
|
skills = list(reader)
|
|
|
|
# Slug-Generierung
|
|
def to_slug(name):
|
|
"""Wandelt Namen in URL-friendly Slugs um."""
|
|
return name.lower().replace(' ', '_').replace('ä', 'ae').replace('ö', 'oe').replace('ü', 'ue').replace('ß', 'ss')
|
|
|
|
# Gruppiere nach Kategorien
|
|
by_main_cat = defaultdict(lambda: defaultdict(list))
|
|
sub_categories = {} # {sub_cat_name: (slug, main_cat)}
|
|
|
|
for s in skills:
|
|
main = s['main_category']
|
|
sub = s['sub_category']
|
|
by_main_cat[main][sub].append(s)
|
|
|
|
if sub not in sub_categories:
|
|
sub_categories[sub] = (to_slug(sub), main)
|
|
|
|
print("""-- Migration 023: Vollständiger Skills-Import
|
|
-- Purpose: Produktionsreifer Import aller 69 Skills mit vollständiger Kategorisierung
|
|
-- Source: Fähigkeitsmatrix https://karatetrainer.net/index.php?title=Fähigkeitsmatrix
|
|
-- Date: 2026-04-27
|
|
|
|
-- ======================================================================
|
|
-- CLEANUP: Alte Daten löschen
|
|
-- ======================================================================
|
|
|
|
-- Erst M:N-Beziehungen löschen
|
|
DELETE FROM exercise_skills;
|
|
|
|
-- Skills löschen (Cascades zu skill_level_definitions)
|
|
DELETE FROM skills;
|
|
|
|
-- Kategorien löschen
|
|
DELETE FROM skill_categories;
|
|
DELETE FROM skill_main_categories WHERE id > 0; -- Falls Tabelle existiert
|
|
|
|
-- ======================================================================
|
|
-- 1. HAUPT-KATEGORIEN
|
|
-- ======================================================================
|
|
|
|
INSERT INTO skill_main_categories (name, slug, description, sort_order) VALUES
|
|
('KARATE Fähigkeiten', 'karate', 'Karate-spezifische Techniken und Fähigkeiten', 1),
|
|
('ALLGEMEINE sportliche Fähigkeiten', 'allgemeine', 'Universelle sportliche und mentale Fähigkeiten', 2);
|
|
|
|
-- ======================================================================
|
|
-- 2. UNTERKATEGORIEN
|
|
-- ======================================================================
|
|
""")
|
|
|
|
# Sortiere Unterkategorien: Karate zuerst, dann Allgemeine
|
|
karate_subs = sorted([(name, slug, main) for name, (slug, main) in sub_categories.items() if main == 'karate'])
|
|
allgemeine_subs = sorted([(name, slug, main) for name, (slug, main) in sub_categories.items() if main == 'allgemeine'])
|
|
|
|
sort_order = 1
|
|
print("INSERT INTO skill_categories (name, slug, main_category_id, description, sort_order) VALUES")
|
|
|
|
for idx, (name, slug, main_cat) in enumerate(karate_subs + allgemeine_subs):
|
|
comma = "," if idx < len(karate_subs) + len(allgemeine_subs) - 1 else ";"
|
|
print(f"('{name}', '{slug}', (SELECT id FROM skill_main_categories WHERE slug='{main_cat}'), '', {sort_order}){comma}")
|
|
sort_order += 1
|
|
|
|
print("""
|
|
-- ======================================================================
|
|
-- 3. SKILLS
|
|
-- ======================================================================
|
|
|
|
INSERT INTO skills (name, description, category_id, main_category_id, focus_areas) VALUES""")
|
|
|
|
# Sortiere Skills: Karate zuerst, dann Allgemeine
|
|
karate_skills = []
|
|
for sub in [name for name, slug, main in karate_subs]:
|
|
karate_skills.extend(by_main_cat['karate'][sub])
|
|
|
|
allgemeine_skills = []
|
|
for sub in [name for name, slug, main in allgemeine_subs]:
|
|
allgemeine_skills.extend(by_main_cat['allgemeine'][sub])
|
|
|
|
all_skills = karate_skills + allgemeine_skills
|
|
|
|
for idx, s in enumerate(all_skills):
|
|
name = s['skill_name'].replace("'", "''") # SQL-Escape
|
|
sub_cat_slug = to_slug(s['sub_category'])
|
|
main_cat_slug = s['main_category']
|
|
focus = s['focus_areas']
|
|
|
|
comma = "," if idx < len(all_skills) - 1 else ";"
|
|
|
|
print(f"('{name}', '', (SELECT id FROM skill_categories WHERE slug='{sub_cat_slug}'), (SELECT id FROM skill_main_categories WHERE slug='{main_cat_slug}'), '[\"{ focus}\"]'::jsonb){comma}")
|
|
|
|
print("""
|
|
-- ======================================================================
|
|
-- 4. VERIFIKATION
|
|
-- ======================================================================
|
|
|
|
-- Sollte 69 Skills ergeben
|
|
DO $$
|
|
DECLARE
|
|
skill_count INT;
|
|
BEGIN
|
|
SELECT COUNT(*) INTO skill_count FROM skills;
|
|
|
|
IF skill_count != 69 THEN
|
|
RAISE WARNING 'FEHLER: % Skills gefunden, erwartet 69', skill_count;
|
|
ELSE
|
|
RAISE NOTICE 'OK: 69 Skills importiert';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- Zeige Verteilung
|
|
SELECT
|
|
mc.name AS hauptkategorie,
|
|
sc.name AS unterkategorie,
|
|
COUNT(s.id) AS anzahl_skills
|
|
FROM skills s
|
|
JOIN skill_categories sc ON s.category_id = sc.id
|
|
JOIN skill_main_categories mc ON s.main_category_id = mc.id
|
|
GROUP BY mc.name, sc.name, mc.sort_order, sc.sort_order
|
|
ORDER BY mc.sort_order, sc.sort_order;
|
|
""")
|