- Incremented APP_VERSION to 0.8.10 and DB_SCHEMA_VERSION to 20260505037. - Added changelog entry for version 0.8.10 detailing database and API changes. - Refactored training framework program handling to support cloning training units from framework slots. - Improved permission checks for training units based on framework slot associations. - Introduced new API endpoint for creating training units from framework slots.
131 lines
4.2 KiB
SQL
131 lines
4.2 KiB
SQL
-- Migration 037: Rahmen-Slot-„Blueprint“ = eine training_units-Zeile (Ablauf wie echte Einheit)
|
|
-- training_framework_slot_exercises migriert nach training_unit_sections / training_unit_section_items,
|
|
-- dann entfernt.
|
|
|
|
-- ── Neue Spalten ───────────────────────────────────────────────────────────────
|
|
ALTER TABLE training_units
|
|
ADD COLUMN IF NOT EXISTS framework_slot_id INT REFERENCES training_framework_slots(id)
|
|
ON DELETE CASCADE,
|
|
ADD COLUMN IF NOT EXISTS origin_framework_slot_id INT REFERENCES training_framework_slots(id)
|
|
ON DELETE SET NULL;
|
|
|
|
-- Genau eine Blueprint-Einheit pro Slot (PostgreSQL UNIQUE erlaubt mehrere NULLs — hier Partial Index)
|
|
DROP INDEX IF EXISTS uq_training_units_blueprint_slot;
|
|
|
|
CREATE UNIQUE INDEX uq_training_units_blueprint_slot
|
|
ON training_units(framework_slot_id)
|
|
WHERE framework_slot_id IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_training_units_framework_blueprint_calendar
|
|
ON training_units(planned_date, group_id)
|
|
WHERE framework_slot_id IS NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_training_units_origin_slot
|
|
ON training_units(origin_framework_slot_id)
|
|
WHERE origin_framework_slot_id IS NOT NULL;
|
|
|
|
-- ── Nullable für Blueprint-Zeilen ────────────────────────────────────────────
|
|
ALTER TABLE training_units ALTER COLUMN planned_date DROP NOT NULL;
|
|
ALTER TABLE training_units ALTER COLUMN group_id DROP NOT NULL;
|
|
|
|
-- ── Für jeden Slot eine Blueprint-Einheit; vorhandene Übungen in erste Sektion ─
|
|
DO $$
|
|
DECLARE
|
|
rec RECORD;
|
|
new_uid INTEGER;
|
|
new_sec INTEGER;
|
|
BEGIN
|
|
FOR rec IN
|
|
SELECT s.id AS sid, fp.created_by AS fp_created_by
|
|
FROM training_framework_slots s
|
|
JOIN training_framework_programs fp ON fp.id = s.framework_program_id
|
|
LOOP
|
|
IF EXISTS (SELECT 1 FROM training_units tu WHERE tu.framework_slot_id = rec.sid) THEN
|
|
CONTINUE;
|
|
END IF;
|
|
|
|
INSERT INTO training_units (
|
|
group_id,
|
|
planned_date,
|
|
planned_time_start,
|
|
planned_time_end,
|
|
planned_focus,
|
|
status,
|
|
notes,
|
|
trainer_notes,
|
|
created_by,
|
|
plan_template_id,
|
|
framework_slot_id
|
|
)
|
|
VALUES (
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
'planned',
|
|
NULL,
|
|
NULL,
|
|
rec.fp_created_by,
|
|
NULL,
|
|
rec.sid
|
|
)
|
|
RETURNING id INTO new_uid;
|
|
|
|
INSERT INTO training_unit_sections (
|
|
training_unit_id,
|
|
order_index,
|
|
title,
|
|
guidance_notes
|
|
)
|
|
VALUES (new_uid, 0, 'Ablauf', NULL)
|
|
RETURNING id INTO new_sec;
|
|
|
|
INSERT INTO training_unit_section_items (
|
|
section_id,
|
|
order_index,
|
|
item_type,
|
|
exercise_id,
|
|
exercise_variant_id,
|
|
planned_duration_min,
|
|
actual_duration_min,
|
|
notes,
|
|
modifications,
|
|
note_body
|
|
)
|
|
SELECT
|
|
new_sec,
|
|
sf.order_index,
|
|
'exercise'::character varying(20),
|
|
sf.exercise_id,
|
|
sf.exercise_variant_id,
|
|
NULL::integer,
|
|
NULL::integer,
|
|
NULL::text,
|
|
NULL::text,
|
|
NULL::text
|
|
FROM training_framework_slot_exercises sf
|
|
WHERE sf.slot_id = rec.sid
|
|
ORDER BY sf.order_index;
|
|
END LOOP;
|
|
END $$;
|
|
|
|
DROP TABLE IF EXISTS training_framework_slot_exercises;
|
|
|
|
ALTER TABLE training_units DROP CONSTRAINT IF EXISTS chk_training_units_blueprint_vs_scheduled;
|
|
|
|
ALTER TABLE training_units
|
|
ADD CONSTRAINT chk_training_units_blueprint_vs_scheduled CHECK (
|
|
(
|
|
framework_slot_id IS NOT NULL
|
|
AND group_id IS NULL
|
|
AND planned_date IS NULL
|
|
AND origin_framework_slot_id IS NULL
|
|
)
|
|
OR (
|
|
framework_slot_id IS NULL
|
|
AND group_id IS NOT NULL
|
|
AND planned_date IS NOT NULL
|
|
)
|
|
);
|