Ticket #465: 465-delete-attachment.patch

File 465-delete-attachment.patch, 8.5 KB (added by digital-dreamer, 10 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  
    3030from sqlalchemy.ext.associationproxy import association_proxy
    3131from sqlalchemy.util import memoized_property
    3232
     33from mediagoblin import mg_globals
    3334from mediagoblin.db.extratypes import (PathTupleWithSlashes, JSONEncoded,
    3435                                       MutationDict)
    3536from mediagoblin.db.base import Base, DictReadAttrProxy
    class MediaAttachmentFile(Base):  
    449450    def dict_view(self):
    450451        """A dict like view on this object"""
    451452        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
    452465
    453466
    454467class 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 {  
    262262  font-family: 'Lato', sans-serif;
    263263}
    264264
     265.button_small {
     266  padding: 1px 3px;
     267  font-size: 14px;
     268}
     269
     270.nowrap {
     271  white-space: nowrap;
     272}
     273
    265274.pagination {
    266275text-align: center;
    267276}
    pre {  
    864873    padding: 5px 14px;
    865874    margin-bottom: 0.5em;
    866875  }
     876 
     877  .button_small {
     878    padding: 1px 3px;
     879    font-size: 14px;
     880  }
    867881   
    868882}
    869883/* 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  
    204204      <h3>{% trans %}Attachments{% endtrans %}</h3>
    205205      <ul>
    206206        {%- for attachment in media.attachment_files %}
    207           <li>
     207          <li class="nowrap">
    208208            <a href="{{ request.app.public_store.file_url(attachment.filepath) }}">
    209209              {{- attachment.name -}}
    210210            </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 %}
    211220          </li>
    212221        {%- endfor %}
    213222      </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',  
    3131          '/u/<string:user>/m/<int:media_id>/confirm-delete/',
    3232          'mediagoblin.user_pages.views:media_confirm_delete')
    3333
     34add_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
    3438# Submission handling of new comments. TODO: only allow for POST methods
    3539add_route('mediagoblin.user_pages.media_post_comment',
    3640          '/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  
    2020
    2121from mediagoblin import messages, mg_globals
    2222from mediagoblin.db.models import (MediaEntry, MediaTag, Collection,
    23                                    CollectionItem, User)
     23                                   CollectionItem, User, MediaAttachmentFile)
    2424from mediagoblin.tools.response import render_to_response, render_404, \
    2525    redirect, redirect_obj
    2626from mediagoblin.tools.text import cleaned_markdown_conversion
    def media_confirm_delete(request, media):  
    331331        'mediagoblin/user_pages/media_confirm_delete.html',
    332332        {'media': media,
    333333         'form': form})
     334   
     335@get_media_entry_by_id
     336@require_active_login
     337@user_may_delete_media
     338def 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
    334377
    335378@user_not_banned
    336379@active_user_from_url