123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 |
- import os
- from django.conf import settings
- from django.core.paginator import Paginator
- from django.http import HttpResponse, JsonResponse
- from django.shortcuts import get_object_or_404, redirect, render
- from django.urls import reverse
- from django.urls.exceptions import NoReverseMatch
- from django.utils.translation import ugettext as _
- from django.views.decorators.vary import vary_on_headers
- from wagtail.admin import messages
- from wagtail.admin.auth import PermissionPolicyChecker, permission_denied
- from wagtail.admin.forms.search import SearchForm
- from wagtail.admin.models import popular_tags_for_model
- from wagtail.core.models import Collection, Site
- from wagtail.images import get_image_model
- from wagtail.images.exceptions import InvalidFilterSpecError
- from wagtail.images.forms import URLGeneratorForm, get_image_form
- from wagtail.images.models import Filter, SourceImageIOError
- from wagtail.images.permissions import permission_policy
- from wagtail.images.views.serve import generate_signature
- from wagtail.search import index as search_index
- permission_checker = PermissionPolicyChecker(permission_policy)
- INDEX_PAGE_SIZE = getattr(settings, 'WAGTAILIMAGES_INDEX_PAGE_SIZE', 20)
- USAGE_PAGE_SIZE = getattr(settings, 'WAGTAILIMAGES_USAGE_PAGE_SIZE', 20)
- @permission_checker.require_any('add', 'change', 'delete')
- @vary_on_headers('X-Requested-With')
- def index(request):
- Image = get_image_model()
- # Get images (filtered by user permission)
- images = permission_policy.instances_user_has_any_permission_for(
- request.user, ['change', 'delete']
- ).order_by('-created_at')
- # Search
- query_string = None
- if 'q' in request.GET:
- form = SearchForm(request.GET, placeholder=_("Search images"))
- if form.is_valid():
- query_string = form.cleaned_data['q']
- images = images.search(query_string)
- else:
- form = SearchForm(placeholder=_("Search images"))
- # Filter by collection
- current_collection = None
- collection_id = request.GET.get('collection_id')
- if collection_id:
- try:
- current_collection = Collection.objects.get(id=collection_id)
- images = images.filter(collection=current_collection)
- except (ValueError, Collection.DoesNotExist):
- pass
- # Filter by tag
- current_tag = request.GET.get('tag')
- if current_tag:
- try:
- images = images.filter(tags__name=current_tag)
- except (AttributeError):
- current_tag = None
- paginator = Paginator(images, per_page=INDEX_PAGE_SIZE)
- images = paginator.get_page(request.GET.get('p'))
- collections = permission_policy.collections_user_has_any_permission_for(
- request.user, ['add', 'change']
- )
- if len(collections) < 2:
- collections = None
- else:
- collections = Collection.order_for_display(collections)
- # Create response
- if request.is_ajax():
- return render(request, 'wagtailimages/images/results.html', {
- 'images': images,
- 'query_string': query_string,
- 'is_searching': bool(query_string),
- })
- else:
- return render(request, 'wagtailimages/images/index.html', {
- 'images': images,
- 'query_string': query_string,
- 'is_searching': bool(query_string),
- 'search_form': form,
- 'popular_tags': popular_tags_for_model(Image),
- 'current_tag': current_tag,
- 'collections': collections,
- 'current_collection': current_collection,
- 'user_can_add': permission_policy.user_has_permission(request.user, 'add'),
- })
- @permission_checker.require('change')
- def edit(request, image_id):
- Image = get_image_model()
- ImageForm = get_image_form(Image)
- image = get_object_or_404(Image, id=image_id)
- if not permission_policy.user_has_permission_for_instance(request.user, 'change', image):
- return permission_denied(request)
- if request.method == 'POST':
- original_file = image.file
- form = ImageForm(request.POST, request.FILES, instance=image, user=request.user)
- if form.is_valid():
- if 'file' in form.changed_data:
- # Set new image file size
- image.file_size = image.file.size
- # Set new image file hash
- image.file.seek(0)
- image._set_file_hash(image.file.read())
- image.file.seek(0)
- form.save()
- if 'file' in form.changed_data:
- # if providing a new image file, delete the old one and all renditions.
- # NB Doing this via original_file.delete() clears the file field,
- # which definitely isn't what we want...
- original_file.storage.delete(original_file.name)
- image.renditions.all().delete()
- # Reindex the image to make sure all tags are indexed
- search_index.insert_or_update_object(image)
- messages.success(request, _("Image '{0}' updated.").format(image.title), buttons=[
- messages.button(reverse('wagtailimages:edit', args=(image.id,)), _('Edit again'))
- ])
- return redirect('wagtailimages:index')
- else:
- messages.error(request, _("The image could not be saved due to errors."))
- else:
- form = ImageForm(instance=image, user=request.user)
- # Check if we should enable the frontend url generator
- try:
- reverse('wagtailimages_serve', args=('foo', '1', 'bar'))
- url_generator_enabled = True
- except NoReverseMatch:
- url_generator_enabled = False
- if image.is_stored_locally():
- # Give error if image file doesn't exist
- if not os.path.isfile(image.file.path):
- messages.error(request, _(
- "The source image file could not be found. Please change the source or delete the image."
- ).format(image.title), buttons=[
- messages.button(reverse('wagtailimages:delete', args=(image.id,)), _('Delete'))
- ])
- try:
- filesize = image.get_file_size()
- except SourceImageIOError:
- filesize = None
- return render(request, "wagtailimages/images/edit.html", {
- 'image': image,
- 'form': form,
- 'url_generator_enabled': url_generator_enabled,
- 'filesize': filesize,
- 'user_can_delete': permission_policy.user_has_permission_for_instance(
- request.user, 'delete', image
- ),
- })
- def url_generator(request, image_id):
- image = get_object_or_404(get_image_model(), id=image_id)
- if not permission_policy.user_has_permission_for_instance(request.user, 'change', image):
- return permission_denied(request)
- form = URLGeneratorForm(initial={
- 'filter_method': 'original',
- 'width': image.width,
- 'height': image.height,
- })
- return render(request, "wagtailimages/images/url_generator.html", {
- 'image': image,
- 'form': form,
- })
- def generate_url(request, image_id, filter_spec):
- # Get the image
- Image = get_image_model()
- try:
- image = Image.objects.get(id=image_id)
- except Image.DoesNotExist:
- return JsonResponse({
- 'error': "Cannot find image."
- }, status=404)
- # Check if this user has edit permission on this image
- if not permission_policy.user_has_permission_for_instance(request.user, 'change', image):
- return JsonResponse({
- 'error': "You do not have permission to generate a URL for this image."
- }, status=403)
- # Parse the filter spec to make sure its valid
- try:
- Filter(spec=filter_spec).operations
- except InvalidFilterSpecError:
- return JsonResponse({
- 'error': "Invalid filter spec."
- }, status=400)
- # Generate url
- signature = generate_signature(image_id, filter_spec)
- url = reverse('wagtailimages_serve', args=(signature, image_id, filter_spec))
- # Get site root url
- try:
- site_root_url = Site.objects.get(is_default_site=True).root_url
- except Site.DoesNotExist:
- site_root_url = Site.objects.first().root_url
- # Generate preview url
- preview_url = reverse('wagtailimages:preview', args=(image_id, filter_spec))
- return JsonResponse({'url': site_root_url + url, 'preview_url': preview_url}, status=200)
- def preview(request, image_id, filter_spec):
- image = get_object_or_404(get_image_model(), id=image_id)
- try:
- response = HttpResponse()
- image = Filter(spec=filter_spec).run(image, response)
- response['Content-Type'] = 'image/' + image.format_name
- return response
- except InvalidFilterSpecError:
- return HttpResponse("Invalid filter spec: " + filter_spec, content_type='text/plain', status=400)
- @permission_checker.require('delete')
- def delete(request, image_id):
- image = get_object_or_404(get_image_model(), id=image_id)
- if not permission_policy.user_has_permission_for_instance(request.user, 'delete', image):
- return permission_denied(request)
- if request.method == 'POST':
- image.delete()
- messages.success(request, _("Image '{0}' deleted.").format(image.title))
- return redirect('wagtailimages:index')
- return render(request, "wagtailimages/images/confirm_delete.html", {
- 'image': image,
- })
- @permission_checker.require('add')
- def add(request):
- ImageModel = get_image_model()
- ImageForm = get_image_form(ImageModel)
- if request.method == 'POST':
- image = ImageModel(uploaded_by_user=request.user)
- form = ImageForm(request.POST, request.FILES, instance=image, user=request.user)
- if form.is_valid():
- # Set image file size
- image.file_size = image.file.size
- # Set image file hash
- image.file.seek(0)
- image._set_file_hash(image.file.read())
- image.file.seek(0)
- form.save()
- # Reindex the image to make sure all tags are indexed
- search_index.insert_or_update_object(image)
- messages.success(request, _("Image '{0}' added.").format(image.title), buttons=[
- messages.button(reverse('wagtailimages:edit', args=(image.id,)), _('Edit'))
- ])
- return redirect('wagtailimages:index')
- else:
- messages.error(request, _("The image could not be created due to errors."))
- else:
- form = ImageForm(user=request.user)
- return render(request, "wagtailimages/images/add.html", {
- 'form': form,
- })
- def usage(request, image_id):
- image = get_object_or_404(get_image_model(), id=image_id)
- paginator = Paginator(image.get_usage(), per_page=USAGE_PAGE_SIZE)
- used_by = paginator.get_page(request.GET.get('p'))
- return render(request, "wagtailimages/images/usage.html", {
- 'image': image,
- 'used_by': used_by
- })
|