From 45e7da8ecfc6a816cd1e70600804dd121570ad23 Mon Sep 17 00:00:00 2001 From: James Ravenscroft Date: Sun, 8 Dec 2024 15:51:02 +0000 Subject: [PATCH] refactor views --- .gitignore | 4 + ...mo_image_mimetype_alter_imagememo_image.py | 24 ++++++ penparse/webui/models.py | 3 + penparse/webui/templates/dashboard.html | 23 ++++-- penparse/webui/urls.py | 9 +- penparse/webui/views.py | 47 ----------- penparse/webui/views/__init__.py | 82 +++++++++++++++++++ penparse/webui/views/register.py | 27 ++++++ penparse/webui/views/thumbnail.py | 60 ++++++++++++++ 9 files changed, 222 insertions(+), 57 deletions(-) create mode 100644 penparse/webui/migrations/0003_imagememo_image_mimetype_alter_imagememo_image.py delete mode 100644 penparse/webui/views.py create mode 100644 penparse/webui/views/__init__.py create mode 100644 penparse/webui/views/register.py create mode 100644 penparse/webui/views/thumbnail.py diff --git a/.gitignore b/.gitignore index 5d381cc..01ef23f 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,7 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + + +thumbnails/ +uploads/ \ No newline at end of file diff --git a/penparse/webui/migrations/0003_imagememo_image_mimetype_alter_imagememo_image.py b/penparse/webui/migrations/0003_imagememo_image_mimetype_alter_imagememo_image.py new file mode 100644 index 0000000..f99503e --- /dev/null +++ b/penparse/webui/migrations/0003_imagememo_image_mimetype_alter_imagememo_image.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.16 on 2024-12-08 15:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webui', '0002_imagememo'), + ] + + operations = [ + migrations.AddField( + model_name='imagememo', + name='image_mimetype', + field=models.CharField(default='image/jpeg', max_length=256), + preserve_default=False, + ), + migrations.AlterField( + model_name='imagememo', + name='image', + field=models.ImageField(upload_to='uploads/%Y/%m/%d'), + ), + ] diff --git a/penparse/webui/models.py b/penparse/webui/models.py index f28afc8..0b5f4b2 100644 --- a/penparse/webui/models.py +++ b/penparse/webui/models.py @@ -42,6 +42,9 @@ class UserManager(BaseUserManager): class ImageMemo(models.Model): """Model definition for ImageMemo.""" id = models.UUIDField(primary_key=True, default=uuid4, editable=False) + + image_mimetype = models.CharField(max_length=256) + image = models.ImageField(upload_to='uploads/%Y/%m/%d') content = models.TextField() diff --git a/penparse/webui/templates/dashboard.html b/penparse/webui/templates/dashboard.html index 3194160..0b81e3e 100644 --- a/penparse/webui/templates/dashboard.html +++ b/penparse/webui/templates/dashboard.html @@ -13,9 +13,8 @@
{% for document in documents %} -
+
+ {{ document.title }} thumbnail

{{ document.title }}

Analyzed on: {{ document.analysis_date }} @@ -40,13 +39,19 @@ {% endfor %}

-

Upload a New Document

- Upload Document +
+ {% csrf_token %} +
+ + +
+ +
{% endblock %} diff --git a/penparse/webui/urls.py b/penparse/webui/urls.py index 6204aff..29d02a7 100644 --- a/penparse/webui/urls.py +++ b/penparse/webui/urls.py @@ -5,7 +5,14 @@ from . import views urlpatterns = [ path("", views.index, name="index"), path("dashboard", views.dashboard, name="dashboard"), - path("settings", views.settings, name='settings'), + path("settings", views.settings, name="settings"), path("documents/upload", views.upload_document, name="upload_document"), + path("documents/", views.view_document, name="view_document"), + path( + "documents//thumbnail", views.document_thumbnail, name="document_thumbnail" + ), + path( + "documents//download", views.download_document, name="download_document" + ), path("auth/register", views.register, name="register"), ] diff --git a/penparse/webui/views.py b/penparse/webui/views.py deleted file mode 100644 index 49a381c..0000000 --- a/penparse/webui/views.py +++ /dev/null @@ -1,47 +0,0 @@ -import logging - - -from django.contrib import messages -from django.shortcuts import redirect, render -from django.http import HttpRequest, HttpResponse - -from django import conf, forms - - -from .models import User -from .forms import RegisterForm - - -logger = logging.getLogger(__name__) - - -def index(request): - # return HttpResponse("Hello, world. You're at the polls index.") - return render(request, 'index.html') - - -def dashboard(request): - return render(request, 'dashboard.html') - - -def settings(request): - return render(request, 'settings.html') - - -def upload_document(request): - return render(request, 'upload.html') - - -def register(request: HttpRequest): - - # if the form is not submitted yet, return the form - if request.method == 'POST': - form = RegisterForm(request.POST) - if form.is_valid(): - form.save() - messages.success(request, 'Registration successful!') - return redirect('login') - else: - form = RegisterForm() - - return render(request, 'register.html', {'form': form}) diff --git a/penparse/webui/views/__init__.py b/penparse/webui/views/__init__.py new file mode 100644 index 0000000..2f2572d --- /dev/null +++ b/penparse/webui/views/__init__.py @@ -0,0 +1,82 @@ +import logging +import os + +from django.contrib import messages +from django.shortcuts import redirect, render +from django.http import HttpRequest +from django.core.files.storage import default_storage +from django.core.files.base import ContentFile +from ..models import ImageMemo + +from django.contrib.auth.decorators import login_required + + + +logger = logging.getLogger(__name__) + +from .thumbnail import document_thumbnail +from .register import register + + +def index(request): + # return HttpResponse("Hello, world. You're at the polls index.") + return render(request, "index.html") + + +__all__ = ["index", "document_thumbnail", "register", "dashboard", "settings", "view_document", "download_document", "upload_document"] + + +@login_required +def dashboard(request: HttpRequest): + + documents = ImageMemo.objects.filter(author__id=request.user.id).order_by( + "-updated_at" + ) + context = {"documents": documents} + + return render(request, "dashboard.html", context) + + +@login_required +def settings(request): + return render(request, "settings.html") + + +@login_required +def view_document(request): + return render(request, "document.html") + + +@login_required +def download_document(request): + return render(request, "document.html") + + +@login_required +def upload_document(request): + if request.method == "POST" and request.FILES.get("document"): + uploaded_file = request.FILES["document"] + + # Check if the file is an image + if not uploaded_file.content_type.startswith("image/"): + messages.error(request, "Please upload an image file.") + return redirect("dashboard") + + # Save the image + file_name = default_storage.save( + f"uploads/{uploaded_file.name}", ContentFile(uploaded_file.read()) + ) + + # Create an ImageMemo instance + image_memo = ImageMemo( + image=file_name, + content="", # You can add initial content here if needed + author=request.user, # Assuming the user is authenticated + ) + image_memo.save() + + messages.success(request, "Image uploaded successfully!") + + return redirect("dashboard") # Redirect to dashboard or appropriate page + + diff --git a/penparse/webui/views/register.py b/penparse/webui/views/register.py new file mode 100644 index 0000000..d3e00cf --- /dev/null +++ b/penparse/webui/views/register.py @@ -0,0 +1,27 @@ +import logging +import os + +from django.contrib import messages +from django.shortcuts import redirect, render +from django.http import HttpRequest + +from ..forms import RegisterForm + + +logger = logging.getLogger(__name__) + + + +def register(request: HttpRequest): + + # if the form is not submitted yet, return the form + if request.method == "POST": + form = RegisterForm(request.POST) + if form.is_valid(): + form.save() + messages.success(request, "Registration successful!") + return redirect("login") + else: + form = RegisterForm() + + return render(request, "register.html", {"form": form}) diff --git a/penparse/webui/views/thumbnail.py b/penparse/webui/views/thumbnail.py new file mode 100644 index 0000000..e293968 --- /dev/null +++ b/penparse/webui/views/thumbnail.py @@ -0,0 +1,60 @@ +import os + +from PIL import Image +from io import BytesIO +from django.core.files.storage import default_storage + +from django import conf +from django.http import HttpRequest, HttpResponse +from django.contrib.auth.decorators import login_required + +from ..models import ImageMemo + +@login_required +def document_thumbnail(request: HttpRequest, pk: str): + """Given a document uuid, look it up, ensure that it belongs to the current user and respond with a thumbnail""" + + # find document with given ID (pk path param) and current user id + document = ImageMemo.objects.filter(id=pk, author__id=request.user.id).first() + + if not document: + return HttpResponse("Document not found", status_code=404) + + # look up the file on disk + + # get thumb directory from django setting + thumbnail_dir = getattr(conf.settings, "THUMBNAIL_DIR", "thumbnails") + + thumb_max_width = getattr(conf.settings, "THUMBNAIL_MAX_WIDTH", 420) + + thumb_path = os.path.join(thumbnail_dir, str(document.id) + ".jpg") + + if not os.path.exists(thumb_path): + + if not os.path.exists(thumbnail_dir): + os.makedirs(thumbnail_dir) + + # Open the image using PIL + image = Image.open(default_storage.open(document.image.name)) + + # get the image width and height + width = int(image.size[0]) + height = int(image.size[1]) + + # find the ratio of the width to height + ratio = round(width / float(height), 3) + + # max width of thumbnail is 240, calculate height based on ratio + thumb_height = int(thumb_max_width * ratio) + + # Create a thumbnail + image.thumbnail((thumb_max_width, thumb_height)) # Adjust size as needed + + # Save the thumbnail to a BytesIO object + thumb_io = BytesIO() + image.save(thumb_path, format="JPEG") + thumb_io.seek(0) + + # Return the thumbnail as an HTTP response + with open(thumb_path, "rb") as f: + return HttpResponse(f.read(), content_type="image/jpeg")