import io import re from pathlib import Path import django.forms as forms from django.http import (Http404, HttpResponse, HttpResponseRedirect, JsonResponse) from django.shortcuts import redirect, render from django.template import Context, loader from django.urls import resolve, reverse from django.views.decorators.csrf import ensure_csrf_cookie from PIL import Image import troggle.settings as settings from troggle.core.utils import WriteAndCommitError, write_and_commit from .auth import login_required_if_public MAX_IMAGE_WIDTH = 1000 MAX_IMAGE_HEIGHT = 800 THUMBNAIL_WIDTH = 200 THUMBNAIL_HEIGHT = 200 def get_dir(path): "From a path sent from urls.py, determine the directory." if "/" in path: return path.rsplit('/', 1)[0] else: return "" def image_selector(request, path): '''Returns available images''' directory = get_dir(path) thumbnailspath = Path(settings.EXPOWEB) / directory / "t" thumbnails = [] if thumbnailspath.is_dir(): for f in thumbnailspath.iterdir(): if f.is_file(): if directory: base = f"{directory}/" else: base = "" thumbnail_url = reverse('expopage', args=[f"{base}t/{f.name}"]) name_base = f.name.rsplit('.', 1)[0] page_path_base = Path(settings.EXPOWEB) / directory / "l" if ((page_path_base / (f"{name_base}.htm")).is_file()): page_url = reverse('expopage', args=[f"{base}l/{name_base}.htm"]) else: page_url = reverse('expopage', args=[f"{base}/l/{name_base}.html"]) thumbnails.append({"thumbnail_url": thumbnail_url, "page_url": page_url}) return render(request, 'image_selector.html', {'thumbnails': thumbnails}) @login_required_if_public @ensure_csrf_cookie def new_image_form(request, path): '''Manages a form to upload new images''' directory = get_dir(path) if request.method == 'POST': form = NewWebImageForm(request.POST, request.FILES, directory = directory) if form.is_valid(): f = request.FILES["file_"] binary_data = io.BytesIO() for chunk in f.chunks(): binary_data.write(chunk) i = Image.open(binary_data) width, height = i.size if width > MAX_IMAGE_WIDTH or height > MAX_IMAGE_HEIGHT: scale = max(width / MAX_IMAGE_WIDTH, height / MAX_IMAGE_HEIGHT) i = i.resize((int(width / scale), int(height / scale)), Image.ANTIALIAS) tscale = max(width / THUMBNAIL_WIDTH, height / THUMBNAIL_HEIGHT) thumbnail = i.resize((int(width / tscale), int(height / tscale)), Image.ANTIALIAS) ib = io.BytesIO() i.save(ib, format="png") tb = io.BytesIO() thumbnail.save(tb, format="png") image_rel_path, thumb_rel_path, desc_rel_path = form.get_rel_paths() image_page_template = loader.get_template('image_page_template.html') image_page = image_page_template.render({'header': form.cleaned_data["header"], 'description': form.cleaned_data["description"], 'photographer': form.cleaned_data["photographer"], 'year': form.cleaned_data["year"], 'filepath': f'/{image_rel_path}' }) image_path, thumb_path, desc_path = form.get_full_paths() # Create directories if required for full_path in image_path, thumb_path, desc_path: print(full_path, full_path.parent) full_path.parent.mkdir(parents=False, exist_ok=True) try: change_message = form.cleaned_data["change_message"] write_and_commit([(desc_path, image_page, "utf-8"), (image_path, ib.getbuffer(), False), (thumb_path, tb.getbuffer(), False)], f'{change_message} - online adding of an image') except WriteAndCommitError as e: return JsonResponse({"error": e.message}) linked_image_template = loader.get_template('linked_image_template.html') html_snippet = linked_image_template.render({'thumbnail_url': f'/{thumb_rel_path}', 'page_url': f'/{desc_rel_path}'}, request) return JsonResponse({"html": html_snippet}) else: form = NewWebImageForm(directory = directory) template = loader.get_template('new_image_form.html') htmlform = template.render({'form': form, 'path': path}, request) return JsonResponse({"form": htmlform}) class NewWebImageForm(forms.Form): '''The form used by the editexpopage function ''' header = forms.CharField(widget=forms.TextInput(attrs={'size':'60', 'placeholder': "Enter title (displayed as a header and in the tab)"})) file_ = forms.FileField() description = forms.CharField(widget=forms.Textarea(attrs={"cols":80, "rows":20, 'placeholder': "Describe the photo (using HTML)"})) photographer = forms.CharField(widget=forms.TextInput(attrs={'size':'60', 'placeholder': "Photographers name"}), required = False) year = forms.CharField(widget=forms.TextInput(attrs={'size':'60', 'placeholder': "Year photo was taken"}), required = False) change_message = forms.CharField(widget=forms.Textarea(attrs={"cols":80, "rows":3, 'placeholder': "Descibe the change made (for git)"})) def __init__(self, *args, **kwargs): self.directory = Path(kwargs.pop('directory')) super(forms.Form, self).__init__(*args, **kwargs) def get_rel_paths(self): f = self.cleaned_data['file_'] return [self.directory / "i" / (f.name.rsplit('.', 1)[0] + ".png"), self.directory / "t" / (f.name.rsplit('.', 1)[0] + ".png"), self.directory / "l" / (f.name.rsplit('.', 1)[0] + ".html")] def get_full_paths(self): return [Path(settings.EXPOWEB) / x for x in self.get_rel_paths()] def clean_file_(self): for rel_path, full_path in zip(self.get_rel_paths(), self.get_full_paths()): if full_path.exists(): raise forms.ValidationError(f"File already exists in {rel_path}") return self.cleaned_data['file_'] class HTMLarea(forms.Textarea): template_name = "widgets/HTMLarea.html" def __init__(self, *args, **kwargs): self.preview = kwargs.pop('preview', False) super(forms.Textarea, self).__init__(*args, **kwargs) def get_context(self, name, value, attrs): c = super(forms.Textarea, self).get_context(name, value, attrs) c["preview"] = self.preview return c