Feature #482 - Media attachments -
authorJoar Wandborg <git@wandborg.com>
Mon, 22 Aug 2011 16:06:28 +0000 (18:06 +0200)
committerJoar Wandborg <git@wandborg.com>
Mon, 22 Aug 2011 16:06:28 +0000 (18:06 +0200)
*   Moved attachment uploading to separate view
*   Support for multiple attachments!

mediagoblin/edit/forms.py
mediagoblin/edit/views.py
mediagoblin/submit/forms.py
mediagoblin/submit/views.py
mediagoblin/templates/mediagoblin/edit/attachments.html [new file with mode: 0644]
mediagoblin/templates/mediagoblin/edit/edit.html
mediagoblin/templates/mediagoblin/submit/start.html
mediagoblin/templates/mediagoblin/user_pages/media.html
mediagoblin/user_pages/routing.py
mediagoblin/user_pages/views.py

index 37e2349c5372091906db637e89b0cdd0bb1d794a..3969e5098176ef538c597a26fb3137edbb84a828 100644 (file)
@@ -30,10 +30,6 @@ class EditForm(wtforms.Form):
     tags = wtforms.TextField(
         'Tags',
         [tag_length_validator])
-    attachment_name = wtforms.TextField(
-        'Attachment title')
-    attachment_delete = wtforms.BooleanField(
-        'Delete attachment')
 
 class EditProfileForm(wtforms.Form):
     bio = wtforms.TextAreaField('Bio',
@@ -42,3 +38,9 @@ class EditProfileForm(wtforms.Form):
         'Website',
         [wtforms.validators.Optional(),
          wtforms.validators.URL(message='Improperly formed URL')])
+
+class EditAttachmentsForm(wtforms.Form):
+    attachment_name = wtforms.TextField(
+        'Title')
+    attachment_file = wtforms.FileField(
+        'File')
index 09aee48b9c57be5169cbd1e93e201b3220f8dba7..c4d503b7ad299b265c0d23f58971872192138ec7 100644 (file)
 
 from webob import exc
 from string import split
+from cgi import FieldStorage
+from datetime import datetime
+
+from werkzeug.utils import secure_filename
 
 from mediagoblin import messages
 from mediagoblin import mg_globals
@@ -34,17 +38,15 @@ def edit_media(request, media):
     if not may_edit_media(request, media):
         return exc.HTTPForbidden()
 
-
     defaults = dict(
-        title = media['title'],
-        slug = media['slug'],
-        description = media['description'],
-        tags = media_tags_as_string(media['tags']))
+        title=media['title'],
+        slug=media['slug'],
+        description=media['description'],
+        tags=media_tags_as_string(media['tags']))
 
     if len(media['attachment_files']):
         defaults['attachment_name'] = media['attachment_files'][0]['name']
 
-
     form = forms.EditForm(
         request.POST,
         **defaults)
@@ -56,7 +58,7 @@ def edit_media(request, media):
             {'slug': request.POST['slug'],
              'uploader': media['uploader'],
              '_id': {'$ne': media['_id']}}).count()
-        
+
         if existing_user_slug_entries:
             form.slug.errors.append(
                 u'An entry with that slug already exists for this user.')
@@ -65,14 +67,16 @@ def edit_media(request, media):
             media['description'] = request.POST.get('description')
             media['tags'] = convert_to_tag_list_of_dicts(
                                    request.POST.get('tags'))
-            
+
             media['description_html'] = cleaned_markdown_conversion(
                 media['description'])
 
             if 'attachment_name' in request.POST:
-                media['attachment_files'][0]['name'] = request.POST['attachment_name']
+                media['attachment_files'][0]['name'] = \
+                    request.POST['attachment_name']
 
-            if 'attachment_delete' in request.POST and 'y' == request.POST['attachment_delete']:
+            if 'attachment_delete' in request.POST \
+                    and 'y' == request.POST['attachment_delete']:
                 del media['attachment_files'][0]
 
             media['slug'] = request.POST['slug']
@@ -87,18 +91,68 @@ def edit_media(request, media):
         messages.add_message(
             request, messages.WARNING,
             "You are editing another user's media. Proceed with caution.")
-        
 
     return render_to_response(
         request,
         'mediagoblin/edit/edit.html',
         {'media': media,
          'form': form})
-    
 
+
+@get_user_media_entry
 @require_active_login
-def edit_profile(request):
+def edit_attachments(request, media):
+    if mg_globals.app_config['allow_attachments']:
+        form = forms.EditAttachmentsForm()
+
+        # Add any attachements
+        if ('attachment_file' in request.POST
+            and isinstance(request.POST['attachment_file'], FieldStorage)
+            and request.POST['attachment_file'].file):
+
+            attachment_public_filepath \
+                = mg_globals.public_store.get_unique_filepath(
+                ['media_entries', unicode(media['_id']), 'attachment',
+                 secure_filename(request.POST['attachment_file'].filename)])
+
+            attachment_public_file = mg_globals.public_store.get_file(
+                attachment_public_filepath, 'wb')
+
+            try:
+                attachment_public_file.write(
+                    request.POST['attachment_file'].file.read())
+            finally:
+                request.POST['attachment_file'].file.close()
+
+            media['attachment_files'].append(dict(
+                    name=request.POST['attachment_name'] \
+                        or request.POST['attachment_file'].filename,
+                    filepath=attachment_public_filepath,
+                    created=datetime.utcnow()
+                    ))
 
+            media.save()
+
+            messages.add_message(
+                request, messages.SUCCESS,
+                "You added the attachment %s!" \
+                    % (request.POST['attachment_name']
+                       or request.POST['attachment_file'].filename))
+
+            return redirect(request, 'mediagoblin.user_pages.media_home',
+                            user=media.uploader()['username'],
+                            media=media['slug'])
+        return render_to_response(
+            request,
+            'mediagoblin/edit/attachments.html',
+            {'media': media,
+             'form': form})
+    else:
+        return exc.HTTPForbidden()
+
+
+@require_active_login
+def edit_profile(request):
     # admins may edit any user profile given a username in the querystring
     edit_username = request.GET.get('username')
     if request.user['is_admin'] and request.user['username'] != edit_username:
@@ -112,8 +166,8 @@ def edit_profile(request):
         user = request.user
 
     form = forms.EditProfileForm(request.POST,
-        url = user.get('url'),
-        bio = user.get('bio'))
+        url=user.get('url'),
+        bio=user.get('bio'))
 
     if request.method == 'POST' and form.validate():
             user['url'] = request.POST['url']
@@ -123,12 +177,12 @@ def edit_profile(request):
 
             user.save()
 
-            messages.add_message(request, 
-                                messages.SUCCESS, 
-                                'Profile edited!')
+            messages.add_message(request,
+                                 messages.SUCCESS,
+                                 'Profile edited!')
             return redirect(request,
                            'mediagoblin.user_pages.user_home',
-                           user=edit_username)
+                            user=edit_username)
 
     return render_to_response(
         request,
index 9b35a8c3b1f60e60234f2b0c912064ff442c9ccc..f02c95a69f970e6ef47a0aa76f00bc8195f7ce3b 100644 (file)
@@ -28,6 +28,3 @@ class SubmitStartForm(wtforms.Form):
     tags = wtforms.TextField(
         'Tags',
         [tag_length_validator])
-    attachment = wtforms.FileField(
-        'Attachment',
-        [wtforms.validators.Optional()])
index 213b2494904192c7b78ae2bd899e3e7fe6a7895e..126cf3a88a15ebdc4765ac08568e957608a90c22 100644 (file)
@@ -76,31 +76,6 @@ def submit_start(request):
             # Generate a slug from the title
             entry.generate_slug()
 
-            # Add any attachements
-            if (mg_globals.app_config['allow_attachments']
-                and request.POST.has_key('attachment')
-                and isinstance(request.POST['attachment'], FieldStorage)
-                and request.POST['attachment'].file):
-
-                attachment_public_filepath = mg_globals.public_store.get_unique_filepath(
-                    ['media_entries',
-                     unicode('attachment-%s' % entry['_id']),
-                     secure_filename(request.POST['attachment'].filename)])
-
-                attachment_public_file = mg_globals.public_store.get_file(
-                    attachment_public_filepath, 'wb')
-
-                try:
-                    attachment_public_file.write(request.POST['attachment'].file.read())
-                finally:
-                    request.POST['attachment'].file.close()
-
-                entry['attachment_files'] = [dict(
-                        name=request.POST['attachment'].filename,
-                        filepath=attachment_public_filepath,
-                        created=datetime.utcnow()
-                        )]
-
             # Now store generate the queueing related filename
             queue_filepath = request.app.queue_store.get_unique_filepath(
                 ['media_entries',
diff --git a/mediagoblin/templates/mediagoblin/edit/attachments.html b/mediagoblin/templates/mediagoblin/edit/attachments.html
new file mode 100644 (file)
index 0000000..2f319db
--- /dev/null
@@ -0,0 +1,55 @@
+{#
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 Free Software Foundation, Inc
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#}
+{% extends "mediagoblin/base.html" %}
+
+{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
+{% block mediagoblin_content %}
+  <form action="{{ request.urlgen('mediagoblin.edit.attachments',
+                               user= media.uploader().username,
+                               media= media._id) }}"
+        method="POST" enctype="multipart/form-data">
+    <div class="grid_8 prefix_1 suffix_1 edit_box form_box">
+      <h1>Editing attachments for {{ media.title }}</h1>
+      <div style="text-align: center;" >
+        <img src="{{ request.app.public_store.file_url(
+                         media['media_files']['thumb']) }}" />
+      </div>
+
+      {% if media.attachment_files|count %}
+      <h2>Attachments</h2>
+      <ul>
+       {% for attachment in media.attachment_files %}
+          <li>
+           <a target="_blank" href="{{ request.app.public_store.file_url(
+                                    attachment['filepath']) }}">
+             {{ attachment.name -}}
+           </a><br />
+         </li>
+       {% endfor %}
+      </ul>
+      {% endif %}
+
+      <h2>Add attachment</h2>
+      {{ wtforms_util.render_divs(form) }}
+      <div class="form_submit_buttons">
+        <a href="{{ media.url_for_self(request.urlgen) }}">Cancel</a>
+        <input type="submit" value="Save changes" class="button" />
+      </div>
+    </div>
+  </form>
+{% endblock %}
index c834918ed02ae243ea3b73659ff73a53298b8ea4..d19034cbd18600a0850d9439f2cbc410e7adc577 100644 (file)
         <img src="{{ request.app.public_store.file_url(
                          media['media_files']['thumb']) }}" />
       </div>
-      {{ wtforms_util.render_field_div(form.title) }}
-      {{ wtforms_util.render_field_div(form.slug) }}
-      {{ wtforms_util.render_field_div(form.description) }}
-      {{ wtforms_util.render_field_div(form.tags) }}
-      {% if media.attachment_files %}
-        {{ wtforms_util.render_field_div(form.attachment_name) }}
-        {{ wtforms_util.render_field_div(form.attachment_delete) }}
-      {% endif %}
+      {{ wtforms_util.render_divs(form) }}
       <div class="form_submit_buttons">
         <a href="{{ media.url_for_self(request.urlgen) }}">Cancel</a>
         <input type="submit" value="Save changes" class="button" />
index 42bbf72471ca5f5bc8f772ff51fb4f12ddfd893e..6d00510cbd71b3d56bf8aefadcd3489ed1235994 100644 (file)
@@ -28,9 +28,6 @@
       {{ wtforms_util.render_field_div(submit_form.title) }}
       {{ wtforms_util.render_textarea_div(submit_form.description) }}
       {{ wtforms_util.render_field_div(submit_form.tags) }}
-      {% if app_config.allow_attachments %}
-        {{ wtforms_util.render_field_div(submit_form.attachment) }}
-      {% endif %}
       <div class="form_submit_buttons">
       <input type="submit" value="Submit" class="button" />
       </div>
index cc4c3350fe4893aae3fa0f02a2e5e3f67b4b1f8b..1a5eed1f452eff70b0aa6c754fa5dbd98e7f281d 100644 (file)
     <div class="grid_5 omega">
       {% include "mediagoblin/utils/prev_next.html" %}
       <h3>Sidebar content here!</h3>
-
-      {% if media.attachment_files %}
-      <dl>
-       <dd>Attachments</dd>
-       {% for attachment in media.attachment_files %}
-       <dt>
-         <a href="{{ request.app.public_store.file_url(
-      attachment.filepath) }}">
-           {{ attachment.name }}
-         </a>
-       </dt>
-       {% endfor %}
-      </dl>
-      {% endif %}
+      {% if media.attachment_files or media['uploader'] == request.user['_id'] or
+                                        request.user['is_admin'] %}
 
       <p>
         {% if media['uploader'] == request.user['_id'] or 
         {% endif %}
       </p>
 
+      {% if media.attachment_files|count %}
+      <h3>Attachments</h3>
+      <ul>
+        {% for attachment in media.attachment_files %}
+          <li>
+            <a href="{{ request.app.public_store.file_url(
+      attachment.filepath) }}">
+           {{ attachment.name }}
+           </a>
+         </li>
+         {% endfor %}
+        {% endif %}
+      </ul>
+      {% endif %}
+      {% if app_config['allow_attachments'] %}
+        <a href="{{ request.urlgen('mediagoblin.edit.attachments',
+                 user= media.uploader().username,
+                 media= media._id) }}">Add attachment</a>
+      {% endif %}
+
       {% if media.tags %}
         {% include "mediagoblin/utils/tags.html" %}
       {% endif %}
index 3be0617dd74e69ef99fd89e60e3a7295b65d8814..81bb80c262d89b0c5edc78dc0ab306e8ca16f8c3 100644 (file)
@@ -28,7 +28,10 @@ user_routes = [
           '/{user}/m/{media}/c/{comment}/',
           controller="mediagoblin.user_pages.views:media_home"),
     Route('mediagoblin.edit.edit_media', "/{user}/m/{media}/edit/",
-        controller="mediagoblin.edit.views:edit_media"),
+          controller="mediagoblin.edit.views:edit_media"),
+    Route('mediagoblin.edit.attachments',
+          '/{user}/m/{media}/attachments/',
+          controller="mediagoblin.edit.views:edit_attachments"),
     Route('mediagoblin.user_pages.atom_feed', '/{user}/atom/',
         controller="mediagoblin.user_pages.views:atom_feed"),
     Route('mediagoblin.user_pages.media_post_comment',
index 85a84db6546d6d5446422c416fcaa5e2ce253333..8b9d94e52e2ca285bf768c76d68ad6b28afaae37 100644 (file)
@@ -16,7 +16,7 @@
 
 from webob import exc
 
-from mediagoblin import messages
+from mediagoblin import messages, mg_globals
 from mediagoblin.db.util import DESCENDING, ObjectId
 from mediagoblin.util import (
     Pagination, render_to_response, redirect, cleaned_markdown_conversion)
@@ -117,7 +117,8 @@ def media_home(request, media, page, **kwargs):
         {'media': media,
          'comments': comments,
          'pagination': pagination,
-         'comment_form': comment_form})
+         'comment_form': comment_form,
+         'app_config': mg_globals.app_config})
 
 
 @require_active_login