diff options
34 files changed, 388 insertions, 185 deletions
@@ -10,6 +10,7 @@ mediagoblin.egg-info *.pyo docs/_build/ user_dev/ +mediagoblin_user.ini server-log.txt *~ *.swp diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 911f2340..08b228f1 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -150,7 +150,7 @@ celeryd in another window. Run:: - CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_celery ./bin/celeryd + CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_celery ./bin/celeryd Running the test suite diff --git a/lazyserver.sh b/lazyserver.sh index fdb03ba0..4f10f771 100755 --- a/lazyserver.sh +++ b/lazyserver.sh @@ -16,6 +16,22 @@ # 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/>. +if [ "$1" = "-h" ] +then + echo "$0 [-h] [-c paste.ini] ARGS_to_paster" + echo " For example:" + echo " $0 -c fcgi.ini port_number=23371" + exit 1 +fi + +PASTE_INI=paste.ini +if [ "$1" = "-c" ] +then + PASTE_INI="$2" + shift + shift +fi + if [ -f ./bin/paster ]; then echo "Using ./bin/paster"; export PASTER="./bin/paster"; @@ -27,4 +43,5 @@ else exit 1 fi -CELERY_ALWAYS_EAGER=true $PASTER serve paste.ini --reload +set -x +CELERY_ALWAYS_EAGER=true $PASTER serve $PASTE_INI "$@" --reload diff --git a/mediagoblin/app.py b/mediagoblin/app.py index b27b5761..9454b403 100644 --- a/mediagoblin/app.py +++ b/mediagoblin/app.py @@ -21,11 +21,12 @@ import routes from webob import Request, exc from mediagoblin import routing, util, storage, staticdirect -from mediagoblin.config import ( +from mediagoblin.init.config import ( read_mediagoblin_config, generate_validation_report) from mediagoblin.db.open import setup_connection_and_db_from_config from mediagoblin.mg_globals import setup_globals -from mediagoblin.celery_setup import setup_celery_from_config +from mediagoblin.init.celery import setup_celery_from_config +from mediagoblin.init import get_jinja_loader from mediagoblin.workbench import WorkbenchManager @@ -71,7 +72,7 @@ class MediaGoblinApp(object): app_config) # Get the template environment - self.template_loader = util.get_jinja_loader( + self.template_loader = get_jinja_loader( app_config.get('user_template_path')) # Set up storage systems diff --git a/mediagoblin/db/__init__.py b/mediagoblin/db/__init__.py index c129cbf8..776025ca 100644 --- a/mediagoblin/db/__init__.py +++ b/mediagoblin/db/__init__.py @@ -13,3 +13,49 @@ # # 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/>. + +""" +Database Abstraction/Wrapper Layer +================================== + + **NOTE from Chris Webber:** I asked Elrond to explain why he put + ASCENDING and DESCENDING in db/util.py when we could just import from + pymongo. Read beow for why, but note that nobody is actually doing + this and there's no proof that we'll ever support more than + MongoDB... it would be a huge amount of work to do so. + + If you really want to prove that possible, jump on IRC and talk to + us about making such a branch. In the meanwhile, it doesn't hurt to + have things as they are... if it ever makes it hard for us to + actually do things, we might revisit or remove this. But for more + information, read below. + +This submodule is for most of the db specific stuff. + +There are two main ideas here: + +1. Open up a small possibility to replace mongo by another + db. This means, that all direct mongo accesses should + happen in the db submodule. While all the rest uses an + API defined by this submodule. + + Currently this API happens to be basicly mongo. + Which means, that the abstraction/wrapper layer is + extremely thin. + +2. Give the rest of the app a simple and easy way to get most of + their db needs. Which often means some simple import + from db.util. + +What does that mean? + +* Never import mongo directly outside of this submodule. + +* Inside this submodule you can do whatever is needed. The + API border is exactly at the submodule layer. Nowhere + else. + +* helper functions can be moved in here. They become part + of the db.* API + +""" diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index bf825a23..8aa35ca9 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -22,8 +22,7 @@ from mediagoblin import util from mediagoblin.auth import lib as auth_lib from mediagoblin import mg_globals from mediagoblin.db import migrations -from mediagoblin.db.util import DESCENDING, ObjectId -from mediagoblin.util import Pagination +from mediagoblin.db.util import ASCENDING, DESCENDING, ObjectId ################### # Custom validators @@ -109,24 +108,13 @@ class MediaEntry(Document): migration_handler = migrations.MediaEntryMigration + def get_comments(self): + return self.db.MediaComment.find({ + 'media_entry': self['_id']}).sort('created', DESCENDING) + def main_mediafile(self): pass - - def get_comments(self, page): - cursor = self.db.MediaComment.find({ - 'media_entry': self['_id']}).sort('created', DESCENDING) - - pagination = Pagination(page, cursor) - comments = pagination() - - data = list() - for comment in comments: - comment['author'] = self.db.User.find_one({ - '_id': comment['author']}) - data.append(comment) - - return (data, pagination) - + def generate_slug(self): self['slug'] = util.slugify(self['title']) @@ -154,6 +142,32 @@ class MediaEntry(Document): 'mediagoblin.user_pages.media_home', user=uploader['username'], media=unicode(self['_id'])) + + def url_to_prev(self, urlgen): + """ + Provide a url to the previous entry from this user, if there is one + """ + cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']}, + 'uploader': self['uploader']}).sort( + '_id', DESCENDING).limit(1) + + if cursor.count(): + return urlgen('mediagoblin.user_pages.media_home', + user=self.uploader()['username'], + media=unicode(cursor[0]['_id'])) + + def url_to_next(self, urlgen): + """ + Provide a url to the next entry from this user, if there is one + """ + cursor = self.db.MediaEntry.find({'_id' : {"$gt": self['_id']}, + 'uploader': self['uploader']}).sort( + '_id', ASCENDING).limit(1) + + if cursor.count(): + return urlgen('mediagoblin.user_pages.media_home', + user=self.uploader()['username'], + media=unicode(cursor[0]['_id'])) def uploader(self): return self.db.User.find_one({'_id': self['uploader']}) diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 46f899f7..70c37945 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -30,7 +30,7 @@ document relevant to here: import copy # Imports that other modules might use -from pymongo import DESCENDING +from pymongo import ASCENDING, DESCENDING from pymongo.errors import InvalidId from mongokit import ObjectId diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index a9071495..e064a9c3 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -17,6 +17,7 @@ from webob import exc +from mediagoblin import messages from mediagoblin.util import render_to_response, redirect, clean_html from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media @@ -63,6 +64,14 @@ def edit_media(request, media): return redirect(request, "mediagoblin.user_pages.media_home", user=media.uploader()['username'], media=media['slug']) + if request.user['is_admin'] \ + and media['uploader'] != request.user['_id'] \ + and request.method != 'POST': + 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', @@ -73,7 +82,18 @@ def edit_media(request, media): @require_active_login def edit_profile(request): - user = request.user + # 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: + user = request.db.User.find_one({'username': edit_username}) + # No need to warn again if admin just submitted an edited profile + if request.method != 'POST': + messages.add_message( + request, messages.WARNING, + "You are editing a user's profile. Proceed with caution.") + else: + user = request.user + form = forms.EditProfileForm(request.POST, url = user.get('url'), bio = user.get('bio')) @@ -83,7 +103,12 @@ def edit_profile(request): user['bio'] = request.POST['bio'] user.save() - return redirect(request, "index", user=user['username']) + messages.add_message(request, + messages.SUCCESS, + 'Profile edited!') + return redirect(request, + "mediagoblin.edit.profile", + username=edit_username) return render_to_response( request, diff --git a/mediagoblin/templates/mediagoblin/media_details.html b/mediagoblin/init/__init__.py index 0e907616..b8ed2456 100644 --- a/mediagoblin/templates/mediagoblin/media_details.html +++ b/mediagoblin/init/__init__.py @@ -1,4 +1,3 @@ -{# # GNU MediaGoblin -- federated, autonomous media hosting # Copyright (C) 2011 Free Software Foundation, Inc # @@ -14,24 +13,21 @@ # # 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" %} -{% block mediagoblin_content %} - {# temporarily, an "image gallery" that isn't one really ;) #} - {% if media %} - <div class="grid_8 alpha media_image"> - <img src="{{ request.app.public_store.file_url( - media.media_files.main) }}" /> - <h1>Media details for {{media.title}}</h1> - <p> - <br/>Uploaded: {{ media.created}} - <br/>Description: {{media.description}} - </p> - </div> - <div class="grid_4 omega sidebar"> - <p>Uploaded: {{ media.created}}</p> - </div> - {% else %} - <p>Sorry, no such media found.<p/> - {% endif %} -{% endblock %} + +import jinja2 + + +def get_jinja_loader(user_template_path=None): + """ + Set up the Jinja template loaders, possibly allowing for user + overridden templates. + + (In the future we may have another system for providing theming; + for now this is good enough.) + """ + if user_template_path: + return jinja2.ChoiceLoader( + [jinja2.FileSystemLoader(user_template_path), + jinja2.PackageLoader('mediagoblin', 'templates')]) + else: + return jinja2.PackageLoader('mediagoblin', 'templates') diff --git a/mediagoblin/celery_setup/__init__.py b/mediagoblin/init/celery/__init__.py index e35dbce2..67c3dfa0 100644 --- a/mediagoblin/celery_setup/__init__.py +++ b/mediagoblin/init/celery/__init__.py @@ -20,7 +20,7 @@ import sys MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media'] -DEFAULT_SETTINGS_MODULE = 'mediagoblin.celery_setup.dummy_settings_module' +DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module' def setup_celery_from_config(app_config, global_config, diff --git a/mediagoblin/celery_setup/dummy_settings_module.py b/mediagoblin/init/celery/dummy_settings_module.py index e69de29b..e69de29b 100644 --- a/mediagoblin/celery_setup/dummy_settings_module.py +++ b/mediagoblin/init/celery/dummy_settings_module.py diff --git a/mediagoblin/celery_setup/from_celery.py b/mediagoblin/init/celery/from_celery.py index ed0a409e..c053591b 100644 --- a/mediagoblin/celery_setup/from_celery.py +++ b/mediagoblin/init/celery/from_celery.py @@ -17,7 +17,7 @@ import os from mediagoblin import app, mg_globals -from mediagoblin.celery_setup import setup_celery_from_config +from mediagoblin.init.celery import setup_celery_from_config OUR_MODULENAME = __name__ diff --git a/mediagoblin/celery_setup/from_tests.py b/mediagoblin/init/celery/from_tests.py index 779ecd65..b2293e2c 100644 --- a/mediagoblin/celery_setup/from_tests.py +++ b/mediagoblin/init/celery/from_tests.py @@ -17,7 +17,7 @@ import os from mediagoblin.tests.tools import TEST_APP_CONFIG -from mediagoblin.celery_setup.from_celery import setup_self +from mediagoblin.init.celery.from_celery import setup_self OUR_MODULENAME = __name__ diff --git a/mediagoblin/config.py b/mediagoblin/init/config.py index 2f93d32c..2f93d32c 100644 --- a/mediagoblin/config.py +++ b/mediagoblin/init/config.py diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 0dce1418..0d1abcb3 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -22,6 +22,7 @@ from mediagoblin import mg_globals as mgg THUMB_SIZE = 200, 200 +MEDIUM_SIZE = 640, 640 def create_pub_filepath(entry, filename): @@ -43,20 +44,32 @@ def process_media_initial(media_id): mgg.queue_store, queued_filepath, 'source') - queued_file = file(queued_filename, 'r') + thumb = Image.open(queued_filename) + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) + # ensure color mode is compatible with jpg + if thumb.mode != "RGB": + thumb = thumb.convert("RGB") - with queued_file: - thumb = Image.open(queued_file) - thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) - # ensure color mode is compatible with jpg - if thumb.mode != "RGB": - thumb = thumb.convert("RGB") + thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') + + thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') + with thumb_file: + thumb.save(thumb_file, "JPEG") + + """ + Create medium file, used in `media.html` + """ + medium = Image.open(queued_filename) + medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS) + + if medium.mode != "RGB": + medium = medium.convert("RGB") - thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') + medium_filepath = create_pub_filepath(entry, 'medium.jpg') - thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - with thumb_file: - thumb.save(thumb_file, "JPEG") + medium_file = mgg.public_store.get_file(medium_filepath, 'w') + with medium_file: + medium.save(medium_file, "JPEG") # we have to re-read because unlike PIL, not everything reads # things in string representation :) @@ -73,6 +86,7 @@ def process_media_initial(media_id): media_files_dict = entry.setdefault('media_files', {}) media_files_dict['thumb'] = thumb_filepath media_files_dict['main'] = main_filepath + media_files_dict['medium'] = medium_filepath entry['state'] = u'processed' entry.save() diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 31573820..3b2a9a50 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -133,15 +133,6 @@ a.mediagoblin_logo:hover { /* common website elements */ -.dotted_line { - width:100%; - height:0px; - border-bottom: dotted 1px #5f5f5f; - position:absolute; - left:0px; - margin-top:-20px; -} - .button { font-family:'Carter One', arial, serif; height:32px; @@ -164,6 +155,10 @@ a.mediagoblin_logo:hover { padding-right:11px; } +.pagination{ +text-align:center; +} + /* forms */ .form_box { @@ -223,6 +218,17 @@ a.mediagoblin_logo:hover { width:280px; } +/* comments */ + +.comment_author { + margin-bottom:40px; + padding-top:4px; +} + +.comment_content p { + margin-bottom:4px; +} + /* media galleries */ ul.media_thumbnail { @@ -240,3 +246,10 @@ li.media_thumbnail { zoom:1; . *display:inline; } + +/* icons */ + +img.media_icon{ + margin:0 4px; + vertical-align:sub; +} diff --git a/mediagoblin/static/images/icon_delete.png b/mediagoblin/static/images/icon_delete.png Binary files differnew file mode 100644 index 00000000..9d76a5db --- /dev/null +++ b/mediagoblin/static/images/icon_delete.png diff --git a/mediagoblin/static/images/icon_edit.png b/mediagoblin/static/images/icon_edit.png Binary files differnew file mode 100644 index 00000000..480c73ad --- /dev/null +++ b/mediagoblin/static/images/icon_edit.png diff --git a/mediagoblin/static/images/icon_feed.png b/mediagoblin/static/images/icon_feed.png Binary files differnew file mode 100644 index 00000000..11e5b1e7 --- /dev/null +++ b/mediagoblin/static/images/icon_feed.png diff --git a/mediagoblin/templates/mediagoblin/edit/edit_profile.html b/mediagoblin/templates/mediagoblin/edit/edit_profile.html index 7efd0ee3..cf228977 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_profile.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_profile.html @@ -21,8 +21,8 @@ {% block mediagoblin_content %} - <form action="{{ request.urlgen('mediagoblin.edit.profile', - user=user.username) }}" + <form action="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ + user['username'] }}" method="POST" enctype="multipart/form-data"> <div class="grid_6 prefix_1 suffix_1 edit_box form_box"> <h1>Editing {{ user['username'] }}'s profile</h1> diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index e29abd51..5b744999 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -23,7 +23,6 @@ {% if request.user %} <p> <a href="{{ request.urlgen('mediagoblin.submit.start') }}">Submit an item</a> - <a href="{{ request.urlgen('mediagoblin.edit.profile') }}">Edit profile</a> </p> {% else %} <p> diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 3cebe2f9..ca2ec5d6 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -18,86 +18,100 @@ {% extends "mediagoblin/base.html" %} {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} +{% from "mediagoblin/utils/pagination.html" import render_pagination %} {% block mediagoblin_content %} - {# temporarily, an "image gallery" that isn't one really ;) #} {% if media %} <div class="grid_8 alpha media_image"> - <h1> + {% if media.media_files.medium %} + <img src="{{ request.app.public_store.file_url( + media.media_files.medium) }}" /> + {% else %} + <img src="{{ request.app.public_store.file_url( + media.media_files.main) }}" /> + {% endif %} + + <h2> {{media.title}} - </h1> - <img class="media_image" src="{{ request.app.public_store.file_url( - media.media_files.main) }}" /> + </h2> + + {% autoescape False %} + <p>{{ media.description_html }}</p> + {% endautoescape %} + <p> - Uploaded on + — uploaded on {{ "%4d-%02d-%02d"|format(media.created.year, media.created.month, media.created.day) }} by <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', user= media.uploader().username) }}"> {{- media.uploader().username }}</a> - </p> + </p> + <br /><br /> - {% autoescape False %} - <p>{{ media.description_html }}</p> - {% endautoescape %} - - {% if media['uploader'] == request.user['_id'] %} - <p><a href="{{ request.urlgen('mediagoblin.edit.edit_media', - user= media.uploader().username, - media= media._id) }}">Edit</a></p> - {% endif %} + <h3>Comments</h3> {% if request.user %} <form action="{{ request.urlgen('mediagoblin.user_pages.media_post_comment', user= media.uploader().username, media=media._id) }}" method="POST"> - <h3>Post a comment!</h3> {{ wtforms_util.render_field_div(comment_form.comment) }} <div class="form_submit_buttons"> - <input type="submit" value="Submit" class="button" /> + <input type="submit" value="Post comment!" class="button" /> </div> </form> {% endif %} - {# - {{ wtforms_util.render_textarea_div(submit_form.description) }} - {{ wtforms_util.render_field_div(submit_form.file) }} - #} - {% if comments %} - <h3>Comments</h3> {% for comment in comments %} + {% set comment_author = comment.author() %} <div class="comment_wrapper" id="comment-{{ comment['_id'] }}"> - <div class="comment_author">By: - <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', - user = comment['author']['username']) }}"> - {{ comment['author']['username'] }} - </a> - </div> - <div class="comment_datetime"> - <a href="#comment-{{ comment['_id'] }}"> - {{ "%4d-%02d-%02d %02d:%02d"|format(comment.created.year, - comment.created.month, - comment.created.day, - comment.created.hour, - comment.created.minute) }} - </a> - </div> <div class="comment_content"> {% autoescape False %} {{ comment.content_html }} {% endautoescape %} - </div> - </div> + </div> + <div class="comment_author">— + <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', + user = comment_author['username']) }}"> + {{ comment_author['username'] }}</a> at + <!--</div> + <div class="comment_datetime">--> + <a href="#comment-{{ comment['_id'] }}"> + {{ "%4d-%02d-%02d %02d:%02d"|format(comment.created.year, + comment.created.month, + comment.created.day, + comment.created.hour, + comment.created.minute) }} + </a> + </div> + </div> {% endfor %} - {% include "mediagoblin/utils/pagination.html" %} + + {{ render_pagination(request, pagination) }} </div> {% endif %} - <div class="grid_4 omega media_sidebar"> - <p>This is a sidebar! Yay!</p> + {% include "mediagoblin/utils/prev_next.html" %} + <h3>Sidebar content here!</h3> + <p> + {% if media['uploader'] == request.user['_id'] or + request.user['is_admin'] %} + <p> + <a href="{{ request.urlgen('mediagoblin.edit.edit_media', + user= media.uploader().username, + media= media._id) }}" + ><img src="{{ request.staticdirect('/images/icon_edit.png') }}" + class="media_icon" />edit</a> + </p> + <p> + <img src="{{ request.staticdirect('/images/icon_delete.png') }}" + class="media_icon" />delete + </p> + {% endif %} + </p> </div> {% else %} - <p>Sorry, no such media found.<p/> + <p>Sorry, no such media found.<p/> {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index 99e46a72..d23daccd 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -27,18 +27,21 @@ {% block mediagoblin_content -%} {% if user %} <h1>{{ user.username }}'s profile</h1> + {% if request.user == user.username or request.user['is_admin'] %} + <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ + user.username }}"> Edit</a> + {% endif %} {% include "mediagoblin/utils/profile.html" %} + {% set pagination_base_url = user_gallery_url %} {% include "mediagoblin/utils/object_gallery.html" %} - <p><a href="{{ request.urlgen('mediagoblin.user_pages.user_gallery', - user= request.user['username']) }}">View all of {{ user.username }}'s media</a></p> - + <p><a href="{{ user_gallery_url }}">View all of {{ user.username }}'s media</a></p> <a href={{ request.urlgen( 'mediagoblin.user_pages.atom_feed', - user=user.username) }}> atom feed</a> + user=user.username) }}>atom feed</a> {% else %} {# This *should* not occur as the view makes sure we pass in a user. #} <p>Sorry, no such user found.<p/> diff --git a/mediagoblin/templates/mediagoblin/utils/object_gallery.html b/mediagoblin/templates/mediagoblin/utils/object_gallery.html index 8c88c174..4e2886f8 100644 --- a/mediagoblin/templates/mediagoblin/utils/object_gallery.html +++ b/mediagoblin/templates/mediagoblin/utils/object_gallery.html @@ -16,6 +16,8 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. #} +{% from "mediagoblin/utils/pagination.html" import render_pagination %} + {% block object_gallery_content -%} <div> {% if media_entries %} @@ -28,8 +30,12 @@ </li> {% endfor %} </ul> - {% include "mediagoblin/utils/pagination.html" %} - {% endif %} - + {% if pagination_base_url %} + {# different url, so set that and don't keep the get params #} + {{ render_pagination(request, pagination, pagination_base_url, False) }} + {% else %} + {{ render_pagination(request, pagination) }} + {% endif %} + {% endif %} </div> {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index 2be0b92e..aae50d22 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -15,30 +15,48 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. #} -{# only display if {{pagination}} is defined #} +{% macro render_pagination(request, pagination, + base_url=None, preserve_get_params=True) %} + {# only display if {{pagination}} is defined #} + {% if pagination and pagination.pages > 1 %} + {% if not base_url %} + {% set base_url = request.path_info %} + {% endif %} -{% if pagination %} - <div class="pagination"> + {% if preserve_get_params %} + {% set get_params = request.GET %} + {% else %} + {% set get_params = {} %} + {% endif %} - {% if pagination.has_prev %} - <a href="{{ pagination.get_page_url(request, pagination.page-1) }}">« Prev</> - {% endif %} - - {%- for page in pagination.iter_pages() %} - {% if page %} - {% if page != pagination.page %} - <a href="{{ pagination.get_page_url(request, page) }}">{{ page }}</a> + <div class="pagination"> + <p> + {% if pagination.has_prev %} + <a href="{{ pagination.get_page_url_explicit( + base_url, get_params, + pagination.page - 1) }}">« Prev</a> + {% endif %} + + {%- for page in pagination.iter_pages() %} + {% if page %} + {% if page != pagination.page %} + <a href="{{ pagination.get_page_url_explicit( + base_url, get_params, + page) }}">{{ page }}</a> + {% else %} + {{ page }} + {% endif %} {% else %} - <strong>{{ page }}</strong> + <span class="ellipsis">…</span> {% endif %} - {% else %} - <span class="ellipsis">…</span> + {%- endfor %} + + {% if pagination.has_next %} + <a href="{{ pagination.get_page_url_explicit( + base_url, get_params, + pagination.page + 1) }}">Next »</a> {% endif %} - {%- endfor %} - - {% if pagination.has_next %} - <a href="{{ pagination.get_page_url(request, pagination.page + 1) }}">Next »</a> - {% endif %} - </div> -{% endif %} - + </p> + </div> + {% endif %} +{% endmacro %} diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html new file mode 100644 index 00000000..e054ed23 --- /dev/null +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -0,0 +1,45 @@ +{# +# 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/>. +#} + +{# Provide navigation links to neighboring media entries, if possible #} +{% set prev_entry_url = media.url_to_prev(request.urlgen) %} +{% set next_entry_url = media.url_to_next(request.urlgen) %} + +<div> + {# There are no previous entries for the very first media entry #} + {% if prev_entry_url %} + <a href="{{ prev_entry_url }}"> + {# TODO - insert 'Previous' and 'X' image sources #} + Previous + </a> + {% else %} + {# This is the first entry. display greyed-out 'previous' image #} + X + {% endif %} + + {# Likewise, this could be the very last media entry #} + {% if next_entry_url %} + <a href="{{ next_entry_url }}"> + {# TODO - insert 'Next' and 'X' image sources #} + Next + </a> + {% else %} + {# This is the last entry. display greyed-out 'next' image #} + X + {% endif %} +</div> diff --git a/mediagoblin/templates/mediagoblin/utils/profile.html b/mediagoblin/templates/mediagoblin/utils/profile.html index b3f5f0f8..21468033 100644 --- a/mediagoblin/templates/mediagoblin/utils/profile.html +++ b/mediagoblin/templates/mediagoblin/utils/profile.html @@ -20,16 +20,16 @@ <div> <ul> {% if user.url %} - <li> - <a href="{{ user.url }}">homepage</a> - </li> - {% endif %} + <li> + <a href="{{ user.url }}">homepage</a> + </li> + {% endif %} {% if user.bio %} - <li> - {{ user.bio }} - </li> - {% endif %} + <li> + {{ user.bio }} + </li> + {% endif %} </ul> </div> {% endblock %} diff --git a/mediagoblin/tests/test_celery_setup.py b/mediagoblin/tests/test_celery_setup.py index 8bf97ae4..b80cab49 100644 --- a/mediagoblin/tests/test_celery_setup.py +++ b/mediagoblin/tests/test_celery_setup.py @@ -16,8 +16,8 @@ import pkg_resources -from mediagoblin import celery_setup -from mediagoblin.config import read_mediagoblin_config +from mediagoblin.init import celery as celery_setup +from mediagoblin.init.config import read_mediagoblin_config TEST_CELERY_CONF_NOSPECIALDB = pkg_resources.resource_filename( diff --git a/mediagoblin/tests/test_config.py b/mediagoblin/tests/test_config.py index 244f05e5..f9f12072 100644 --- a/mediagoblin/tests/test_config.py +++ b/mediagoblin/tests/test_config.py @@ -16,7 +16,7 @@ import pkg_resources -from mediagoblin import config +from mediagoblin.init import config CARROT_CONF_GOOD = pkg_resources.resource_filename( diff --git a/mediagoblin/tests/test_mgoblin_app.ini b/mediagoblin/tests/test_mgoblin_app.ini index e022d47b..fd0f87a4 100644 --- a/mediagoblin/tests/test_mgoblin_app.ini +++ b/mediagoblin/tests/test_mgoblin_app.ini @@ -8,7 +8,7 @@ email_debug_mode = true db_name = __mediagoblin_tests__ # Celery shouldn't be set up by the application as it's setup via -# mediagoblin.celery_setup.from_celery +# mediagoblin.init.celery.from_celery celery_setup_elsewhere = true [celery] diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py index 64f773f0..e56af4de 100644 --- a/mediagoblin/tests/tools.py +++ b/mediagoblin/tests/tools.py @@ -22,7 +22,7 @@ from paste.deploy import loadapp from webtest import TestApp from mediagoblin import util -from mediagoblin.config import read_mediagoblin_config +from mediagoblin.init.config import read_mediagoblin_config from mediagoblin.decorators import _make_safe from mediagoblin.db.open import setup_connection_and_db_from_config @@ -42,8 +42,8 @@ USER_DEV_DIRECTORIES_TO_SETUP = [ BAD_CELERY_MESSAGE = """\ Sorry, you *absolutely* must run nosetests with the -mediagoblin.celery_setup.from_tests module. Like so: -$ CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_tests ./bin/nosetests""" +mediagoblin.init.celery.from_tests module. Like so: +$ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests""" class BadCeleryEnviron(Exception): pass @@ -51,7 +51,7 @@ class BadCeleryEnviron(Exception): pass def suicide_if_bad_celery_environ(): if not os.environ.get('CELERY_CONFIG_MODULE') == \ - 'mediagoblin.celery_setup.from_tests': + 'mediagoblin.init.celery.from_tests': raise BadCeleryEnviron(BAD_CELERY_MESSAGE) @@ -59,7 +59,7 @@ def get_test_app(dump_old_app=True): suicide_if_bad_celery_environ() # Leave this imported as it sets up celery. - from mediagoblin.celery_setup import from_tests + from mediagoblin.init.celery import from_tests global MGOBLIN_APP diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 399d2020..3a8684d3 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -48,10 +48,15 @@ def user_home(request, page): if media_entries == None: return exc.HTTPNotFound() + user_gallery_url = request.urlgen( + 'mediagoblin.user_pages.user_gallery', + user=user['username']) + return render_to_response( request, 'mediagoblin/user_pages/user.html', {'user': user, + 'user_gallery_url': user_gallery_url, 'media_entries': media_entries, 'pagination': pagination}) @@ -82,17 +87,19 @@ def user_gallery(request, page): 'media_entries': media_entries, 'pagination': pagination}) +MEDIA_COMMENTS_PER_PAGE = 50 @get_user_media_entry @uses_pagination -def media_home(request, media, **kwargs): +def media_home(request, media, page, **kwargs): """ 'Homepage' of a MediaEntry() """ - comment_form = user_forms.MediaCommentForm(request.POST) + pagination = Pagination(page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE) + comments = pagination() - (comments, pagination) = media.get_comments(kwargs.get('page')) + comment_form = user_forms.MediaCommentForm(request.POST) return render_to_response( request, diff --git a/mediagoblin/util.py b/mediagoblin/util.py index a20e87c4..ab219df0 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -64,22 +64,6 @@ def clear_test_buckets(): clear_test_template_context() -def get_jinja_loader(user_template_path=None): - """ - Set up the Jinja template loaders, possibly allowing for user - overridden templates. - - (In the future we may have another system for providing theming; - for now this is good enough.) - """ - if user_template_path: - return jinja2.ChoiceLoader( - [jinja2.FileSystemLoader(user_template_path), - jinja2.PackageLoader('mediagoblin', 'templates')]) - else: - return jinja2.PackageLoader('mediagoblin', 'templates') - - SETUP_JINJA_ENVS = {} diff --git a/runtests.sh b/runtests.sh index 9b96b17c..1dfbf093 100755 --- a/runtests.sh +++ b/runtests.sh @@ -27,4 +27,4 @@ else exit 1 fi -CELERY_CONFIG_MODULE=mediagoblin.celery_setup.from_tests $NOSETESTS $@ +CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests $NOSETESTS $@ |