add phototags

This commit is contained in:
root 2022-06-15 12:05:29 +02:00
parent e91e83df40
commit d160bf3e7b
69 changed files with 138 additions and 343 deletions

4
.gitignore vendored Normal file → Executable file
View File

@ -1,2 +1,6 @@
static/*
./*/*pycache*/*
**/__pycache__
*/migrations/*
env/
static_bk/

View File

@ -1,38 +0,0 @@
# Generated by Django 3.2.8 on 2021-10-27 11:22
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='CustomUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('email', models.EmailField(max_length=254, unique=True, verbose_name='email address')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
),
]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
api/photolog_generator.py Normal file → Executable file
View File

0
api/photolog_layout.py Normal file → Executable file
View File

View File

@ -1,5 +1,11 @@
from rest_framework import serializers
from photo_log.models import PhotoGroup, Photo, PhotoLog
from photo_log.models import PhotoGroup, Photo, PhotoLog, PhotoTag
class PhotoTagSerializer(serializers.ModelSerializer):
class Meta:
model = PhotoTag
fields = ('id', 'name', 'color')
class PhotoGroupSerializer(serializers.ModelSerializer):
@ -15,15 +21,17 @@ class PhotosSerializer(serializers.ModelSerializer):
class PhotoSerializer(serializers.ModelSerializer):
tag = PhotoTagSerializer()
class Meta:
model = Photo
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'intersections', 'original_image', 'cropped_image', 'ocr_text')
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'intersections', 'original_image', 'cropped_image', 'ocr_text', 'tag')
class PhotoUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'ocr_text')
fields = ('id', 'legacy_id', 'group', 'bbox_coords', 'rotate', 'ocr_text', 'tag')
class PhotoLogSerializer(serializers.ModelSerializer):

View File

@ -14,6 +14,9 @@ from .views import (
UpdatePhotoLogAPIView,
UpdatePhotoAPIView,
GeneratePhotoLogAPIView,
PhotoTagsAPIView,
RetrieveUpdateDestroyPhotoTagAPIView,
CreatePhotoTagAPIView,
)
@ -33,4 +36,7 @@ urlpatterns = [
path('updatephotolog/<int:pk>/', UpdatePhotoLogAPIView.as_view()),
path('updatephoto/<int:pk>/', UpdatePhotoAPIView.as_view()),
path('generatephotolog/<int:pk>/', GeneratePhotoLogAPIView.as_view()),
path('phototag/', CreatePhotoTagAPIView.as_view()),
path('phototags/', PhotoTagsAPIView.as_view()),
path('phototag/<int:pk>/', RetrieveUpdateDestroyPhotoTagAPIView.as_view()),
]

View File

@ -1,7 +1,7 @@
from rest_framework import generics, views, status
from rest_framework.response import Response
from django.shortcuts import get_list_or_404
from photo_log.models import PhotoGroup, Photo, PhotoLog
from photo_log.models import PhotoGroup, Photo, PhotoLog, PhotoTag
from .serializers import (
PhotoGroupSerializer,
PhotosSerializer,
@ -9,6 +9,7 @@ from .serializers import (
PhotoUpdateSerializer,
PhotoLogSerializer,
PhotoLogsSerializer,
PhotoTagSerializer,
)
from .photolog_generator import generate_photolog_from_latex
@ -22,6 +23,21 @@ from io import BytesIO
from PIL import Image, ExifTags
class PhotoTagsAPIView(generics.ListAPIView):
queryset = PhotoTag.objects.all()
serializer_class = PhotoTagSerializer
class CreatePhotoTagAPIView(generics.CreateAPIView):
queryset = PhotoTag.objects.all()
serializer_class = PhotoTagSerializer
class RetrieveUpdateDestroyPhotoTagAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = PhotoTag.objects.all()
serializer_class = PhotoTagSerializer
class PhotoGroupAPIView(generics.ListAPIView):
queryset = PhotoGroup.objects.all()
serializer_class = PhotoGroupSerializer
@ -135,7 +151,7 @@ class GeneratePhotoLogAPIView(generics.RetrieveAPIView):
if log_bytes:
photolog.pdf.save('log.pdf', ContentFile(log_bytes))
return Response({'pdf': 'https://server.riezel.com%s' % str(photolog.pdf.url)})
return Response({'pdf': 'https://zierle-training.riezel.com%s' % str(photolog.pdf.url)})
return Response({"error": "Not Found"}, status=status.HTTP_404_NOT_FOUND)
@ -191,6 +207,9 @@ def rotateByExif(img):
exif = img._getexif()
if not exif:
return img
if exif[orientation] == 3:
img=img.rotate(180, expand=True)
elif exif[orientation] == 6:

0
config/package-lock.json generated Normal file → Executable file
View File

View File

@ -26,7 +26,7 @@ SECRET_KEY = 'django-insecure-z465dl_(vk55hxbm0bj*mp-ok3!*=ssw#!$5s2nrxa!9j+67z+
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['server.riezel.com', 'localhost', '127.0.0.1', '192.168.1.244']
ALLOWED_HOSTS = ['zierle-training.riezel.com', 'localhost', '127.0.0.1', '192.168.1.244']
# Application definition
@ -45,6 +45,7 @@ INSTALLED_APPS = [
'corsheaders',
'drf_yasg',
'django_tex',
'colorfield',
# local
'accounts',
@ -110,8 +111,8 @@ ASGI_APPLICATION = 'config.asgi.application'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'www_db',
'USER': 'www_db_user',
'NAME': 'zierle_training_db',
'USER': 'zierle_training_db_user',
'PASSWORD': 'UI&hWG,El7G{A2c0n=qIULv:b',
'HOST': 'localhost',
'PORT': '5432',
@ -157,12 +158,37 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
#STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/")]
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
MINIO = False
if MINIO:
# MinIO S3 Object-Storage
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'
AWS_ACCESS_KEY_ID = 'zierle-trainig-minio'
AWS_SECRET_ACCESS_KEY = 'iGWJt7IFlKzufMtVTnl4W4kGmHz0TTBG'
AWS_STORAGE_BUCKET_NAME = 'zierle-training'
AWS_S3_ENDPOINT_URL = 'https://minio.riezel.com'
AWS_DEFAULT_ACL = 'public'
MEDIA_URL = 'https://minio.riezel.com/zierle-training/'
STATIC_URL = 'https://minio.riezel.com/zierle-training/'
AWS_S3_OBJECT_PARAMETERS = {
'CacheControl': 'public, max-age=86400',
}
else:
#MEDIA_URL = 'media/'
#MEDIA_ROOT = BASE_DIR / 'media'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
#STATICFILES_DIRS = [os.path.join(BASE_DIR, "static/")]

View File

@ -1,8 +1,9 @@
from django.contrib import admin
from .models import PhotoGroup, Photo, PhotoLog
from .models import PhotoGroup, Photo, PhotoLog, PhotoTag
admin.site.register(PhotoGroup)
admin.site.register(Photo)
admin.site.register(PhotoLog)
admin.site.register(PhotoTag)

View File

@ -1,36 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-05 17:12
import django.contrib.postgres.fields
from django.db import migrations, models
import django.db.models.deletion
import photo_log.models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='PhotoGroup',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=200, unique=True)),
('date', models.DateField(null=True)),
],
),
migrations.CreateModel(
name='Photo',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('legacy_id', models.IntegerField(blank=True, null=True, unique=True)),
('original_image', models.ImageField(upload_to='original_images/')),
('cropped_image', models.ImageField(blank=True, null=True, upload_to='cropped_images/')),
('ocr_text', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), size=None)),
('group', models.ForeignKey(default=photo_log.models.get_default_photogroup, on_delete=django.db.models.deletion.SET_DEFAULT, to='photo_log.photogroup')),
],
),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-05 17:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='photo',
name='cropped_image',
field=models.ImageField(blank=True, null=True, upload_to='static/cropped_images/'),
),
migrations.AlterField(
model_name='photo',
name='original_image',
field=models.ImageField(upload_to='static/original_images/'),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-06 08:52
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0002_auto_20220105_1757'),
]
operations = [
migrations.AlterField(
model_name='photo',
name='ocr_text',
field=django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, null=True, size=None),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-06 12:48
from django.db import migrations, models
import django.db.models.deletion
import photo_log.models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0003_alter_photo_ocr_text'),
]
operations = [
migrations.AlterField(
model_name='photo',
name='group',
field=models.ForeignKey(blank=True, default=photo_log.models.get_default_photogroup, on_delete=django.db.models.deletion.SET_DEFAULT, to='photo_log.photogroup'),
),
]

View File

@ -1,26 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-13 13:32
import datetime
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0004_alter_photo_group'),
]
operations = [
migrations.CreateModel(
name='PhotoLog',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=5000)),
('date', models.DateField(default=datetime.date.today)),
('render_date', models.BooleanField(blank=True, default=True)),
('start_slide_image', models.IntegerField(blank=True, default=3, null=True)),
('slides', django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(null=True), blank=True, null=True, size=3), size=None)),
],
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-13 15:11
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0005_photolog'),
]
operations = [
migrations.AlterField(
model_name='photolog',
name='slides',
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(null=True), blank=True, null=True, size=3), blank=True, default=[], size=None),
),
]

View File

@ -1,20 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-13 15:13
import django.contrib.postgres.fields
from django.db import migrations, models
import photo_log.models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0006_alter_photolog_slides'),
]
operations = [
migrations.AlterField(
model_name='photolog',
name='slides',
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(null=True), blank=True, null=True, size=3), blank=True, default=photo_log.models.get_empty_photolog_default, size=None),
),
]

View File

@ -1,24 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-18 18:47
from django.db import migrations, models
import photo_log.models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0007_alter_photolog_slides'),
]
operations = [
migrations.AlterField(
model_name='photo',
name='cropped_image',
field=models.ImageField(blank=True, null=True, upload_to=photo_log.models.get_cropped_photo_path),
),
migrations.AlterField(
model_name='photo',
name='original_image',
field=models.ImageField(upload_to=photo_log.models.get_original_photo_path),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-18 19:56
from django.db import migrations, models
import photo_log.models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0008_auto_20220118_1847'),
]
operations = [
migrations.AddField(
model_name='photolog',
name='pdf',
field=models.FileField(blank=True, null=True, upload_to=photo_log.models.get_photolog_pdf_path),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-21 11:47
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0009_photolog_pdf'),
]
operations = [
migrations.AddField(
model_name='photo',
name='bbox_coords',
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(default=None, null=True), size=2), blank=True, default=None, null=True, size=4),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.8 on 2022-01-22 11:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0010_photo_bbox_coords'),
]
operations = [
migrations.AlterField(
model_name='photo',
name='ocr_text',
field=models.CharField(blank=True, max_length=200, null=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 3.2.8 on 2022-05-03 14:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0011_alter_photo_ocr_text'),
]
operations = [
migrations.AddField(
model_name='photo',
name='rotate',
field=models.FloatField(blank=True, null=True),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 3.2.8 on 2022-05-04 07:28
import django.contrib.postgres.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('photo_log', '0012_photo_rotate'),
]
operations = [
migrations.AddField(
model_name='photo',
name='intersections',
field=django.contrib.postgres.fields.ArrayField(base_field=django.contrib.postgres.fields.ArrayField(base_field=models.IntegerField(default=None, null=True), size=2), blank=True, default=None, null=True, size=None),
),
]

View File

@ -2,12 +2,22 @@ from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.dispatch import receiver
from colorfield.fields import ColorField
from datetime import date
import os
import uuid
class PhotoTag(models.Model):
name = models.CharField(unique=True, null=False, blank=False, max_length=100)
color = ColorField(default='#FFE5B4')
def __str__(self):
return self.name
class PhotoGroup(models.Model):
name = models.CharField(unique=True, null=False, max_length=200)
date = models.DateField(null=True)
@ -63,6 +73,13 @@ class Photo(models.Model):
default=get_default_photogroup
)
ocr_text = models.CharField(max_length=200, null=True, blank=True)
tag = models.ForeignKey(
PhotoTag,
null=True,
blank=False,
on_delete=models.SET_NULL,
default=None,
)
def __str__(self):
return "Photo #" + str(self.id)

13
req.txt
View File

@ -1,13 +0,0 @@
imageio==2.13.5
imutils==0.5.4
networkx==2.6.3
numpy==1.22.0
opencv-python==4.5.5.62
packaging==21.3
Pillow==9.0.0
pyparsing==3.0.6
pytesseract==0.3.8
PyWavelets==1.2.0
scikit-image==0.19.1
scipy==1.7.3
tifffile==2021.11.2

View File

@ -1,19 +1,64 @@
asgiref==3.4.1
attrs==21.4.0
autobahn==22.4.2
Automat==20.2.0
beautifulsoup4==4.10.0
certifi==2021.10.8
cffi==1.15.0
channels==3.0.4
charset-normalizer==2.0.7
constantly==15.1.0
coreapi==2.3.3
coreschema==0.0.4
cryptography==37.0.2
daphne==3.0.2
Django==3.2.8
django-cors-headers==3.12.0
django-filter==21.1
django-tex==1.1.10
djangorestframework==3.13.1
drf-yasg==1.20.0
gunicorn==20.1.0
hyperlink==21.0.0
idna==3.3
imageio==2.13.5
imutils==0.5.4
incremental==21.3.0
inflection==0.5.1
itypes==1.2.0
Jinja2==3.1.2
lxml==4.6.3
Markdown==3.3.7
MarkupSafe==2.1.1
networkx==2.6.3
numpy==1.22.0
opencv-python==4.5.5.62
packaging==21.3
Pillow==9.0.0
psycopg2==2.9.1
pyasn1==0.4.8
pyasn1-modules==0.2.8
pycparser==2.21
pyOpenSSL==22.0.0
pyparsing==3.0.6
pytesseract==0.3.8
python-dateutil==2.8.2
pytz==2021.3
PyWavelets==1.2.0
requests==2.26.0
ruamel.yaml==0.17.21
ruamel.yaml.clib==0.2.6
scikit-image==0.19.1
scipy==1.7.3
service-identity==21.1.0
six==1.16.0
soupsieve==2.2.1
sqlparse==0.4.2
tifffile==2021.11.2
tqdm==4.62.3
Twisted==22.4.0
txaio==22.2.1
typing_extensions==4.2.0
uritemplate==4.1.1
urllib3==1.26.7
zope.interface==5.4.0

0
templates/photolog.tex Normal file → Executable file
View File