Files
training-software/cms/migrations/0001_initial.py
Paperclip CTO b087a63b56
Some checks failed
CI / Tests (Python 3.12) (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / OpenAPI Schema (push) Has been cancelled
feat(TRA-237): CMS content blocks, media upload pipeline, and course theme
- MediaAsset model with file metadata and AV scan status tracking
- ContentBlock model (richtext/image/video/embed/download) with ordered
  blocks per page and unique constraint on (page, order)
- CourseTheme one-to-one per course with primary/secondary color and logo
- validate_upload/save_upload helpers with extension and size enforcement
- scan_media_asset_task Celery stub (marks clean; replace with ClamAV)
- REST API: media upload, page content blocks CRUD, block patch/delete
- Admin registrations for all three models
- Factory-boy factories and pytest test suite for views, upload, and task

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 09:28:54 +02:00

108 lines
4.6 KiB
Python

import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("accounts", "0001_initial"),
("courses", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="MediaAsset",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("org_id", models.UUIDField(db_index=True)),
("file_name", models.CharField(max_length=255)),
("file_path", models.CharField(max_length=1000)),
("file_size", models.PositiveBigIntegerField()),
("mime_type", models.CharField(blank=True, max_length=100)),
("extension", models.CharField(blank=True, max_length=20)),
("scan_status", models.CharField(
choices=[
("pending", "Pending"), ("clean", "Clean"),
("infected", "Infected"), ("error", "Error"),
],
default="pending",
max_length=20,
)),
("scan_result", models.TextField(blank=True)),
("created_at", models.DateTimeField(auto_now_add=True)),
("uploaded_by", models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="media_assets",
to=settings.AUTH_USER_MODEL,
)),
],
options={"db_table": "cms_media_asset", "ordering": ["-created_at"]},
),
migrations.CreateModel(
name="ContentBlock",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("order", models.PositiveIntegerField(default=0)),
("block_type", models.CharField(
choices=[
("richtext", "Rich Text"), ("image", "Image"),
("video", "Video"), ("embed", "Embed"), ("download", "Download"),
],
max_length=20,
)),
("body", models.TextField(blank=True)),
("embed_url", models.URLField(blank=True, max_length=1000)),
("caption", models.CharField(blank=True, max_length=500)),
("extra", models.JSONField(blank=True, default=dict)),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("media_asset", models.ForeignKey(
blank=True, null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="blocks",
to="cms.mediaasset",
)),
("page", models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="content_blocks",
to="courses.page",
)),
],
options={"db_table": "cms_content_block", "ordering": ["order"]},
),
migrations.AddConstraint(
model_name="contentblock",
constraint=models.UniqueConstraint(
fields=("page", "order"), name="unique_page_block_order"
),
),
migrations.CreateModel(
name="CourseTheme",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("primary_color", models.CharField(default="#000000", max_length=7)),
("secondary_color", models.CharField(default="#ffffff", max_length=7)),
("extra", models.JSONField(blank=True, default=dict)),
("updated_at", models.DateTimeField(auto_now=True)),
("course", models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="theme",
to="courses.course",
)),
("logo", models.ForeignKey(
blank=True, null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="course_logos",
to="cms.mediaasset",
)),
],
options={"db_table": "cms_course_theme"},
),
]