Ticket #465: 465-delete-attachment.patch
File 465-delete-attachment.patch, 8.5 KB (added by , 11 years ago) |
---|
-
mediagoblin/db/models.py
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index b750375..39e1f03 100644
a b from sqlalchemy.sql.expression import desc 30 30 from sqlalchemy.ext.associationproxy import association_proxy 31 31 from sqlalchemy.util import memoized_property 32 32 33 from mediagoblin import mg_globals 33 34 from mediagoblin.db.extratypes import (PathTupleWithSlashes, JSONEncoded, 34 35 MutationDict) 35 36 from mediagoblin.db.base import Base, DictReadAttrProxy … … class MediaAttachmentFile(Base): 449 450 def dict_view(self): 450 451 """A dict like view on this object""" 451 452 return DictReadAttrProxy(self) 453 454 def delete(self, **kwargs): 455 """Delete MediaAttachmentFile""" 456 457 try: 458 mg_globals.public_store.delete_file(self.filepath) 459 except OSError, error: 460 _log.error('No such attachment file to delete: {0}'.format(str(error))) 461 _log.info('Deleted Attachment entry id "{0}"'.format(self.id)) 462 463 super(MediaAttachmentFile, self).delete(**kwargs) 464 452 465 453 466 454 467 class Tag(Base): -
mediagoblin/static/css/base.css
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 32c6c6c..459c4fa 100644
a b footer { 262 262 font-family: 'Lato', sans-serif; 263 263 } 264 264 265 .button_small { 266 padding: 1px 3px; 267 font-size: 14px; 268 } 269 270 .nowrap { 271 white-space: nowrap; 272 } 273 265 274 .pagination { 266 275 text-align: center; 267 276 } … … pre { 864 873 padding: 5px 14px; 865 874 margin-bottom: 0.5em; 866 875 } 876 877 .button_small { 878 padding: 1px 3px; 879 font-size: 14px; 880 } 867 881 868 882 } 869 883 /* desktop resolutions */ -
mediagoblin/templates/mediagoblin/user_pages/media.html
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index e01cce5..aef51d5 100644
a b 204 204 <h3>{% trans %}Attachments{% endtrans %}</h3> 205 205 <ul> 206 206 {%- for attachment in media.attachment_files %} 207 <li >207 <li class="nowrap"> 208 208 <a href="{{ request.app.public_store.file_url(attachment.filepath) }}"> 209 209 {{- attachment.name -}} 210 210 </a> 211 {% if request.user and 212 (media.uploader == request.user.id or 213 request.user.has_privilege('admin')) %} 214 {% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete_attachment', 215 user=media.get_uploader.username, 216 media_id=media.id, 217 attachment_id=attachment.id) %} 218 <a class="button_action button_warning button_small" href="{{ delete_url }}">{% trans %}Delete{% endtrans %}</a> 219 {%- endif %} 211 220 </li> 212 221 {%- endfor %} 213 222 </ul> -
new file mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete_attachment.html
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete_attachment.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete_attachment.html new file mode 100644 index 0000000..b9e0684
- + 1 {# 2 # GNU MediaGoblin -- federated, autonomous media hosting 3 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. 4 # 5 # This program is free software: you can redistribute it and/or modify 6 # it under the terms of the GNU Affero General Public License as published by 7 # the Free Software Foundation, either version 3 of the License, or 8 # (at your option) any later version. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU Affero General Public License for more details. 14 # 15 # You should have received a copy of the GNU Affero General Public License 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. 17 #} 18 {% extends "mediagoblin/base.html" %} 19 20 {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} 21 22 {% block mediagoblin_content %} 23 24 <form action="{{ request.urlgen('mediagoblin.user_pages.media_confirm_delete_attachment', 25 user=media.get_uploader.username, 26 media_id=media.id, 27 attachment_id=attachment.id) }}" 28 method="POST" enctype="multipart/form-data"> 29 <div class="form_box"> 30 <h2> 31 {% trans %}Really delete this attachment?{% endtrans %} 32 </h2> 33 <h3> 34 {{ attachment.name }} 35 </h3> 36 37 <br /> 38 39 <p class="delete_checkbox_box"> 40 {{ form.confirm }} 41 {{ wtforms_util.render_label(form.confirm) }} 42 </p> 43 44 <div class="form_submit_buttons"> 45 {# TODO: This isn't a button really... might do unexpected things :) #} 46 <a class="button_action" href="{{ media.url_for_self(request.urlgen) }}">{% trans %}Cancel{% endtrans %}</a> 47 <input type="submit" value="{% trans %}Delete permanently{% endtrans %}" class="button_form button_warning" /> 48 {{ csrf_token }} 49 </div> 50 </div> 51 </form> 52 {% endblock %} -
mediagoblin/user_pages/routing.py
diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index f0f4d8b..7766d02 100644
a b add_route('mediagoblin.user_pages.media_confirm_delete', 31 31 '/u/<string:user>/m/<int:media_id>/confirm-delete/', 32 32 'mediagoblin.user_pages.views:media_confirm_delete') 33 33 34 add_route('mediagoblin.user_pages.media_confirm_delete_attachment', 35 '/u/<string:user>/m/<int:media_id>/confirm-delete-attachment/<int:attachment_id>/', 36 'mediagoblin.user_pages.views:media_confirm_delete_attachment') 37 34 38 # Submission handling of new comments. TODO: only allow for POST methods 35 39 add_route('mediagoblin.user_pages.media_post_comment', 36 40 '/u/<string:user>/m/<int:media_id>/comment/add/', -
mediagoblin/user_pages/views.py
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 64fa793..ad3ef20 100644
a b import json 20 20 21 21 from mediagoblin import messages, mg_globals 22 22 from mediagoblin.db.models import (MediaEntry, MediaTag, Collection, 23 CollectionItem, User )23 CollectionItem, User, MediaAttachmentFile) 24 24 from mediagoblin.tools.response import render_to_response, render_404, \ 25 25 redirect, redirect_obj 26 26 from mediagoblin.tools.text import cleaned_markdown_conversion … … def media_confirm_delete(request, media): 331 331 'mediagoblin/user_pages/media_confirm_delete.html', 332 332 {'media': media, 333 333 'form': form}) 334 335 @get_media_entry_by_id 336 @require_active_login 337 @user_may_delete_media 338 def media_confirm_delete_attachment(request, media): 339 340 # media_id is verified to prevent attacks by URL with fake media/attachment pair 341 attachment = MediaAttachmentFile.query.filter_by( 342 id=request.matchdict['attachment_id'], 343 media_entry=request.matchdict['media_id']).first() 344 if not attachment: 345 return render_404(request) 346 347 form = user_forms.ConfirmDeleteForm(request.form) 348 349 if request.method == 'POST' and form.validate(): 350 if form.confirm.data is True: 351 352 attachment.delete(); 353 messages.add_message( 354 request, messages.SUCCESS, _('You deleted the attachment.')) 355 return redirect_obj(request, media) 356 357 else: 358 messages.add_message( 359 request, messages.ERROR, 360 _("The attachment was not deleted because you didn't check that you were sure.")) 361 return redirect_obj(request, media) 362 363 if ((request.user.has_privilege(u'admin') and 364 request.user.id != media.uploader)): 365 messages.add_message( 366 request, messages.WARNING, 367 _("You are about to delete another user's attachment. " 368 "Proceed with caution.")) 369 370 return render_to_response( 371 request, 372 'mediagoblin/user_pages/media_confirm_delete_attachment.html', 373 {'media': media, 374 'form': form, 375 'attachment': attachment}) 376 334 377 335 378 @user_not_banned 336 379 @active_user_from_url