diff --git a/argocd/deployment.yaml b/argocd/deployment.yaml index 613dd21..0e68867 100644 --- a/argocd/deployment.yaml +++ b/argocd/deployment.yaml @@ -18,14 +18,14 @@ spec: fsGroupChangePolicy: "OnRootMismatch" initContainers: - name: loader - image: git.baumann.gr/adebaumann/labhelper-data-loader:0.001 + image: git.baumann.gr/adebaumann/labhelper-data-loader:0.002 command: [ "sh","-c","cp -n preload/preload.sqlite3 /data/db.sqlite3; chown -R 999:999 /data; ls -la /data; sleep 10; exit 0" ] volumeMounts: - name: data mountPath: /data containers: - name: web - image: git.baumann.gr/adebaumann/labhelper:0.007 + image: git.baumann.gr/adebaumann/labhelper:0.008 imagePullPolicy: Always ports: - containerPort: 8000 diff --git a/boxes/admin.py b/boxes/admin.py index b7e40f9..64fe900 100644 --- a/boxes/admin.py +++ b/boxes/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from .models import Box, BoxType +from .models import Box, BoxType, Thing, ThingType @admin.register(BoxType) @@ -18,3 +18,20 @@ class BoxAdmin(admin.ModelAdmin): list_display = ('id', 'box_type') list_filter = ('box_type',) search_fields = ('id',) + + +@admin.register(ThingType) +class ThingTypeAdmin(admin.ModelAdmin): + """Admin configuration for ThingType model.""" + + list_display = ('name',) + search_fields = ('name',) + + +@admin.register(Thing) +class ThingAdmin(admin.ModelAdmin): + """Admin configuration for Thing model.""" + + list_display = ('name', 'thing_type', 'box') + list_filter = ('thing_type', 'box') + search_fields = ('name', 'description') diff --git a/boxes/migrations/0002_thingtype_thing.py b/boxes/migrations/0002_thingtype_thing.py new file mode 100644 index 0000000..31efad8 --- /dev/null +++ b/boxes/migrations/0002_thingtype_thing.py @@ -0,0 +1,38 @@ +# Generated by Django 5.2.9 on 2025-12-28 19:06 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('boxes', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='ThingType', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, unique=True)), + ], + options={ + 'ordering': ['name'], + }, + ), + migrations.CreateModel( + name='Thing', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True)), + ('picture', models.ImageField(blank=True, upload_to='things/')), + ('box', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='things', to='boxes.box')), + ('thing_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='things', to='boxes.thingtype')), + ], + options={ + 'ordering': ['name'], + }, + ), + ] diff --git a/boxes/models.py b/boxes/models.py index 219cbce..f13a03d 100644 --- a/boxes/models.py +++ b/boxes/models.py @@ -35,3 +35,39 @@ class Box(models.Model): def __str__(self): return self.id + + +class ThingType(models.Model): + """A type/category for things stored in boxes.""" + + name = models.CharField(max_length=255, unique=True) + + class Meta: + ordering = ['name'] + + def __str__(self): + return self.name + + +class Thing(models.Model): + """An item stored in a box.""" + + name = models.CharField(max_length=255) + thing_type = models.ForeignKey( + ThingType, + on_delete=models.PROTECT, + related_name='things' + ) + box = models.ForeignKey( + Box, + on_delete=models.PROTECT, + related_name='things' + ) + description = models.TextField(blank=True) + picture = models.ImageField(upload_to='things/', blank=True) + + class Meta: + ordering = ['name'] + + def __str__(self): + return self.name diff --git a/data-loader/preload.sqlite3 b/data-loader/preload.sqlite3 index 7b7b92c..31f0970 100644 Binary files a/data-loader/preload.sqlite3 and b/data-loader/preload.sqlite3 differ diff --git a/data/media/things/Black-Cable-Ties.webp b/data/media/things/Black-Cable-Ties.webp new file mode 100644 index 0000000..351b140 Binary files /dev/null and b/data/media/things/Black-Cable-Ties.webp differ diff --git a/labhelper/settings.py b/labhelper/settings.py index 537ea62..3d5f5dd 100644 --- a/labhelper/settings.py +++ b/labhelper/settings.py @@ -20,7 +20,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-t1kymy8ugqnj$li2knhha0@gc5v8f3bge=$+gbybj2$jt28uqm' +SECRET_KEY = 'f0arjg8q3ut4iuqrguqfjaruf0eripIZZN3t1kymy8ugqnj$li2knhha0@gc5v8f3bge=$+gbybj2$jt28uqm' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -119,6 +119,10 @@ USE_TZ = True STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'staticfiles' +# Media files (user uploads) +MEDIA_URL = '/media/' +MEDIA_ROOT = BASE_DIR / 'data' / 'media' + # Default primary key field type # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field diff --git a/labhelper/urls.py b/labhelper/urls.py index 8efd033..9486341 100644 --- a/labhelper/urls.py +++ b/labhelper/urls.py @@ -28,3 +28,4 @@ urlpatterns = [ if settings.DEBUG: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/requirements.txt b/requirements.txt index d76e079..70dc548 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,5 +32,6 @@ six==1.17.0 sqlparse==0.5.3 urllib3==2.6.0 wcwidth==0.2.13 +Pillow==11.1.0 bleach==6.1.0 coverage==7.6.1