Mercurial > public > sg101
changeset 718:bf5340705d0c
Completed view to delete user photos.
Still need to modify the admin to delete not just the model instance but the S3
bucket keys.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Wed, 18 Sep 2013 21:34:05 -0500 |
parents | 846cf9a06a04 |
children | cc8de231df5a |
files | core/s3.py sg101/templates/user_photos/gallery.html sg101/templates/user_photos/photo_detail.html user_photos/s3.py user_photos/views.py |
diffstat | 5 files changed, 118 insertions(+), 10 deletions(-) [+] |
line wrap: on
line diff
--- a/core/s3.py Wed Sep 18 18:33:52 2013 -0500 +++ b/core/s3.py Wed Sep 18 21:34:05 2013 -0500 @@ -10,8 +10,6 @@ class S3Bucket(object): """This class abstracts an Amazon S3 bucket. - We currently only support upload functionality. - """ def __init__(self, access_key, secret_key, base_url, bucket_name): self.conn = S3Connection(access_key, secret_key) @@ -71,6 +69,28 @@ key.make_public() return '{}{}/{}'.format(self.base_url, self.name, key_name) + def delete_keys(self, key_urls): + """Deletes a set of keys, specified as a list of URLs. The URLs could + have been returned by one or more of the upload_* methods. + + Returns the number of keys that were successfully deleted. + + """ + if len(key_urls) == 0: + return 0 + + prefix = '{}{}/'.format(self.base_url, self.name) + prefix_len = len(prefix) + + keys = [] + for url in key_urls: + if url.startswith(prefix): + key = url[prefix_len:] + keys.append(key) + + response = self.bucket.delete_keys(keys, quiet=True) + return len(key_urls) - len(response.errors) + def _make_key(self, key_name, metadata): """Private method to create a key and optionally apply metadata to it.
--- a/sg101/templates/user_photos/gallery.html Wed Sep 18 18:33:52 2013 -0500 +++ b/sg101/templates/user_photos/gallery.html Wed Sep 18 21:34:05 2013 -0500 @@ -4,6 +4,34 @@ {% block custom_css %} <link rel="stylesheet" href="{{ STATIC_URL }}css/user_photos.css" /> {% endblock %} +{% block custom_js %} +{% if user == gallery_owner %} +<script> +function confirmPhotoDelete(submit) +{ + var n = $("#photo-delete input[type='checkbox']:checked").length; + if (n == 0) + { + alert("Please select some photos to delete."); + return false; + } + + var msg = [ + "Are you sure you want to delete these photos?\n", + "This will cause broken images in any posts you pasted them in. ", + "To fix this you can edit the posts." + ].join(""); + var result = confirm(msg); + if (result) + { + submit.disabled = true; + submit.value = "Please wait..."; + } + return result; +} +</script> +{% endif %} +{% endblock %} {% block content %} <h2>Photo Gallery for {{ gallery_owner.username }}</h2> @@ -27,7 +55,8 @@ {% if photos %} {% if user == gallery_owner %} - <form action="{% url 'user_photos-delete' %}" method="post">{% csrf_token %} + <form id="photo-delete" action="{% url 'user_photos-delete' %}" method="post" + onsubmit="return confirmPhotoDelete(submit);" >{% csrf_token %} {% for photo in photos %} <div class="user_photo owner_photo"> <a href="{{ photo.get_absolute_url }}">
--- a/sg101/templates/user_photos/photo_detail.html Wed Sep 18 18:33:52 2013 -0500 +++ b/sg101/templates/user_photos/photo_detail.html Wed Sep 18 21:34:05 2013 -0500 @@ -61,7 +61,14 @@ <a href="{% url 'user_photos-upload' %}">Upload another photo</a></li> <li><img src="{{ STATIC_URL }}icons/pictures.png" alt="Gallery" /> <a href="{% url 'user_photos-gallery' username=object.user.username %}">See all my photos</a></li> - </ul> +</ul> + +<form id="photo-delete" action="{% url 'user_photos-delete' %}" method="post" + onsubmit="return confirm('Really delete this photo?');" >{% csrf_token %} + <input type="hidden" name="photo_id" value="{{ object.id }}"></input> + <input type="submit" name="submit" value="Delete Photo" /> +</form> + {% else %} <p> <img src="{{ STATIC_URL }}icons/pictures.png" alt="Gallery" />
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/user_photos/s3.py Wed Sep 18 21:34:05 2013 -0500 @@ -0,0 +1,40 @@ +"""Module for all S3 related operations for the user_photos application.""" + +import logging + +from django.conf import settings + +from core.s3 import S3Bucket + + +logger = logging.getLogger(__name__) + + +def delete_photos(qs): + """Delete the photos stored on S3 for the given Photo queryset. + + Returns the number of photos actually deleted. + + """ + + bucket = S3Bucket(settings.USER_PHOTOS_ACCESS_KEY, + settings.USER_PHOTOS_SECRET_KEY, + settings.USER_PHOTOS_BASE_URL, + settings.USER_PHOTOS_BUCKET) + + key_urls = [] + for photo in qs: + key_urls.append(photo.url) + key_urls.append(photo.thumb_url) + req_cnt = len(key_urls) + + logger.info("Requesting deletion of %d user photo(s) from S3", req_cnt) + + act_cnt = bucket.delete_keys(key_urls) + + if act_cnt == req_cnt: + logger.info("Deleted %d user photo(s) from S3", act_cnt) + else: + logger.warning("Deleted %d user photo(s) out of %d", act_cnt, req_cnt) + + return act_cnt
--- a/user_photos/views.py Wed Sep 18 18:33:52 2013 -0500 +++ b/user_photos/views.py Wed Sep 18 21:34:05 2013 -0500 @@ -10,6 +10,7 @@ from user_photos.forms import UploadForm from user_photos.models import Photo +from user_photos.s3 import delete_photos @login_required @@ -69,6 +70,14 @@ @login_required @require_POST def delete(request): + """A view function to allow a user to delete their own photos.""" + + ret_view, username = 'user_photos-gallery', request.user.username + + if not settings.USER_PHOTOS_ENABLED: + messages.error(request, "This function is disabled temporarily") + return redirect(ret_view, username) + photo_ids = [] for photo_id in request.POST.getlist('photo_id'): try: @@ -80,11 +89,14 @@ count = 0 if photo_ids: qs = Photo.objects.filter(user=request.user, pk__in=photo_ids) - count = qs.count() - qs.delete() + count = len(qs) + if count: + delete_photos(qs) + qs.delete() - if count: - msg = "{} photo{} deleted".format(count, '' if count == 1 else 's') - messages.add_message(request, messages.INFO, msg) + msg = "{} photo{} deleted".format(count, '' if count == 1 else 's') + messages.add_message(request, + messages.SUCCESS if count > 0 else messages.WARNING, + msg) - return redirect('user_photos-gallery', username=request.user.username) + return redirect(ret_view, username)