diff --git a/.gitignore b/.gitignore index 9a5383af3..c6d7f2478 100644 --- a/.gitignore +++ b/.gitignore @@ -22,12 +22,14 @@ manager/src/static/assets manager/src/static/bootstrap* manager/src/static/examples manager/secrets -manager/src/django/secrets.py +manager/src/manager/secrets.py docker-compose.yml kubernetes/setup/ kubernetes/manager media -migrations +# Ignore runtime migrations directory (not Django source migrations) +/migrations +**/workspace/migrations pvd-mqtt/detect sample_data/xREF_* test_data diff --git a/REUSE.toml b/REUSE.toml index 4c64bf71a..68d92dc93 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -7,7 +7,7 @@ version = 1 path = [ "docs/doxygen/Doxyfile.common", "docs/doxygen/api_docs", - "manager/src/static/site.webmanifest", + "manager/src/manager/static/site.webmanifest", "tests/security/fuzzing/token", "**/*.env", "**/mp4", diff --git a/docs/development/vscode-setup.md b/docs/development/vscode-setup.md index 528b6c913..a6d19bd47 100644 --- a/docs/development/vscode-setup.md +++ b/docs/development/vscode-setup.md @@ -91,7 +91,7 @@ Create `.vscode/settings.json` in the project root, or press `Ctrl+Shift+P` → "python.terminal.activateEnvironment": true, "python.analysis.extraPaths": [ "${workspaceFolder}", - "${workspaceFolder}/manager/src/django", + "${workspaceFolder}/manager/src/manager", "${workspaceFolder}/tests", "${workspaceFolder}/scene_common/src", "${workspaceFolder}/controller/src", diff --git a/exclude_for_release.txt b/exclude_for_release.txt index e11e99329..873cc336c 100644 --- a/exclude_for_release.txt +++ b/exclude_for_release.txt @@ -17,7 +17,7 @@ docs/doxygen/html exclude_for_release.txt model_installer/models venv -manager/src/django/settings_local.py +manager/src/manager/settings_local.py secrets SECURITY.md *.bundle diff --git a/manager/Agents.md b/manager/Agents.md index 208285700..6a17ecb9c 100644 --- a/manager/Agents.md +++ b/manager/Agents.md @@ -5,6 +5,10 @@ SPDX-License-Identifier: Apache-2.0 # Manager Service - AI Agent Guide +## Documentation + +- [MIGRATIONS.md](MIGRATIONS.md) - Django migrations workflow and best practices + ## Service Overview The **Manager** service is the Django-based web UI and REST API gateway for Intel® SceneScape. It provides user-facing interfaces for system configuration, scene management, camera setup, and PostgreSQL-backed persistence for metadata and configuration. @@ -15,13 +19,13 @@ The **Manager** service is the Django-based web UI and REST API gateway for Inte ### Core Modules -1. **Django Application** (`src/django/`): +1. **Django Application** (`src/manager/`): - Scene management views and APIs - Camera configuration interfaces - User authentication and authorization - PostgreSQL ORM models -2. **REST API** (`src/django/api/`): +2. **REST API** (`src/manager/api/`): - RESTful endpoints for external integrations - Scene CRUD operations - Camera calibration triggers @@ -225,11 +229,12 @@ class Camera(models.Model): ### Adding New Database Model -1. Define model in `src/django/scenescape/models.py` +1. Define model in `src/manager/models.py` 2. Create migration: `docker compose exec manager python manage.py makemigrations` -3. Review migration file in `src/django/scenescape/migrations/` -4. Apply: `docker compose exec manager python manage.py migrate` -5. Update admin interface if needed: `src/django/scenescape/admin.py` +3. Review migration file in `src/manager/migrations/` +4. Commit migration file to version control +5. Apply: `docker compose exec manager python manage.py migrate` +6. Update admin interface if needed: `src/manager/admin.py` ### Modifying Web UI diff --git a/manager/Dockerfile b/manager/Dockerfile index bdde9a86c..fc497d010 100644 --- a/manager/Dockerfile +++ b/manager/Dockerfile @@ -144,15 +144,9 @@ RUN : \ # Copy application code RUN mkdir -p $SCENESCAPE_HOME/manager -COPY ./manager/src/django/*.py \ - ./manager/src/setup.py \ - ./version.txt $SCENESCAPE_HOME/manager/ -COPY ./manager/src/django/ppl_generator/* $SCENESCAPE_HOME/manager/ppl_generator/ -COPY ./manager/src/management/ $SCENESCAPE_HOME/manager/management -COPY ./manager/src/templates/ $SCENESCAPE_HOME/manager/templates -COPY ./manager/src/static/ $SCENESCAPE_HOME/manager/static -COPY ./manager/src/templatetags/ $SCENESCAPE_HOME/manager/templatetags -COPY ./manager/src/django/manage.py $SCENESCAPE_HOME +COPY ./manager/src/manager $SCENESCAPE_HOME/manager +COPY ./manager/src/manage.py $SCENESCAPE_HOME/manage.py +COPY ./version.txt $SCENESCAPE_HOME/manager/ COPY --from=scenescape-manager-builder /usr/local/lib/python3.11/site-packages/fast_geometry /usr/local/lib/python3.11/site-packages/fast_geometry COPY --from=scenescape-manager-builder /usr/local/lib/python3.11/site-packages/scene_common /usr/local/lib/python3.11/site-packages/scene_common diff --git a/manager/MIGRATIONS.md b/manager/MIGRATIONS.md new file mode 100644 index 000000000..487ed9f9a --- /dev/null +++ b/manager/MIGRATIONS.md @@ -0,0 +1,180 @@ +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation + +# SPDX-License-Identifier: Apache-2.0 + +# Django Migrations Guide + +## Overview + +SceneScape uses Django's migration system to manage database schema changes. Migration files are version-controlled and applied at runtime to ensure consistent database upgrades across releases. + +## Important: Proper Migration Usage + +**DO NOT** run `makemigrations` at runtime or in production. Migrations should be: + +1. Generated during development +2. Reviewed and tested +3. Committed to version control +4. Built into the Docker image +5. Applied at runtime via `migrate` only + +## Creating Migrations + +### For Local Development + +When you modify Django models in `src/manager/models.py`, follow these steps: + +1. **Make your model changes** in `src/manager/models.py` + +2. **Generate migration file** using the generate_migrations.sh script: + + ```bash + bash manager/tools/generate_migrations.sh + ``` + +3. **Review the generated migration** in `src/manager/migrations/`: + + ```bash + ls -la manager/src/manager/migrations/ + ``` + +4. ** Re-build manager** + + ```bash + make manager + ``` + +5. **Verify the migration is being applied **: + + ```bash + docker compose down web && docker compose up web + ``` + +6. **Check migration status**: + + ```bash + bash manager/tools/generate_migrations.sh --show --network scenescape_scenescape --dbhost pgserver --dbport 5432 + ``` + +7. **Commit the migration file** to version control: + ```bash + git add manager/src/manager/migrations/XXXX_*.py + git commit -m "Add migration for [describe changes]" + ``` + +### For CI/CD and Release Process + +Migration generation should be automated as part of the release build: + +1. **In CI/CD pipeline**, after model changes are merged: + + ```bash + # If migrations are needed, generate them + bash manager/tools/generate_migrations.sh + + # Build the manager image + make manager + + # Review migrations + manager/src/manager/migrations + + # Commit and push the generated migrations + git add manager/src/manager/migrations/ + git commit -m "Generate migrations for release" + git push + ``` + +2. **Rebuild the image** with the new migrations included + +## Migration Naming Convention + +Django automatically names migrations as: + +- `0001_initial.py` - Initial schema +- `0002_.py` - Subsequent changes +- `0003_.py` - More changes +- etc. + +For releases, you may want to include version information in the description: + +```bash +docker compose exec manager python manage.py makemigrations manager --name release_2026_1_0 +``` + +This creates: `0002_release_2026_1_0.py` + +## Applying Migrations + +Migrations are applied automatically at container startup via the `migrate` command in `config/scenescape-init`. + +To manually apply migrations: + +```bash +docker exec -it -w /home/scenescape/SceneScape scenescape-web-1 \ +python manage.py migrate +``` + +## Checking Migration Status + +View all migrations and their application status: + +```bash +docker exec -it -w /home/scenescape/SceneScape scenescape-web-1 \ +python manage.py showmigrations +``` + +Example output: + +``` +manager + [X] 0001_initial + [X] 0002_release_2026_1_0 + [ ] 0003_add_new_field +``` + +## Troubleshooting + +### Migration conflicts + +If multiple developers create migrations in parallel: + +1. Merge the code +2. Run `makemigrations --merge` to create a merge migration +3. Test the merge migration +4. Commit the merge migration file + +### Reverting migrations + +```bash +# Revert to a specific migration +docker exec -it -w /home/scenescape/SceneScape scenescape-web-1 \ +python manage.py migrate manager 0001_initial + +# Revert all migrations for an app +docker exec -it -w /home/scenescape/SceneScape scenescape-web-1 \ +python manage.py migrate manager zero +``` + +### Fake migrations + +In rare cases (like database schema already matches): + +```bash +docker exec -it -w /home/scenescape/SceneScape scenescape-web-1 \ +python manage.py migrate manager --fake +``` + +## Best Practices + +1. **Always review generated migrations** before committing +2. **Test migrations** on a copy of production data +3. **Keep migrations small** - one logical change per migration +4. **Never edit applied migrations** - create a new migration instead +5. **Document complex migrations** with comments in the migration file +6. **Backup database** before applying migrations in production + +## References + +- [Django Migrations Documentation](https://docs.djangoproject.com/en/5.2/topics/migrations/) +- [Django makemigrations Command](https://docs.djangoproject.com/en/5.2/ref/django-admin/#makemigrations) +- [Django migrate Command](https://docs.djangoproject.com/en/5.2/ref/django-admin/#migrate) diff --git a/manager/Makefile b/manager/Makefile index 65fb67649..a3ada7cc3 100644 --- a/manager/Makefile +++ b/manager/Makefile @@ -6,7 +6,7 @@ RUNTIME_OS_IMAGE = python:3.11-slim-bookworm TARGET = scenescape-manager-runtime SHELL = /bin/bash CERTDOMAIN = scenescape.intel.com -JSLIBDIR = src/static +JSLIBDIR = src/manager/static CURL_FLAGS = --connect-timeout 5 --max-time 120 --retry 5 --retry-delay 0 FORCE_VAAPI ?= 0 THREEJS_VERSION = 168 diff --git a/manager/config/scenescape-init b/manager/config/scenescape-init index a32587206..0c00bc8d1 100755 --- a/manager/config/scenescape-init +++ b/manager/config/scenescape-init @@ -244,21 +244,26 @@ fi export -n DBPASS SUPASS if [ -n "$DBTYPE" ]; then - cd ${MANAGERDIR} + # Determine "first run" using the marker (or another check) CREATEDB=0 - MIGRATIONS=${DBROOT}/migrations/__init__.py - if [ ! -e ${MIGRATIONS} ] ; then - CREATEDB=1 + MIGRATIONS_MARKER="${DBROOT}/migrations/__init__.py" + if [ ! -e "${MIGRATIONS_MARKER}" ]; then + CREATEDB=1 + mkdir -p "$(dirname "${MIGRATIONS_MARKER}")" + touch "${MIGRATIONS_MARKER}" fi - if [ ${CREATEDB} = 1 ] ; then - mkdir -p ${DBROOT}/migrations - touch ${MIGRATIONS} - echo "Checking if database is empty..." - if ! (./manage.py showmigrations | grep -q '\[X\]'); then - echo "Database is empty — running initial migrations..." - (./manage.py makemigrations manager) - (./manage.py migrate) - fi + + # ALWAYS apply migrations + cd ${MANAGERDIR} + echo "==> Applying pending migrations..." + ./manage.py migrate --noinput + + if [ "${CREATEDB}" -eq 1 ] && [ -n "${EXAMPLEDB:-}" ]; then + echo "==> Preloading example DB..." + mkdir -p "${DBROOT}/media" + tar -C "${DBROOT}/media" -xf "${EXAMPLEDB}" + ./manage.py loaddata "${DBROOT}/media/data.json" + rm -f "${DBROOT}/media/data.json" "${DBROOT}/media/meta.json" fi ./manage.py updatedbstatus --not-ready diff --git a/manager/src/django/manage.py b/manager/src/manage.py similarity index 100% rename from manager/src/django/manage.py rename to manager/src/manage.py diff --git a/manager/src/django/__init__.py b/manager/src/manager/__init__.py similarity index 100% rename from manager/src/django/__init__.py rename to manager/src/manager/__init__.py diff --git a/manager/src/django/admin.py b/manager/src/manager/admin.py similarity index 100% rename from manager/src/django/admin.py rename to manager/src/manager/admin.py diff --git a/manager/src/django/api.py b/manager/src/manager/api.py similarity index 100% rename from manager/src/django/api.py rename to manager/src/manager/api.py diff --git a/manager/src/django/calculate_intrinsics_view.py b/manager/src/manager/calculate_intrinsics_view.py similarity index 100% rename from manager/src/django/calculate_intrinsics_view.py rename to manager/src/manager/calculate_intrinsics_view.py diff --git a/manager/src/django/context_processors.py b/manager/src/manager/context_processors.py similarity index 100% rename from manager/src/django/context_processors.py rename to manager/src/manager/context_processors.py diff --git a/manager/src/django/fields.py b/manager/src/manager/fields.py similarity index 100% rename from manager/src/django/fields.py rename to manager/src/manager/fields.py diff --git a/manager/src/django/forms.py b/manager/src/manager/forms.py similarity index 100% rename from manager/src/django/forms.py rename to manager/src/manager/forms.py diff --git a/manager/src/django/kubeclient.py b/manager/src/manager/kubeclient.py similarity index 100% rename from manager/src/django/kubeclient.py rename to manager/src/manager/kubeclient.py diff --git a/manager/src/management/__init.py__ b/manager/src/manager/management/__init.py__ similarity index 100% rename from manager/src/management/__init.py__ rename to manager/src/manager/management/__init.py__ diff --git a/manager/src/management/commands/__init.py__ b/manager/src/manager/management/commands/__init.py__ similarity index 100% rename from manager/src/management/commands/__init.py__ rename to manager/src/manager/management/commands/__init.py__ diff --git a/manager/src/management/commands/createuser.py b/manager/src/manager/management/commands/createuser.py similarity index 100% rename from manager/src/management/commands/createuser.py rename to manager/src/manager/management/commands/createuser.py diff --git a/manager/src/management/commands/db2config.py b/manager/src/manager/management/commands/db2config.py similarity index 100% rename from manager/src/management/commands/db2config.py rename to manager/src/manager/management/commands/db2config.py diff --git a/manager/src/management/commands/kubecommand.py b/manager/src/manager/management/commands/kubecommand.py similarity index 100% rename from manager/src/management/commands/kubecommand.py rename to manager/src/manager/management/commands/kubecommand.py diff --git a/manager/src/management/commands/updatedbstatus.py b/manager/src/manager/management/commands/updatedbstatus.py similarity index 100% rename from manager/src/management/commands/updatedbstatus.py rename to manager/src/manager/management/commands/updatedbstatus.py diff --git a/manager/src/django/mesh_generator.py b/manager/src/manager/mesh_generator.py similarity index 100% rename from manager/src/django/mesh_generator.py rename to manager/src/manager/mesh_generator.py diff --git a/manager/src/django/middleware.py b/manager/src/manager/middleware.py similarity index 100% rename from manager/src/django/middleware.py rename to manager/src/manager/middleware.py diff --git a/manager/src/manager/migrations/0001_initial.py b/manager/src/manager/migrations/0001_initial.py new file mode 100644 index 000000000..86344ec56 --- /dev/null +++ b/manager/src/manager/migrations/0001_initial.py @@ -0,0 +1,424 @@ +#!/bin/bash +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Script to generate Django migrations +# This should be run during development or as part of the release process +# DO NOT run this in production or at container startup + +import django.core.validators +import django.db.models.deletion +import manager.fields +import manager.models +import manager.validators +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('sessions', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Asset3D', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200, unique=True, verbose_name='Class Name')), + ('x_size', models.FloatField(default=1.0, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Object size in x-axis')), + ('y_size', models.FloatField(default=1.0, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Object size in y-axis')), + ('z_size', models.FloatField(default=1.0, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Object size in z-axis')), + ('x_buffer_size', models.FloatField(default=0.0, verbose_name='Object buffer size in x-axis')), + ('y_buffer_size', models.FloatField(default=0.0, verbose_name='Object buffer size in y-axis')), + ('z_buffer_size', models.FloatField(default=0.0, verbose_name='Object buffer size in z-axis')), + ('mark_color', models.CharField(blank=True, default='#888888', max_length=20, verbose_name='Mark Color')), + ('model_3d', models.FileField(blank=True, null=True, upload_to='', validators=[django.core.validators.FileExtensionValidator(['glb']), manager.validators.validate_glb])), + ('rotation_x', models.FloatField(blank=True, default=0.0, null=True, verbose_name='X Rotation (degrees)')), + ('rotation_y', models.FloatField(blank=True, default=0.0, null=True, verbose_name='Y Rotation (degrees)')), + ('rotation_z', models.FloatField(blank=True, default=0.0, null=True, verbose_name='Z Rotation (degrees)')), + ('translation_x', models.FloatField(blank=True, default=0.0, null=True, verbose_name='X Translation (meters)')), + ('translation_y', models.FloatField(blank=True, default=0.0, null=True, verbose_name='Y Translation (meters)')), + ('translation_z', models.FloatField(blank=True, default=0.0, null=True, verbose_name='Z Translation (meters)')), + ('scale', models.FloatField(blank=True, default=1.0, null=True, verbose_name='Scale')), + ('rotation_from_velocity', models.BooleanField(choices=[(True, 'Yes'), (False, 'No')], default=False, null=True)), + ('tracking_radius', models.FloatField(default=2.0, verbose_name='Tracking radius (meters)')), + ('shift_type', models.IntegerField(choices=[(1, 'Type 1 (default)'), (2, 'Type 2 (may work better for wide and short objects)')], default=1, null=True)), + ('project_to_map', models.BooleanField(choices=[(True, 'Yes'), (False, 'No')], default=False, null=True)), + ('geometric_center', manager.fields.ListField(base_field=models.FloatField(), blank=True, default=manager.models.default_geometric_center, help_text='Geometric center offset [x, y, z] in meters from bottom center', null=True, size=None)), + ('mass', models.FloatField(blank=True, default=1.0, null=True, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Mass (kg)')), + ('center_of_mass', manager.fields.ListField(base_field=models.FloatField(), blank=True, default=manager.models.default_center_of_mass, help_text='Center of mass offset [x, y, z] in meters from geometric center', null=True, size=None)), + ('is_static', models.BooleanField(blank=True, choices=[(True, 'Yes'), (False, 'No')], default=False, help_text='Whether object can move on its own', null=True, verbose_name='Is Static')), + ('ttl', models.FloatField(blank=True, default=0.0, help_text='Time to live for track expiration (0 = infinite)', null=True, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Time to Live (seconds)')), + ('linear_damping', models.FloatField(blank=True, default=0.05, help_text='Resistance to linear motion (0.0 - 1.0)', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(1.0)], verbose_name='Linear Damping')), + ('angular_damping', models.FloatField(blank=True, default=0.05, help_text='Resistance to angular motion (0.0 - 1.0)', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(1.0)], verbose_name='Angular Damping')), + ('coefficient_of_restitution', models.FloatField(blank=True, default=0.5, help_text='Bounciness for collisions (0.0 - 1.0)', null=True, validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(1.0)], verbose_name='Coefficient of Restitution')), + ('friction_coefficients', manager.fields.ListField(base_field=models.FloatField(), blank=True, default=manager.models.default_friction_coefficients, help_text='Friction coefficients [static, dynamic]', null=True, size=None)), + ], + ), + migrations.CreateModel( + name='BoundingBox', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='BoundingBoxPoints', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sequence', models.IntegerField(blank=True, default=None, null=True)), + ('x', models.FloatField(blank=True, default=None, null=True)), + ('y', models.FloatField(blank=True, default=None, null=True)), + ], + ), + migrations.CreateModel( + name='Sensor', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sensor_id', models.CharField(default=None, max_length=20, unique=True, verbose_name='Sensor ID')), + ('name', models.CharField(max_length=200, unique=True)), + ('type', models.CharField(choices=[('camera', 'Camera'), ('generic', 'generic')], max_length=200)), + ('icon', models.ImageField(blank=True, default=None, null=True, upload_to='')), + ], + ), + migrations.CreateModel( + name='DataLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.FloatField(db_index=True)), + ], + ), + migrations.CreateModel( + name='DatabaseStatus', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('is_ready', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='FailedLogin', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('ip', models.GenericIPAddressField(null=True)), + ('delay', models.FloatField(default=0.0)), + ], + options={ + 'verbose_name': 'FailedLogin Entry', + 'verbose_name_plural': 'FailedLogin Entries', + 'db_table': 'db_failedlogin_entry', + }, + ), + migrations.CreateModel( + name='MobileObject', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.FloatField(db_index=True)), + ('pid', models.IntegerField(default=None)), + ('x', models.FloatField(blank=True, default=None, null=True)), + ('y', models.FloatField(blank=True, default=None, null=True)), + ('previous', models.OneToOneField(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, to='manager.mobileobject')), + ], + ), + migrations.CreateModel( + name='Scene', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=200, unique=True)), + ('map_type', models.CharField(choices=[('map_upload', 'Map Upload'), ('geospatial_map', 'Geospatial Map')], default='map_upload', max_length=20, null=True, verbose_name='Map Type')), + ('thumbnail', models.ImageField(default=None, editable=False, null=True, upload_to='')), + ('map', models.FileField(blank=True, default=None, null=True, upload_to='', validators=[django.core.validators.FileExtensionValidator(['glb', 'png', 'jpeg', 'jpg', 'zip', 'ply', 'mp4', 'mov', 'mkv', 'webm', 'avi']), manager.validators.validate_map_file], verbose_name='Scene map as .glb or .ply or image or .zip or video')), + ('scale', models.FloatField(blank=True, default=None, null=True, validators=[django.core.validators.MinValueValidator(5e-324)], verbose_name='Pixels per meter')), + ('use_tracker', models.BooleanField(blank=True, choices=[(True, 'Yes'), (False, 'No')], default=True, verbose_name='Use tracker')), + ('rotation_x', models.FloatField(default=0.0, null=True, verbose_name='X Rotation (degrees)')), + ('rotation_y', models.FloatField(default=0.0, null=True, verbose_name='Y Rotation (degrees)')), + ('rotation_z', models.FloatField(default=0.0, null=True, verbose_name='Z Rotation (degrees)')), + ('translation_x', models.FloatField(default=0.0, null=True, verbose_name='X Translation (meters)')), + ('translation_y', models.FloatField(default=0.0, null=True, verbose_name='Y Translation (meters)')), + ('translation_z', models.FloatField(default=0.0, null=True, verbose_name='Z Translation (meters)')), + ('scale_x', models.FloatField(default=1.0, null=True, verbose_name='X Scale')), + ('scale_y', models.FloatField(default=1.0, null=True, verbose_name='Y Scale')), + ('scale_z', models.FloatField(default=1.0, null=True, verbose_name='Z Scale')), + ('map_processed', models.DateTimeField(editable=False, null=True, verbose_name='Last Processed at')), + ('output_lla', models.BooleanField(choices=[(True, 'Yes'), (False, 'No')], default=False, null=True, verbose_name='Output geospatial coordinates')), + ('map_corners_lla', models.JSONField(blank=True, default=None, help_text="Provide the array of four map corners geospatial coordinates (lat, long, alt).\nRequired only if 'Output geospatial coordinates' is set to `Yes`.\nExpected order: starting from the bottom-left corner counterclockwise.\nExpected JSON format: '[ [lat1, lon1, alt1], [lat2, lon2, alt2], [lat3, lon3, alt3], [lat4, lon4, alt4] ]'", null=True, validators=[manager.validators.validate_map_corners_lla], verbose_name='Geospatial coordinates of the four map corners in JSON format')), + ('geospatial_provider', models.CharField(blank=True, choices=[('google', 'Google Maps'), ('mapbox', 'Mapbox')], default='google', help_text='The map provider used for geospatial maps (google or mapbox)', max_length=20, null=True, verbose_name='Geospatial Map Provider')), + ('map_zoom', models.FloatField(blank=True, default=15.0, help_text='Zoom level for the geospatial map view', null=True, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Map Zoom Level')), + ('map_center_lat', models.FloatField(blank=True, default=None, help_text='Center latitude for the geospatial map view', null=True, verbose_name='Map Center Latitude')), + ('map_center_lng', models.FloatField(blank=True, default=None, help_text='Center longitude for the geospatial map view', null=True, verbose_name='Map Center Longitude')), + ('map_bearing', models.FloatField(blank=True, default=0.0, help_text='Rotation angle for the geospatial map view in degrees', null=True, verbose_name='Map Bearing/Rotation (degrees)')), + ('trs_matrix', models.JSONField(blank=True, default=None, editable=False, help_text='4x4 transformation matrix (translation-rotation-scale) stored as JSON [[...], [...], [...], [...]]', null=True, verbose_name='Transformation matrix (Translation, Rotation, Scale) coordinates to LLA (Latitude, Longitude, Altitude)')), + ('camera_calibration', models.CharField(choices=[('AprilTag', 'AprilTag'), ('Markerless', 'Markerless'), ('Manual', 'Manual')], default='Manual', max_length=20, verbose_name='Calibration Type')), + ('polycam_data', models.FileField(blank=True, null=True, upload_to='', validators=[django.core.validators.FileExtensionValidator(['zip'])])), + ('dataset_dir', models.CharField(blank=True, editable=False, max_length=200)), + ('output_dir', models.CharField(blank=True, editable=False, max_length=200)), + ('output', models.CharField(blank=True, editable=False, max_length=500, null=True)), + ('retrieval_conf', models.JSONField(blank=True, editable=False, null=True)), + ('global_descriptor_file', models.FileField(blank=True, editable=False, null=True, upload_to='', validators=[django.core.validators.FileExtensionValidator(['h5'])])), + ('number_of_localizations', models.IntegerField(blank=True, default=50, null=True, verbose_name='Number Of Localizations')), + ('global_feature', models.CharField(blank=True, default='netvlad', max_length=200, verbose_name='Global Feature Matching Algorithm')), + ('local_feature', models.JSONField(blank=True, default=manager.models.Scene._getDefaultSiftDict, null=True)), + ('matcher', models.JSONField(blank=True, default=manager.models.Scene._getDefaultNnRatioDict, null=True)), + ('minimum_number_of_matches', models.IntegerField(blank=True, default=20, null=True, verbose_name='Minimum Number Of Matches')), + ('polycam_hash', models.CharField(blank=True, editable=False, max_length=100, null=True)), + ('apriltag_size', models.FloatField(blank=True, default=0.162, max_length=10, null=True, verbose_name='AprilTag Size (meters)')), + ('regulated_rate', models.FloatField(blank=True, default=30, validators=[django.core.validators.MinValueValidator(0.001)], verbose_name='Regulate Rate (Hz)')), + ('external_update_rate', models.FloatField(blank=True, default=30, validators=[django.core.validators.MinValueValidator(0.001)], verbose_name='Max External Update Rate (Hz)')), + ('inlier_threshold', models.FloatField(blank=True, default=0.5, validators=[django.core.validators.MinValueValidator(0.0)], verbose_name='Feature Match Confidence Threshold')), + ], + ), + migrations.CreateModel( + name='SceneImport', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('zipFile', models.FileField(null=True, upload_to=manager.models.sanitizeZipPath)), + ], + ), + migrations.CreateModel( + name='Region', + fields=[ + ('boundingbox_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.boundingbox')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('buffer_size', models.FloatField(default=0.0, validators=[django.core.validators.MinValueValidator(0)])), + ('height', models.FloatField(default=1.0, validators=[django.core.validators.MinValueValidator(0.001)])), + ('volumetric', models.BooleanField(choices=[(True, 'Yes'), (False, 'No')], default=False, null=True)), + ('scene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='regions', to='manager.scene')), + ], + bases=('manager.boundingbox',), + ), + migrations.CreateModel( + name='Cam', + fields=[ + ('sensor_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.sensor')), + ('command', models.CharField(default=None, max_length=512, null=True, verbose_name='Camera (Video Source)')), + ('camerachain', models.CharField(default=None, max_length=64, null=True, verbose_name='Camera Chain')), + ('threshold', models.FloatField(blank=True, default=None, null=True)), + ('aspect', models.CharField(blank=True, default=None, max_length=64, null=True)), + ('cv_subsystem', models.CharField(choices=[('AUTO', 'AUTO'), ('GPU', 'GPU'), ('CPU', 'CPU')], default='AUTO', max_length=64, null=True, verbose_name='Decode Device')), + ('undistort', models.BooleanField(default=False, verbose_name='Undistort')), + ('transforms', manager.fields.ListField(base_field=models.FloatField(), blank=True, default=list, size=None)), + ('transform_type', models.CharField(choices=[('matrix', 'Matrix'), ('euler', 'Euler Angles'), ('quaternion', 'Quaternion'), ('3d-2d point correspondence', '3D-2D Point Correspondence')], default='3d-2d point correspondence', max_length=26)), + ('width', models.IntegerField(default=640)), + ('height', models.IntegerField(default=480)), + ('scene_x', models.IntegerField(blank=True, default=None, null=True)), + ('scene_y', models.IntegerField(blank=True, default=None, null=True)), + ('scene_z', models.IntegerField(blank=True, default=None, null=True)), + ('intrinsics_fx', models.FloatField(blank=True, default=None, null=True, validators=[django.core.validators.MinValueValidator(0.001)])), + ('intrinsics_fy', models.FloatField(blank=True, default=None, null=True, validators=[django.core.validators.MinValueValidator(0.001)])), + ('intrinsics_cx', models.FloatField(blank=True, default=None, null=True, validators=[django.core.validators.MinValueValidator(0.001)])), + ('intrinsics_cy', models.FloatField(blank=True, default=None, null=True, validators=[django.core.validators.MinValueValidator(0.001)])), + ('distortion_k1', models.FloatField(blank=True, default=None, null=True)), + ('distortion_k2', models.FloatField(blank=True, default=None, null=True)), + ('distortion_p1', models.FloatField(blank=True, default=None, null=True)), + ('distortion_p2', models.FloatField(blank=True, default=None, null=True)), + ('distortion_k3', models.FloatField(blank=True, default=None, null=True)), + ('sensor', models.CharField(blank=True, max_length=512, null=True)), + ('sensorchain', models.CharField(blank=True, max_length=64, null=True)), + ('sensorattrib', models.CharField(blank=True, max_length=64, null=True)), + ('window', models.BooleanField(default=False)), + ('usetimestamps', models.BooleanField(default=False)), + ('virtual', models.CharField(blank=True, max_length=512, null=True)), + ('debug', models.BooleanField(default=False)), + ('override_saved_intrinstics', models.BooleanField(default=False)), + ('frames', models.IntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ('stats', models.BooleanField(default=False)), + ('waitforstable', models.BooleanField(default=False)), + ('preprocess', models.BooleanField(default=False)), + ('realtime', models.BooleanField(default=False)), + ('faketime', models.BooleanField(default=False)), + ('modelconfig', models.CharField(blank=True, default='model_config.json', max_length=512, null=True, verbose_name='Model Config')), + ('rootcert', models.CharField(blank=True, max_length=64, null=True)), + ('cert', models.CharField(blank=True, max_length=64, null=True)), + ('cvcores', models.IntegerField(blank=True, null=True)), + ('ovcores', models.IntegerField(blank=True, null=True)), + ('unwarp', models.BooleanField(default=False)), + ('ovmshost', models.CharField(blank=True, max_length=64, null=True)), + ('framerate', models.IntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ('maxcache', models.IntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), + ('filter', models.CharField(choices=[('bottom', 'Bottom'), ('top', 'Top'), ('none', 'None (default)')], default='none', max_length=64)), + ('disable_rotation', models.BooleanField(default=False)), + ('maxdistance', models.FloatField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(0.001)])), + ('use_camera_pipeline', models.BooleanField(blank=True, default=False, help_text='Enable to directly apply the Camera Pipeline string in the camera VA pipeline instead of generating it automatically from camera settings.', null=True, verbose_name='Use Camera Pipeline')), + ('camera_pipeline', models.TextField(blank=True, help_text="The camera pipeline string in gst-launch-1.0 syntax which will be applied in camera VA pipeline once 'Use Camera Pipeline' is enabled and 'Save Camera' button is clicked. Please review and/or adjust it before applying.", max_length=5000, null=True)), + ('detection_labels', models.TextField(blank=True, help_text='Detection labels to use, one per line', max_length=2000, null=True, verbose_name='Detection Labels')), + ], + bases=('manager.sensor',), + ), + migrations.CreateModel( + name='SingletonSensor', + fields=[ + ('sensor_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.sensor')), + ('map_x', models.FloatField(blank=True, default=None, null=True)), + ('map_y', models.FloatField(blank=True, default=None, null=True)), + ('area', models.CharField(choices=[('scene', 'scene'), ('circle', 'circle'), ('poly', 'poly')], default='scene', max_length=16)), + ('radius', models.FloatField(blank=True, default=None, null=True)), + ('singleton_type', models.CharField(choices=[('environmental', 'environmental'), ('attribute', 'attribute')], default='environmental', max_length=20, verbose_name='Type of Sensor')), + ], + bases=('manager.sensor',), + ), + migrations.CreateModel( + name='Vehicle', + fields=[ + ('mobileobject_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.mobileobject')), + ], + bases=('manager.mobileobject',), + ), + migrations.AddField( + model_name='sensor', + name='scene', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manager.scene'), + ), + migrations.AddField( + model_name='mobileobject', + name='scene', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='manager.scene'), + ), + migrations.CreateModel( + name='CalibrationMarker', + fields=[ + ('marker_id', models.CharField(max_length=50, primary_key=True, serialize=False)), + ('apriltag_id', models.CharField(max_length=10)), + ('dims', manager.fields.ListField(base_field=models.FloatField(), default=list, size=None)), + ('scene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='manager.scene')), + ], + ), + migrations.CreateModel( + name='UserSession', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('session', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='sessions.session')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='RegionOccupancyThreshold', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sectors', models.JSONField(default=list)), + ('range_max', models.IntegerField(default=10)), + ('region', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='roi_occupancy_threshold', to='manager.region')), + ], + ), + migrations.CreateModel( + name='Event', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.FloatField(db_index=True)), + ('region', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='manager.region')), + ], + ), + migrations.CreateModel( + name='Tripwire', + fields=[ + ('boundingbox_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.boundingbox')), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False, unique=True)), + ('height', models.FloatField(default=1.0)), + ('scene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tripwires', to='manager.scene')), + ], + bases=('manager.boundingbox',), + ), + migrations.CreateModel( + name='RegionPoint', + fields=[ + ('boundingboxpoints_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.boundingboxpoints')), + ('region', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='points', to='manager.region')), + ], + bases=('manager.boundingboxpoints',), + ), + migrations.CreateModel( + name='TripwirePoint', + fields=[ + ('boundingboxpoints_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.boundingboxpoints')), + ('tripwire', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='points', to='manager.tripwire')), + ], + bases=('manager.boundingboxpoints',), + ), + migrations.CreateModel( + name='SingletonScalarThreshold', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sectors', models.JSONField(default=list)), + ('range_max', models.IntegerField(default=10)), + ('singleton', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='singleton_scalar_threshold', to='manager.singletonsensor')), + ], + ), + migrations.CreateModel( + name='SingletonAreaPoint', + fields=[ + ('boundingboxpoints_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='manager.boundingboxpoints')), + ('singleton', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='points', to='manager.singletonsensor')), + ], + bases=('manager.boundingboxpoints',), + ), + migrations.CreateModel( + name='CamLog', + fields=[ + ('log', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, related_name='camLog', serialize=False, to='manager.datalog')), + ('pid', models.IntegerField(blank=True, default=None, null=True)), + ('x', models.FloatField(blank=True, default=None, null=True)), + ('y', models.FloatField(blank=True, default=None, null=True)), + ('width', models.FloatField(blank=True, default=None, null=True)), + ('height', models.FloatField(blank=True, default=None, null=True)), + ('sensor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='manager.sensor')), + ], + ), + migrations.CreateModel( + name='SceneLog', + fields=[ + ('log', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='manager.datalog')), + ('scene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='manager.scene')), + ], + ), + migrations.CreateModel( + name='PubSubACL', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('topic', models.CharField(choices=[('CHANNEL', 'CHANNEL'), ('CMD_CAMERA', 'CMD_CAMERA'), ('CMD_DATABASE', 'CMD_DATABASE'), ('CMD_KUBECLIENT', 'CMD_KUBECLIENT'), ('CMD_SCENE_UPDATE', 'CMD_SCENE_UPDATE'), ('DATA_AUTOCALIB_CAM_POSE', 'DATA_AUTOCALIB_CAM_POSE'), ('DATA_CAMERA', 'DATA_CAMERA'), ('DATA_EXTERNAL', 'DATA_EXTERNAL'), ('DATA_REGION', 'DATA_REGION'), ('DATA_REGULATED', 'DATA_REGULATED'), ('DATA_SCENE', 'DATA_SCENE'), ('DATA_SENSOR', 'DATA_SENSOR'), ('EVENT', 'EVENT'), ('IMAGE_CALIBRATE', 'IMAGE_CALIBRATE'), ('IMAGE_CAMERA', 'IMAGE_CAMERA'), ('SYS_CHILDSCENE_STATUS', 'SYS_CHILDSCENE_STATUS'), ('ANALYTICS_CLUSTERS', 'ANALYTICS_CLUSTERS')], max_length=50)), + ('access', models.IntegerField(choices=[(0, 'No access'), (1, 'Read only'), (2, 'Write only'), (3, 'Read and Write')], default=0)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='acls', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'constraints': [models.UniqueConstraint(fields=('user', 'topic'), name='manager_pubsubacl_unique_user_topic')], + }, + ), + migrations.CreateModel( + name='ChildScene', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('child_name', models.CharField(blank=True, default=None, max_length=200, null=True, verbose_name='Child Name')), + ('remote_child_id', models.UUIDField(blank=True, default=None, null=True, unique=True, verbose_name='Remote Child ID')), + ('child_type', models.CharField(default='local', max_length=15)), + ('transform1', models.FloatField(blank=True, default=1.0, null=True)), + ('transform2', models.FloatField(blank=True, default=0.0, null=True)), + ('transform3', models.FloatField(blank=True, default=0.0, null=True)), + ('transform4', models.FloatField(blank=True, default=0.0, null=True)), + ('transform5', models.FloatField(blank=True, default=0.0, null=True)), + ('transform6', models.FloatField(blank=True, default=1.0, null=True)), + ('transform7', models.FloatField(blank=True, default=0.0, null=True)), + ('transform8', models.FloatField(blank=True, default=0.0, null=True)), + ('transform9', models.FloatField(blank=True, default=0.0, null=True)), + ('transform10', models.FloatField(blank=True, default=0.0, null=True)), + ('transform11', models.FloatField(blank=True, default=1.0, null=True)), + ('transform12', models.FloatField(blank=True, default=0.0, null=True)), + ('transform13', models.FloatField(blank=True, default=0.0, null=True)), + ('transform14', models.FloatField(blank=True, default=0.0, null=True)), + ('transform15', models.FloatField(blank=True, default=0.0, null=True)), + ('transform16', models.FloatField(blank=True, default=1.0, null=True)), + ('transform_type', models.CharField(choices=[('matrix', 'Matrix'), ('euler', 'Euler Angles'), ('quaternion', 'Quaternion')], default='matrix', max_length=10)), + ('host_name', models.CharField(blank=True, max_length=200, null=True, verbose_name='Hostname or IP')), + ('mqtt_username', models.CharField(blank=True, max_length=200, null=True, verbose_name='MQTT Username')), + ('mqtt_password', models.CharField(blank=True, max_length=200, null=True, verbose_name='MQTT Password')), + ('retrack', models.BooleanField(blank=True, choices=[(True, 'Yes'), (False, 'No')], default=True, verbose_name='Retrack objects')), + ('child', models.OneToOneField(blank=True, default=None, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parent', to='manager.scene')), + ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='children', to='manager.scene')), + ], + options={ + 'constraints': [models.CheckConstraint(condition=models.Q(models.Q(('child__isnull', False), ('child_name__isnull', True)), models.Q(('child__isnull', True), ('child_name__isnull', False)), _connector='OR'), name='manager_childscene_either_child_or_child_name'), models.UniqueConstraint(fields=('child', 'parent'), name='manager_childscene_local_child_unique_relationships'), models.UniqueConstraint(fields=('child_name', 'parent'), name='manager_childscene_remote_child_unique_relationships'), models.CheckConstraint(condition=models.Q(('child', models.F('parent')), _negated=True), name='manager_childscene_prevent_self_follow')], + }, + ), + ] diff --git a/manager/src/manager/migrations/__init__.py b/manager/src/manager/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/manager/src/django/model_directory_view.py b/manager/src/manager/model_directory_view.py similarity index 100% rename from manager/src/django/model_directory_view.py rename to manager/src/manager/model_directory_view.py diff --git a/manager/src/django/models.py b/manager/src/manager/models.py similarity index 100% rename from manager/src/django/models.py rename to manager/src/manager/models.py diff --git a/manager/src/django/ppl_generator/__init__.py b/manager/src/manager/ppl_generator/__init__.py similarity index 100% rename from manager/src/django/ppl_generator/__init__.py rename to manager/src/manager/ppl_generator/__init__.py diff --git a/manager/src/django/ppl_generator/common_types.py b/manager/src/manager/ppl_generator/common_types.py similarity index 100% rename from manager/src/django/ppl_generator/common_types.py rename to manager/src/manager/ppl_generator/common_types.py diff --git a/manager/src/django/ppl_generator/config_generator.py b/manager/src/manager/ppl_generator/config_generator.py similarity index 100% rename from manager/src/django/ppl_generator/config_generator.py rename to manager/src/manager/ppl_generator/config_generator.py diff --git a/manager/src/django/ppl_generator/inference_model.py b/manager/src/manager/ppl_generator/inference_model.py similarity index 100% rename from manager/src/django/ppl_generator/inference_model.py rename to manager/src/manager/ppl_generator/inference_model.py diff --git a/manager/src/django/ppl_generator/model_chain.py b/manager/src/manager/ppl_generator/model_chain.py similarity index 100% rename from manager/src/django/ppl_generator/model_chain.py rename to manager/src/manager/ppl_generator/model_chain.py diff --git a/manager/src/django/ppl_generator/pipeline_generator.py b/manager/src/manager/ppl_generator/pipeline_generator.py similarity index 100% rename from manager/src/django/ppl_generator/pipeline_generator.py rename to manager/src/manager/ppl_generator/pipeline_generator.py diff --git a/manager/src/django/scene_import.py b/manager/src/manager/scene_import.py similarity index 100% rename from manager/src/django/scene_import.py rename to manager/src/manager/scene_import.py diff --git a/manager/src/django/serializers.py b/manager/src/manager/serializers.py similarity index 100% rename from manager/src/django/serializers.py rename to manager/src/manager/serializers.py diff --git a/manager/src/django/settings.py b/manager/src/manager/settings.py similarity index 100% rename from manager/src/django/settings.py rename to manager/src/manager/settings.py diff --git a/manager/src/django/settings_local.py b/manager/src/manager/settings_local.py similarity index 100% rename from manager/src/django/settings_local.py rename to manager/src/manager/settings_local.py diff --git a/manager/src/setup.py b/manager/src/manager/setup.py similarity index 100% rename from manager/src/setup.py rename to manager/src/manager/setup.py diff --git a/manager/src/static/android-chrome-192x192.png b/manager/src/manager/static/android-chrome-192x192.png similarity index 100% rename from manager/src/static/android-chrome-192x192.png rename to manager/src/manager/static/android-chrome-192x192.png diff --git a/manager/src/static/android-chrome-512x512.png b/manager/src/manager/static/android-chrome-512x512.png similarity index 100% rename from manager/src/static/android-chrome-512x512.png rename to manager/src/manager/static/android-chrome-512x512.png diff --git a/manager/src/static/apple-touch-icon.png b/manager/src/manager/static/apple-touch-icon.png similarity index 100% rename from manager/src/static/apple-touch-icon.png rename to manager/src/manager/static/apple-touch-icon.png diff --git a/manager/src/manager/static/bootstrap-4.6.1-dist.zip b/manager/src/manager/static/bootstrap-4.6.1-dist.zip new file mode 100644 index 000000000..8ba69a54b Binary files /dev/null and b/manager/src/manager/static/bootstrap-4.6.1-dist.zip differ diff --git a/manager/src/manager/static/bootstrap-icons-1.3.0.zip b/manager/src/manager/static/bootstrap-icons-1.3.0.zip new file mode 100644 index 000000000..142c52858 Binary files /dev/null and b/manager/src/manager/static/bootstrap-icons-1.3.0.zip differ diff --git a/manager/src/static/css/geospatial.css b/manager/src/manager/static/css/geospatial.css similarity index 100% rename from manager/src/static/css/geospatial.css rename to manager/src/manager/static/css/geospatial.css diff --git a/manager/src/static/css/images/rotate.svg b/manager/src/manager/static/css/images/rotate.svg similarity index 100% rename from manager/src/static/css/images/rotate.svg rename to manager/src/manager/static/css/images/rotate.svg diff --git a/manager/src/static/css/images/translate.svg b/manager/src/manager/static/css/images/translate.svg similarity index 100% rename from manager/src/static/css/images/translate.svg rename to manager/src/manager/static/css/images/translate.svg diff --git a/manager/src/static/css/scenescape.css b/manager/src/manager/static/css/scenescape.css similarity index 100% rename from manager/src/static/css/scenescape.css rename to manager/src/manager/static/css/scenescape.css diff --git a/manager/src/static/css/style.css b/manager/src/manager/static/css/style.css similarity index 100% rename from manager/src/static/css/style.css rename to manager/src/manager/static/css/style.css diff --git a/manager/src/static/favicon-16x16.png b/manager/src/manager/static/favicon-16x16.png similarity index 100% rename from manager/src/static/favicon-16x16.png rename to manager/src/manager/static/favicon-16x16.png diff --git a/manager/src/static/favicon-32x32.png b/manager/src/manager/static/favicon-32x32.png similarity index 100% rename from manager/src/static/favicon-32x32.png rename to manager/src/manager/static/favicon-32x32.png diff --git a/manager/src/static/favicon.ico b/manager/src/manager/static/favicon.ico similarity index 100% rename from manager/src/static/favicon.ico rename to manager/src/manager/static/favicon.ico diff --git a/manager/src/static/images/logo.png b/manager/src/manager/static/images/logo.png similarity index 100% rename from manager/src/static/images/logo.png rename to manager/src/manager/static/images/logo.png diff --git a/manager/src/static/images/offline.png b/manager/src/manager/static/images/offline.png similarity index 100% rename from manager/src/static/images/offline.png rename to manager/src/manager/static/images/offline.png diff --git a/manager/src/static/js/assetmanager.js b/manager/src/manager/static/js/assetmanager.js similarity index 100% rename from manager/src/static/js/assetmanager.js rename to manager/src/manager/static/js/assetmanager.js diff --git a/manager/src/static/js/calibration.js b/manager/src/manager/static/js/calibration.js similarity index 100% rename from manager/src/static/js/calibration.js rename to manager/src/manager/static/js/calibration.js diff --git a/manager/src/static/js/camcanvas.js b/manager/src/manager/static/js/camcanvas.js similarity index 100% rename from manager/src/static/js/camcanvas.js rename to manager/src/manager/static/js/camcanvas.js diff --git a/manager/src/static/js/cameracalibrate.js b/manager/src/manager/static/js/cameracalibrate.js similarity index 100% rename from manager/src/static/js/cameracalibrate.js rename to manager/src/manager/static/js/cameracalibrate.js diff --git a/manager/src/static/js/childscene.js b/manager/src/manager/static/js/childscene.js similarity index 100% rename from manager/src/static/js/childscene.js rename to manager/src/manager/static/js/childscene.js diff --git a/manager/src/static/js/constants.js b/manager/src/manager/static/js/constants.js similarity index 100% rename from manager/src/static/js/constants.js rename to manager/src/manager/static/js/constants.js diff --git a/manager/src/static/js/customcamerahelper.js b/manager/src/manager/static/js/customcamerahelper.js similarity index 100% rename from manager/src/static/js/customcamerahelper.js rename to manager/src/manager/static/js/customcamerahelper.js diff --git a/manager/src/static/js/draw.js b/manager/src/manager/static/js/draw.js similarity index 100% rename from manager/src/static/js/draw.js rename to manager/src/manager/static/js/draw.js diff --git a/manager/src/static/js/geospatial/geomanager.js b/manager/src/manager/static/js/geospatial/geomanager.js similarity index 100% rename from manager/src/static/js/geospatial/geomanager.js rename to manager/src/manager/static/js/geospatial/geomanager.js diff --git a/manager/src/static/js/geospatial/google-maps-plugin.js b/manager/src/manager/static/js/geospatial/google-maps-plugin.js similarity index 100% rename from manager/src/static/js/geospatial/google-maps-plugin.js rename to manager/src/manager/static/js/geospatial/google-maps-plugin.js diff --git a/manager/src/static/js/geospatial/map-interface.js b/manager/src/manager/static/js/geospatial/map-interface.js similarity index 100% rename from manager/src/static/js/geospatial/map-interface.js rename to manager/src/manager/static/js/geospatial/map-interface.js diff --git a/manager/src/static/js/geospatial/mapbox-plugin.js b/manager/src/manager/static/js/geospatial/mapbox-plugin.js similarity index 100% rename from manager/src/static/js/geospatial/mapbox-plugin.js rename to manager/src/manager/static/js/geospatial/mapbox-plugin.js diff --git a/manager/src/static/js/geospatial/scene-form.js b/manager/src/manager/static/js/geospatial/scene-form.js similarity index 100% rename from manager/src/static/js/geospatial/scene-form.js rename to manager/src/manager/static/js/geospatial/scene-form.js diff --git a/manager/src/static/js/interactions.js b/manager/src/manager/static/js/interactions.js similarity index 100% rename from manager/src/static/js/interactions.js rename to manager/src/manager/static/js/interactions.js diff --git a/manager/src/static/js/marks.js b/manager/src/manager/static/js/marks.js similarity index 100% rename from manager/src/static/js/marks.js rename to manager/src/manager/static/js/marks.js diff --git a/manager/src/static/js/model_list.js b/manager/src/manager/static/js/model_list.js similarity index 100% rename from manager/src/static/js/model_list.js rename to manager/src/manager/static/js/model_list.js diff --git a/manager/src/static/js/pipeline-generator.js b/manager/src/manager/static/js/pipeline-generator.js similarity index 100% rename from manager/src/static/js/pipeline-generator.js rename to manager/src/manager/static/js/pipeline-generator.js diff --git a/manager/src/static/js/restclient.js b/manager/src/manager/static/js/restclient.js similarity index 100% rename from manager/src/static/js/restclient.js rename to manager/src/manager/static/js/restclient.js diff --git a/manager/src/static/js/scenescape3d.js b/manager/src/manager/static/js/scenescape3d.js similarity index 100% rename from manager/src/static/js/scenescape3d.js rename to manager/src/manager/static/js/scenescape3d.js diff --git a/manager/src/static/js/sscape.js b/manager/src/manager/static/js/sscape.js similarity index 100% rename from manager/src/static/js/sscape.js rename to manager/src/manager/static/js/sscape.js diff --git a/manager/src/static/js/thing/controls/thingcontrols.js b/manager/src/manager/static/js/thing/controls/thingcontrols.js similarity index 100% rename from manager/src/static/js/thing/controls/thingcontrols.js rename to manager/src/manager/static/js/thing/controls/thingcontrols.js diff --git a/manager/src/static/js/thing/controls/thingtransformcontrols.js b/manager/src/manager/static/js/thing/controls/thingtransformcontrols.js similarity index 100% rename from manager/src/static/js/thing/controls/thingtransformcontrols.js rename to manager/src/manager/static/js/thing/controls/thingtransformcontrols.js diff --git a/manager/src/static/js/thing/controls/validateinputcontrols.js b/manager/src/manager/static/js/thing/controls/validateinputcontrols.js similarity index 100% rename from manager/src/static/js/thing/controls/validateinputcontrols.js rename to manager/src/manager/static/js/thing/controls/validateinputcontrols.js diff --git a/manager/src/static/js/thing/managers/cameramanager.js b/manager/src/manager/static/js/thing/managers/cameramanager.js similarity index 100% rename from manager/src/static/js/thing/managers/cameramanager.js rename to manager/src/manager/static/js/thing/managers/cameramanager.js diff --git a/manager/src/static/js/thing/managers/regionmanager.js b/manager/src/manager/static/js/thing/managers/regionmanager.js similarity index 100% rename from manager/src/static/js/thing/managers/regionmanager.js rename to manager/src/manager/static/js/thing/managers/regionmanager.js diff --git a/manager/src/static/js/thing/managers/sensormanager.js b/manager/src/manager/static/js/thing/managers/sensormanager.js similarity index 100% rename from manager/src/static/js/thing/managers/sensormanager.js rename to manager/src/manager/static/js/thing/managers/sensormanager.js diff --git a/manager/src/static/js/thing/managers/thingmanager.js b/manager/src/manager/static/js/thing/managers/thingmanager.js similarity index 100% rename from manager/src/static/js/thing/managers/thingmanager.js rename to manager/src/manager/static/js/thing/managers/thingmanager.js diff --git a/manager/src/static/js/thing/managers/tripwiremanager.js b/manager/src/manager/static/js/thing/managers/tripwiremanager.js similarity index 100% rename from manager/src/static/js/thing/managers/tripwiremanager.js rename to manager/src/manager/static/js/thing/managers/tripwiremanager.js diff --git a/manager/src/static/js/thing/scene.js b/manager/src/manager/static/js/thing/scene.js similarity index 100% rename from manager/src/static/js/thing/scene.js rename to manager/src/manager/static/js/thing/scene.js diff --git a/manager/src/static/js/thing/scenecamera.js b/manager/src/manager/static/js/thing/scenecamera.js similarity index 100% rename from manager/src/static/js/thing/scenecamera.js rename to manager/src/manager/static/js/thing/scenecamera.js diff --git a/manager/src/static/js/thing/sceneregion.js b/manager/src/manager/static/js/thing/sceneregion.js similarity index 100% rename from manager/src/static/js/thing/sceneregion.js rename to manager/src/manager/static/js/thing/sceneregion.js diff --git a/manager/src/static/js/thing/scenesensor.js b/manager/src/manager/static/js/thing/scenesensor.js similarity index 100% rename from manager/src/static/js/thing/scenesensor.js rename to manager/src/manager/static/js/thing/scenesensor.js diff --git a/manager/src/static/js/thing/scenetripwire.js b/manager/src/manager/static/js/thing/scenetripwire.js similarity index 100% rename from manager/src/static/js/thing/scenetripwire.js rename to manager/src/manager/static/js/thing/scenetripwire.js diff --git a/manager/src/static/js/toast.js b/manager/src/manager/static/js/toast.js similarity index 100% rename from manager/src/static/js/toast.js rename to manager/src/manager/static/js/toast.js diff --git a/manager/src/static/js/utils.js b/manager/src/manager/static/js/utils.js similarity index 100% rename from manager/src/static/js/utils.js rename to manager/src/manager/static/js/utils.js diff --git a/manager/src/static/js/viewport.js b/manager/src/manager/static/js/viewport.js similarity index 100% rename from manager/src/static/js/viewport.js rename to manager/src/manager/static/js/viewport.js diff --git a/manager/src/static/site.webmanifest b/manager/src/manager/static/site.webmanifest similarity index 100% rename from manager/src/static/site.webmanifest rename to manager/src/manager/static/site.webmanifest diff --git a/manager/src/templates/asset/asset_create.html b/manager/src/manager/templates/asset/asset_create.html similarity index 100% rename from manager/src/templates/asset/asset_create.html rename to manager/src/manager/templates/asset/asset_create.html diff --git a/manager/src/templates/asset/asset_delete.html b/manager/src/manager/templates/asset/asset_delete.html similarity index 100% rename from manager/src/templates/asset/asset_delete.html rename to manager/src/manager/templates/asset/asset_delete.html diff --git a/manager/src/templates/asset/asset_list.html b/manager/src/manager/templates/asset/asset_list.html similarity index 100% rename from manager/src/templates/asset/asset_list.html rename to manager/src/manager/templates/asset/asset_list.html diff --git a/manager/src/templates/asset/asset_update.html b/manager/src/manager/templates/asset/asset_update.html similarity index 100% rename from manager/src/templates/asset/asset_update.html rename to manager/src/manager/templates/asset/asset_update.html diff --git a/manager/src/templates/cam/cam_calibrate.html b/manager/src/manager/templates/cam/cam_calibrate.html similarity index 100% rename from manager/src/templates/cam/cam_calibrate.html rename to manager/src/manager/templates/cam/cam_calibrate.html diff --git a/manager/src/templates/cam/cam_create.html b/manager/src/manager/templates/cam/cam_create.html similarity index 100% rename from manager/src/templates/cam/cam_create.html rename to manager/src/manager/templates/cam/cam_create.html diff --git a/manager/src/templates/cam/cam_delete.html b/manager/src/manager/templates/cam/cam_delete.html similarity index 100% rename from manager/src/templates/cam/cam_delete.html rename to manager/src/manager/templates/cam/cam_delete.html diff --git a/manager/src/templates/cam/cam_list.html b/manager/src/manager/templates/cam/cam_list.html similarity index 100% rename from manager/src/templates/cam/cam_list.html rename to manager/src/manager/templates/cam/cam_list.html diff --git a/manager/src/templates/cam/cam_update.html b/manager/src/manager/templates/cam/cam_update.html similarity index 100% rename from manager/src/templates/cam/cam_update.html rename to manager/src/manager/templates/cam/cam_update.html diff --git a/manager/src/templates/child/child_create.html b/manager/src/manager/templates/child/child_create.html similarity index 100% rename from manager/src/templates/child/child_create.html rename to manager/src/manager/templates/child/child_create.html diff --git a/manager/src/templates/child/child_delete.html b/manager/src/manager/templates/child/child_delete.html similarity index 100% rename from manager/src/templates/child/child_delete.html rename to manager/src/manager/templates/child/child_delete.html diff --git a/manager/src/templates/child/child_update.html b/manager/src/manager/templates/child/child_update.html similarity index 100% rename from manager/src/templates/child/child_update.html rename to manager/src/manager/templates/child/child_update.html diff --git a/manager/src/templates/model/includes/model_directory.html b/manager/src/manager/templates/model/includes/model_directory.html similarity index 100% rename from manager/src/templates/model/includes/model_directory.html rename to manager/src/manager/templates/model/includes/model_directory.html diff --git a/manager/src/templates/model/model_list.html b/manager/src/manager/templates/model/model_list.html similarity index 100% rename from manager/src/templates/model/model_list.html rename to manager/src/manager/templates/model/model_list.html diff --git a/manager/src/templates/scene/geospatial.html b/manager/src/manager/templates/scene/geospatial.html similarity index 100% rename from manager/src/templates/scene/geospatial.html rename to manager/src/manager/templates/scene/geospatial.html diff --git a/manager/src/templates/scene/scene_create.html b/manager/src/manager/templates/scene/scene_create.html similarity index 100% rename from manager/src/templates/scene/scene_create.html rename to manager/src/manager/templates/scene/scene_create.html diff --git a/manager/src/templates/scene/scene_delete.html b/manager/src/manager/templates/scene/scene_delete.html similarity index 100% rename from manager/src/templates/scene/scene_delete.html rename to manager/src/manager/templates/scene/scene_delete.html diff --git a/manager/src/templates/scene/scene_detail.html b/manager/src/manager/templates/scene/scene_detail.html similarity index 100% rename from manager/src/templates/scene/scene_detail.html rename to manager/src/manager/templates/scene/scene_detail.html diff --git a/manager/src/templates/scene/scene_import.html b/manager/src/manager/templates/scene/scene_import.html similarity index 100% rename from manager/src/templates/scene/scene_import.html rename to manager/src/manager/templates/scene/scene_import.html diff --git a/manager/src/templates/scene/scene_list.html b/manager/src/manager/templates/scene/scene_list.html similarity index 100% rename from manager/src/templates/scene/scene_list.html rename to manager/src/manager/templates/scene/scene_list.html diff --git a/manager/src/templates/scene/scene_update.html b/manager/src/manager/templates/scene/scene_update.html similarity index 100% rename from manager/src/templates/scene/scene_update.html rename to manager/src/manager/templates/scene/scene_update.html diff --git a/manager/src/templates/singleton_sensor/singleton_sensor_calibrate.html b/manager/src/manager/templates/singleton_sensor/singleton_sensor_calibrate.html similarity index 100% rename from manager/src/templates/singleton_sensor/singleton_sensor_calibrate.html rename to manager/src/manager/templates/singleton_sensor/singleton_sensor_calibrate.html diff --git a/manager/src/templates/singleton_sensor/singleton_sensor_create.html b/manager/src/manager/templates/singleton_sensor/singleton_sensor_create.html similarity index 100% rename from manager/src/templates/singleton_sensor/singleton_sensor_create.html rename to manager/src/manager/templates/singleton_sensor/singleton_sensor_create.html diff --git a/manager/src/templates/singleton_sensor/singleton_sensor_delete.html b/manager/src/manager/templates/singleton_sensor/singleton_sensor_delete.html similarity index 100% rename from manager/src/templates/singleton_sensor/singleton_sensor_delete.html rename to manager/src/manager/templates/singleton_sensor/singleton_sensor_delete.html diff --git a/manager/src/templates/singleton_sensor/singleton_sensor_list.html b/manager/src/manager/templates/singleton_sensor/singleton_sensor_list.html similarity index 100% rename from manager/src/templates/singleton_sensor/singleton_sensor_list.html rename to manager/src/manager/templates/singleton_sensor/singleton_sensor_list.html diff --git a/manager/src/templates/singleton_sensor/singleton_sensor_update.html b/manager/src/manager/templates/singleton_sensor/singleton_sensor_update.html similarity index 100% rename from manager/src/templates/singleton_sensor/singleton_sensor_update.html rename to manager/src/manager/templates/singleton_sensor/singleton_sensor_update.html diff --git a/manager/src/templates/sscape/500_error.html b/manager/src/manager/templates/sscape/500_error.html similarity index 100% rename from manager/src/templates/sscape/500_error.html rename to manager/src/manager/templates/sscape/500_error.html diff --git a/manager/src/templates/sscape/account_locked.html b/manager/src/manager/templates/sscape/account_locked.html similarity index 100% rename from manager/src/templates/sscape/account_locked.html rename to manager/src/manager/templates/sscape/account_locked.html diff --git a/manager/src/templates/sscape/base.html b/manager/src/manager/templates/sscape/base.html similarity index 100% rename from manager/src/templates/sscape/base.html rename to manager/src/manager/templates/sscape/base.html diff --git a/manager/src/templates/sscape/base_3d.html b/manager/src/manager/templates/sscape/base_3d.html similarity index 100% rename from manager/src/templates/sscape/base_3d.html rename to manager/src/manager/templates/sscape/base_3d.html diff --git a/manager/src/templates/sscape/index.html b/manager/src/manager/templates/sscape/index.html similarity index 100% rename from manager/src/templates/sscape/index.html rename to manager/src/manager/templates/sscape/index.html diff --git a/manager/src/templates/sscape/sceneDetail.html b/manager/src/manager/templates/sscape/sceneDetail.html similarity index 100% rename from manager/src/templates/sscape/sceneDetail.html rename to manager/src/manager/templates/sscape/sceneDetail.html diff --git a/manager/src/templates/sscape/sign_in.html b/manager/src/manager/templates/sscape/sign_in.html similarity index 100% rename from manager/src/templates/sscape/sign_in.html rename to manager/src/manager/templates/sscape/sign_in.html diff --git a/manager/src/templates/sscape/singletonArea.html b/manager/src/manager/templates/sscape/singletonArea.html similarity index 100% rename from manager/src/templates/sscape/singletonArea.html rename to manager/src/manager/templates/sscape/singletonArea.html diff --git a/manager/src/templatetags/user_tags.py b/manager/src/manager/templatetags/user_tags.py similarity index 100% rename from manager/src/templatetags/user_tags.py rename to manager/src/manager/templatetags/user_tags.py diff --git a/manager/src/django/urls.py b/manager/src/manager/urls.py similarity index 100% rename from manager/src/django/urls.py rename to manager/src/manager/urls.py diff --git a/manager/src/django/validators.py b/manager/src/manager/validators.py similarity index 100% rename from manager/src/django/validators.py rename to manager/src/manager/validators.py diff --git a/manager/src/django/views.py b/manager/src/manager/views.py similarity index 100% rename from manager/src/django/views.py rename to manager/src/manager/views.py diff --git a/manager/src/django/wsgi.py b/manager/src/manager/wsgi.py similarity index 100% rename from manager/src/django/wsgi.py rename to manager/src/manager/wsgi.py diff --git a/manager/tools/generate_migrations.sh b/manager/tools/generate_migrations.sh new file mode 100755 index 000000000..93057c83d --- /dev/null +++ b/manager/tools/generate_migrations.sh @@ -0,0 +1,130 @@ +#!/bin/bash +# SPDX-FileCopyrightText: (C) 2025 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +# Script to generate Django migrations +# This should be run during development or as part of the release process +# DO NOT run this in production or at container startup + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" + +SECRETS_DIR="${PROJECT_ROOT}/manager/secrets" +RUN_SECRETS="/run/secrets/django/secrets.py" +MANAGER_DIR="/home/scenescape/SceneScape/manager" + +# Where we want to copy migrations to on the host +HOST_MIGRATIONS_DIR="${PROJECT_ROOT}/manager/src/manager/migrations" + +IMAGE="scenescape-manager:latest" + +# Defaults for showmigrations (can be overridden via flags/env) +DB_NETWORK="${DB_NETWORK:-scenescape_scenescape}" +DB_HOST="${DB_HOST:-pgserver}" # service/container name on the network +DB_PORT="${DB_PORT:-5432}" + +SHOW_AFTER=0 + +usage() { + cat < Django Migration Generator for SceneScape Manager" +echo "" + +generate_migrations() { + local container="scenescape-migrate-gen-$$" + + mkdir -p "${HOST_MIGRATIONS_DIR}" + docker run --name "${container}" \ + --user "$(id -u):$(id -g)" \ + -v "${SECRETS_DIR}/django:/run/secrets/django:ro" \ + -v "${PROJECT_ROOT}/manager/src/manager/migrations:/home/scenescape/SceneScape/manager/migrations:rw" \ + -v "${PROJECT_ROOT}/manager/src/manager:/home/scenescape/SceneScape/manager:rw" \ + --entrypoint /bin/bash \ + "${IMAGE}" \ + -lc ' + set -euo pipefail + cd /home/scenescape/SceneScape + cp /run/secrets/django/secrets.py /home/scenescape/SceneScape/manager/secrets.py + python manage.py makemigrations manager + ' + docker rm -f "${container}" >/dev/null + echo "==> Migrations can be found at ${HOST_MIGRATIONS_DIR}" +} + +show_migrations() { + echo "" + echo "==> showmigrations (requires DB reachable)" + echo "DB network: ${DB_NETWORK}" + echo "DB host: ${DB_HOST}" + echo "DB port: ${DB_PORT}" + echo "" + + # Quick preflight: ensure the network exists + if ! docker network inspect "${DB_NETWORK}" >/dev/null 2>&1; then + echo "ERROR: Docker network '${DB_NETWORK}' not found." + echo "Hint: start your compose stack or create the network, or pass --network ." + return 2 + fi + + # Run showmigrations against DB_HOST on the network. + # We patch settings.py HOST/PORT just for this container run. + docker run --rm \ + --network "${DB_NETWORK}" \ + -v "${SECRETS_DIR}/django:/run/secrets/django:ro" \ + --entrypoint /bin/bash \ + "${IMAGE}" \ + -lc " + set -e + cd /home/scenescape/SceneScape + cp ${RUN_SECRETS} ${MANAGER_DIR}/secrets.py + + sed -i -E \"s|'HOST': '[^']*'|'HOST': '${DB_HOST}'|; s|'PORT': '[^']*'|'PORT': '${DB_PORT}'|\" \ + /home/scenescape/SceneScape/manager/settings.py + + python manage.py showmigrations + " +} + +generate_migrations + +echo "" +echo "==> Migration files generated in manager/src/manager/migrations/" +echo "" +echo "Next steps:" +echo "1. Review the generated migration files" +echo "2. Commit migration files to version control" + +if [[ "${SHOW_AFTER}" -eq 1 ]]; then + show_migrations +else + echo "3. (Optional) Check applied/unapplied status (requires DB):" + echo " $(basename "$0") --show --network ${DB_NETWORK} --dbhost ${DB_HOST} --dbport ${DB_PORT}" +fi +echo "" diff --git a/manager/tools/migrate-rename-manager b/manager/tools/migrate-rename-manager index 5c2f9d728..27dcaf71f 100755 --- a/manager/tools/migrate-rename-manager +++ b/manager/tools/migrate-rename-manager @@ -2,6 +2,10 @@ # SPDX-FileCopyrightText: (C) 2025 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +# DEPRECATED: This script was used for one-time migration from 'sscape' to 'manager'. +# It is no longer needed and should not be used for new deployments. +# See manager/MIGRATIONS.md for the correct migration workflow. + MANAGERDIR=SceneScape WSHOME=$(eval echo ~${WSUSER}) MANAGERDIR="${WSHOME}/${MANAGERDIR}" diff --git a/manager/tools/migration b/manager/tools/migration index 77b26b550..b5e0b9f92 100755 --- a/manager/tools/migration +++ b/manager/tools/migration @@ -3,6 +3,12 @@ # SPDX-FileCopyrightText: (C) 2023 - 2025 Intel Corporation # SPDX-License-Identifier: Apache-2.0 +# DEPRECATED: This script is deprecated in favor of the new migration workflow. +# See manager/MIGRATIONS.md for the correct way to generate and apply migrations. +# +# This script was used for legacy migration management and should not be used +# for new development. It calls makemigrations which should not be done at runtime. + set -e APPDIR=/workspace diff --git a/tests/sscape_tests/secrets.sh b/tests/sscape_tests/secrets.sh index c9f46387c..1d1695567 100755 --- a/tests/sscape_tests/secrets.sh +++ b/tests/sscape_tests/secrets.sh @@ -5,7 +5,7 @@ export LOGSFORCONTAINER=mqtt_publish_1 export LOG=${LOGSFORCONTAINER}.log -if [ ! -e manager/src/django/secrets.py ] && [ ! -h manager/src/django/secrets.py ] ; then +if [ ! -e manager/src/manager/secrets.py ] && [ ! -h manager/src/manager/secrets.py ] ; then echo "Creating symlink to django secrets" - ln -s /run/secrets/django/secrets.py manager/src/django/ + ln -s /run/secrets/django/secrets.py manager/src/manager/ fi