from django.shortcuts import render, redirect from django.http import HttpResponse, HttpResponseRedirect, Http404, JsonResponse from django.urls import reverse, resolve from django.template import Context, loader import re, io from PIL import Image from pathlib import Path import django.forms as forms import troggle.settings as settings from django.views.decorators.csrf import ensure_csrf_cookie from .auth import login_required_if_public from troggle.core.utils import write_and_commit, WriteAndCommitError 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