diff options
39 files changed, 322 insertions, 231 deletions
diff --git a/docs/conf.py b/docs/conf.py index 0e75a617..6c64cdda 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ copyright = u'2011, Free Software Foundation, Inc and contributors' # built documents. # # The short X.Y version. -version = '0.0.2' +version = '0.0.3' # The full version, including alpha/beta/rc tags. -release = '0.0.2' +release = '0.0.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/hackinghowto.rst b/docs/hackinghowto.rst index 08b228f1..914a5135 100644 --- a/docs/hackinghowto.rst +++ b/docs/hackinghowto.rst @@ -57,6 +57,11 @@ requirements:: sudo apt-get install mongodb git-core python python-dev \ python-lxml +On Fedora:: + + yum install mongodb-server python-paste-deploy python-paste-script \ + git-core python python-devel + .. YouCanHelp:: If you have instructions for other GNU/Linux distributions to set diff --git a/maketarball.sh b/maketarball.sh new file mode 100755 index 00000000..2ee78016 --- /dev/null +++ b/maketarball.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# usage: maketarball +# maketarball <tag> +# +# With no arguments, this creates a source tarball from git master with a +# filename based on today's date. +# +# With a <tag> argument, this creates a tarball of the tag. +# +# Examples: +# +# ./maketarball +# ./maketarball v0.0.2 + +NOWDATE=`date "+%Y-%m-%d"` + +if [ -z "$1" ] +then + REVISH=master + PREFIX="$NOWDATE-$REVISH" +else + REVISH=$1 + PREFIX="$REVISH" +fi + +# convert PREFIX to all lowercase. +# nix the v from tag names. +PREFIX=`echo "$PREFIX" | tr '[A-Z]' '[a-z]' | sed s/v//` + +echo "== REVISH $REVISH" +echo "== PREFIX $PREFIX" + +echo "" + +echo "generating archive...." +git archive \ + --format=tar \ + --prefix=mediagoblin-$PREFIX/ \ + $REVISH > mediagoblin-$PREFIX.tar + +if [[ $? -ne 0 ]] +then + echo "git archive command failed. See above text for reason." + if [[ -e mediagoblin-$PREFIX.tar ]] + then + rm mediagoblin-$PREFIX.tar + fi + exit 1; +fi + +echo "compressing...." +gzip mediagoblin-$PREFIX.tar + +echo "archive at mediagoblin-$PREFIX.tar.gz" + +echo "done."
\ No newline at end of file diff --git a/mediagoblin.ini b/mediagoblin.ini index 596107dc..e889646a 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -8,6 +8,9 @@ email_sender_address = "notice@mediagoblin.example.org" # set to false to enable sending notices email_debug_mode = true +# Set to false to disable registrations +allow_registration = true + ## Uncomment this to put some user-overriding templates here #local_templates = %(here)s/user_dev/templates/ diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index 1d00f382..7fe507b1 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -18,6 +18,8 @@ import uuid from webob import exc +from mediagoblin import messages +from mediagoblin import mg_globals from mediagoblin.util import render_to_response, redirect from mediagoblin.db.util import ObjectId from mediagoblin.auth import lib as auth_lib @@ -29,6 +31,14 @@ def register(request): """ Your classic registration view! """ + # Redirects to indexpage if registrations are disabled + if not mg_globals.app_config["allow_registration"]: + messages.add_message( + request, + messages.WARNING, + ('Sorry, registration is disabled on this instance.')) + return redirect(request, "index") + register_form = auth_forms.RegistrationForm(request.POST) if request.method == 'POST' and register_form.validate(): @@ -51,7 +61,7 @@ def register(request): entry['pw_hash'] = auth_lib.bcrypt_gen_password_hash( request.POST['password']) entry.save(validate=True) - + send_verification_email(entry, request) return redirect(request, "mediagoblin.auth.register_success") @@ -97,13 +107,14 @@ def login(request): 'mediagoblin/auth/login.html', {'login_form': login_form, 'next': request.GET.get('next') or request.POST.get('next'), - 'login_failed': login_failed}) + 'login_failed': login_failed, + 'allow_registration': mg_globals.app_config["allow_registration"]}) def logout(request): # Maybe deleting the user_id parameter would be enough? request.session.delete() - + return redirect(request, "index") @@ -124,16 +135,24 @@ def verify_email(request): if user and user['verification_key'] == unicode(request.GET['token']): user['status'] = u'active' user['email_verified'] = True - verification_successful = True user.save() + verification_successful = True + messages.add_message( + request, + messages.SUCCESS, + ('Your email address has been verified. ' + 'You may now login, edit your profile, and submit images!')) else: verification_successful = False - + messages.add_message(request, + messages.ERROR, + 'The verification key or user id is incorrect') + return render_to_response( request, - 'mediagoblin/auth/verify_email.html', + 'mediagoblin/user_pages/user.html', {'user': user, - 'verification_successful': verification_successful}) + 'verification_successful' : verification_successful}) def resend_activation(request): diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index aadf5c21..b6356b0e 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -21,6 +21,9 @@ direct_remote_path = string(default="/mgoblin_static/") email_debug_mode = boolean(default=True) email_sender_address = string(default="notice@mediagoblin.example.org") +# Set to false to disable registrations +allow_registration = boolean(default=True) + # By default not set, but you might want something like: # "%(here)s/user_dev/templates/" local_templates = string() @@ -73,4 +76,4 @@ celeryd_eta_scheduler_precision = float() # known lists celery_routes = string_list() -celery_imports = string_list()
\ No newline at end of file +celery_imports = string_list() diff --git a/mediagoblin/db/indexes.py b/mediagoblin/db/indexes.py index d379a52b..a832e013 100644 --- a/mediagoblin/db/indexes.py +++ b/mediagoblin/db/indexes.py @@ -45,11 +45,13 @@ REQUIRED READING: To remove deprecated indexes ---------------------------- -Removing deprecated indexes is easier, just do: +Removing deprecated indexes is the same, just move the index into the +deprecated indexes mapping. -INACTIVE_INDEXES = { - 'collection_name': [ - 'deprecated_index_identifier1', 'deprecated_index_identifier2']} +DEPRECATED_INDEXES = { + 'collection_name': { + 'deprecated_index_identifier1': { + 'index': [index_foo_goes_here]}} ... etc. diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py index 8aa35ca9..279cb9f2 100644 --- a/mediagoblin/db/models.py +++ b/mediagoblin/db/models.py @@ -147,31 +147,33 @@ class MediaEntry(Document): """ 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) - + cursor = self.db.MediaEntry.find({'_id' : {"$gt": self['_id']}, + 'uploader': self['uploader'], + 'state': 'processed'}).sort( + '_id', ASCENDING).limit(1) if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', user=self.uploader()['username'], - media=unicode(cursor[0]['_id'])) + media=unicode(cursor[0]['slug'])) 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) + cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']}, + 'uploader': self['uploader'], + 'state': 'processed'}).sort( + '_id', DESCENDING).limit(1) if cursor.count(): return urlgen('mediagoblin.user_pages.media_home', user=self.uploader()['username'], - media=unicode(cursor[0]['_id'])) + media=unicode(cursor[0]['slug'])) def uploader(self): return self.db.User.find_one({'_id': self['uploader']}) + class MediaComment(Document): __collection__ = 'media_comments' diff --git a/mediagoblin/db/util.py b/mediagoblin/db/util.py index 70c37945..37e6586f 100644 --- a/mediagoblin/db/util.py +++ b/mediagoblin/db/util.py @@ -81,18 +81,25 @@ def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES): Args: - database: pymongo or mongokit database instance. - deprecated_indexes: the indexes to deprecate in the pattern of: - {'collection': ['index_identifier1', 'index_identifier2']} + {'collection_name': { + 'identifier': { + 'index': [index_foo_goes_here], + 'unique': True}} + + (... although we really only need the 'identifier' here, as the + rest of the information isn't used in this case. But it's kept + around so we can remember what it was) Returns: A list of indexes removed in form ('collection', 'index_name') """ indexes_removed = [] - for collection_name, index_names in deprecated_indexes.iteritems(): + for collection_name, indexes in deprecated_indexes.iteritems(): collection = database[collection_name] collection_indexes = collection.index_information().keys() - for index_name in index_names: + for index_name, index_data in indexes.iteritems(): if index_name in collection_indexes: collection.drop_index(index_name) diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index d5e7f0a9..0ed52af1 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -23,7 +23,8 @@ class EditForm(wtforms.Form): 'Title', [wtforms.validators.Length(min=0, max=500)]) slug = wtforms.TextField( - 'Slug') + 'Slug', + [wtforms.validators.Required(message="The slug can't be empty")]) description = wtforms.TextAreaField('Description of this work') class EditProfileForm(wtforms.Form): diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index e064a9c3..3bcf788b 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -106,9 +106,9 @@ def edit_profile(request): messages.add_message(request, messages.SUCCESS, 'Profile edited!') - return redirect(request, - "mediagoblin.edit.profile", - username=edit_username) + return redirect(request, + 'mediagoblin.user_pages.user_home', + user=edit_username) return render_to_response( request, diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py index 27f72b65..da3e887e 100644 --- a/mediagoblin/process_media/__init__.py +++ b/mediagoblin/process_media/__init__.py @@ -54,7 +54,7 @@ def process_media_initial(media_id): thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') with thumb_file: - thumb.save(thumb_file, "JPEG") + thumb.save(thumb_file, "JPEG", quality=90) """ Create medium file, used in `media.html` @@ -69,7 +69,7 @@ def process_media_initial(media_id): medium_file = mgg.public_store.get_file(medium_filepath, 'w') with medium_file: - medium.save(medium_file, "JPEG") + medium.save(medium_file, "JPEG", quality=90) # we have to re-read because unlike PIL, not everything reads # things in string representation :) diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css index 10dbc98b..31b8ebc2 100644 --- a/mediagoblin/static/css/base.css +++ b/mediagoblin/static/css/base.css @@ -1,6 +1,6 @@ body { - background-color: #272727; - color: #f7f7f7; + background-color: #1F1F1F; + color: #aaa; font-family: sans-serif; padding:none; margin:0px; @@ -18,28 +18,23 @@ form { font-family: 'Carter One'; font-style: normal; font-weight: normal; - src: local('CarterOne'), url('http://themes.googleusercontent.com/font?kit=VjW2qt1pkqVtO22ObxgEBRsxEYwM7FgeyaSgU71cLG0') format('woff'); + src: local('CarterOne'), url('http://themes.googleusercontent.com/font?kit=FWNn6ITYqL6or7ZTmBxRhq3fkYX5z1QtDUdIWoaaD_k') format('woff'); } /* text styles */ h1{ font-family: 'Carter One', arial, serif; - margin-bottom: 20px; - margin-top:40px; + margin-bottom: 15px; + margin-top:15px; } h2{ margin-top:20px; } -p { - font-family: sans-serif; - font-size:16px; -} - a { - color: #86D4B1; + color: #fff; } label { @@ -56,15 +51,33 @@ label { .mediagoblin_header { width:100%; height:36px; - background-color:#393939; + background-color:#2F2F2F; padding-top:14px; margin-bottom:40px; } +.header_submit{ + color:#272727; + background-color:#aaa; + background-image: -webkit-gradient(linear, left top, left bottom, from(##D2D2D2), to(#aaa)); + background-image: -webkit-linear-gradient(top, #D2D2D2, #aaa); + background-image: -moz-linear-gradient(top, #D2D2D2, #aaa); + background-image: -ms-linear-gradient(top, #D2D2D2, #aaa); + background-image: -o-linear-gradient(top, #D2D2D2, #aaa); + background-image: linear-gradient(top, #D2D2D2, #aaa); + box-shadow:0px 0px 4px #000; + border-radius:5px 5px 5px 5px; + margin:8px; + padding:3px 8px; + text-decoration:none; + border:medium none; + font-family:'Carter One',arial,serif; +} + .mediagoblin_footer { width:100%; - height:26px; - background-color:#393939; + height:30px; + background-color:#2F2F2F; bottom:0px; padding-top:8px; position:absolute; @@ -77,19 +90,6 @@ label { padding-bottom:74px; } -a.mediagoblin_logo { - width:34px; - height:25px; - margin-right:10px; - background-image:url('../images/icon.png'); - background-position:0px 0px; - display:inline-block; -} - -a.mediagoblin_logo:hover { - background-position:0px -28px; -} - .mediagoblin_header_right { float:right; } @@ -122,6 +122,10 @@ a.mediagoblin_logo:hover { text-align:center; } +.pagination_arrow{ + margin:5px; +} + /* forms */ .form_box { @@ -130,7 +134,7 @@ text-align:center; background-repeat:repeat-x; font-size:18px; padding-bottom:30px; - padding-top:1px; + padding-top:30px; margin-left:auto; margin-right:auto; display:block; @@ -160,6 +164,7 @@ text-align:center; .form_field_error { background-color:#87453b; + color:#fff; border:none; font-size:16px; padding:9px; @@ -190,7 +195,7 @@ text-align:center; height:180px; overflow:hidden; float:left; - margin:0px 10px 10px 0px; + margin:0px 4px 10px 4px; text-align:center; } @@ -204,14 +209,14 @@ img.media_icon{ /* navigation */ .navigation_button{ - width: 139px; + width:139px; display:block; float:left; - text-align: center; - background-color: #393939; - text-decoration: none; - padding: 6px 0pt; - font-family: 'Carter One', arial, serif; + text-align:center; + background-color:#393939; + text-decoration:none; + padding:12px 0pt; + font-family:'Carter One', arial, serif; font-size:2em; margin:0 0 20px } @@ -257,10 +262,3 @@ ul.mediagoblin_messages { background-color: #f7f7f7; color:#272727; } - -/* profile stuff */ - -.profile_content p, .profile_bio { - padding: 6px; - background-color: #393939; -} diff --git a/mediagoblin/static/images/icon.png b/mediagoblin/static/images/icon.png Binary files differdeleted file mode 100644 index 4f4f3e9c..00000000 --- a/mediagoblin/static/images/icon.png +++ /dev/null diff --git a/mediagoblin/static/images/logo.png b/mediagoblin/static/images/logo.png Binary files differnew file mode 100644 index 00000000..cf28a6d4 --- /dev/null +++ b/mediagoblin/static/images/logo.png diff --git a/mediagoblin/static/images/navigation_end.png b/mediagoblin/static/images/navigation_end.png Binary files differnew file mode 100644 index 00000000..b2f27296 --- /dev/null +++ b/mediagoblin/static/images/navigation_end.png diff --git a/mediagoblin/static/images/navigation_left.png b/mediagoblin/static/images/navigation_left.png Binary files differnew file mode 100644 index 00000000..d1645120 --- /dev/null +++ b/mediagoblin/static/images/navigation_left.png diff --git a/mediagoblin/static/images/navigation_right.png b/mediagoblin/static/images/navigation_right.png Binary files differnew file mode 100644 index 00000000..d4caa7b8 --- /dev/null +++ b/mediagoblin/static/images/navigation_right.png diff --git a/mediagoblin/static/images/pagination_left.png b/mediagoblin/static/images/pagination_left.png Binary files differnew file mode 100644 index 00000000..56a26596 --- /dev/null +++ b/mediagoblin/static/images/pagination_left.png diff --git a/mediagoblin/static/images/pagination_right.png b/mediagoblin/static/images/pagination_right.png Binary files differnew file mode 100644 index 00000000..84f8abba --- /dev/null +++ b/mediagoblin/static/images/pagination_right.png diff --git a/mediagoblin/submit/routing.py b/mediagoblin/submit/routing.py index 3edbab70..5585ecb0 100644 --- a/mediagoblin/submit/routing.py +++ b/mediagoblin/submit/routing.py @@ -18,7 +18,4 @@ from routes.route import Route submit_routes = [ Route('mediagoblin.submit.start', '/', - controller='mediagoblin.submit.views:submit_start'), - Route('mediagoblin.submit.success', '/success/', - template='mediagoblin/submit/success.html', - controller='mediagoblin.views:simple_template_render')] + controller='mediagoblin.submit.views:submit_start')] diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py index 4c7476b0..1848f5e5 100644 --- a/mediagoblin/submit/views.py +++ b/mediagoblin/submit/views.py @@ -95,8 +95,3 @@ def submit_start(request): request, 'mediagoblin/submit/start.html', {'submit_form': submit_form}) - - -def submit_success(request): - return render_to_response( - request, 'mediagoblin/submit/success.html', {}) diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 2303ce5c..e25783ea 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -35,7 +35,9 @@ <input type="hidden" name="next" value="{{ next }}" class="button" style="display: none;"/> {% endif %} - <p>Don't have an account yet?<br /><a href="{{ request.urlgen('mediagoblin.auth.register') }}">Create one here!</a></p> + {% if allow_registration %} + <p>Don't have an account yet?<br /><a href="{{ request.urlgen('mediagoblin.auth.register') }}">Create one here!</a></p> + {% endif %} </div> </form> {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/verify_email.html b/mediagoblin/templates/mediagoblin/auth/verify_email.html deleted file mode 100644 index b6e6d1f8..00000000 --- a/mediagoblin/templates/mediagoblin/auth/verify_email.html +++ /dev/null @@ -1,28 +0,0 @@ -{# -# 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" %} - -{% block mediagoblin_content %} -<p> - {% if verification_successful %} - Your email address has been verified! - {% else %} - The verification key or user id is incorrect - {% endif %} -</p> -{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html index b71fca24..40bb085e 100644 --- a/mediagoblin/templates/mediagoblin/base.html +++ b/mediagoblin/templates/mediagoblin/base.html @@ -38,8 +38,12 @@ <div class="container_16"> <div class="grid_16"> {% block mediagoblin_logo %} - <a class="mediagoblin_logo" href="{{ request.urlgen('index') }}"></a> - {% endblock %}{% block mediagoblin_header_title %}{% endblock %} + <a class="mediagoblin_logo" href="{{ request.urlgen('index') }}"><img src="{{ request.staticdirect('/images/logo.png') }}" alt="Mediagoblin logo" /></a> + {% endblock %} + {% if request.user %} + <a class="header_submit" href="{{ request.urlgen('mediagoblin.submit.start') }}">Submit media</a> + {% endif %} + {% block mediagoblin_header_title %}{% endblock %} <div class="mediagoblin_header_right"> {% if request.user %} <a href="{{ request.urlgen('mediagoblin.user_pages.user_home', diff --git a/mediagoblin/templates/mediagoblin/root.html b/mediagoblin/templates/mediagoblin/root.html index 5b744999..bae033c4 100644 --- a/mediagoblin/templates/mediagoblin/root.html +++ b/mediagoblin/templates/mediagoblin/root.html @@ -29,10 +29,12 @@ If you have an account, you can <a href="{{ request.urlgen('mediagoblin.auth.login') }}">Login</a>. </p> - <p> - If you don't have an account, please - <a href="{{ request.urlgen('mediagoblin.auth.register') }}">Register</a>. - </p> + {% if allow_registration %} + <p> + If you don't have an account, please + <a href="{{ request.urlgen('mediagoblin.auth.register') }}">Register</a>. + </p> + {% endif %} {% endif %} {# temporarily, an "image gallery" that isn't one really ;) #} diff --git a/mediagoblin/templates/mediagoblin/submit/success.html b/mediagoblin/templates/mediagoblin/submit/success.html deleted file mode 100644 index afc9f9d1..00000000 --- a/mediagoblin/templates/mediagoblin/submit/success.html +++ /dev/null @@ -1,22 +0,0 @@ -{# -# 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" %} - -{% block mediagoblin_content %} - Woohoo! Submitted! -{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html index 0383277b..3f4dce3b 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/media.html +++ b/mediagoblin/templates/mediagoblin/user_pages/media.html @@ -48,14 +48,14 @@ user= media.uploader().username) }}"> {{- media.uploader().username }}</a> </p> - <br /><br /> + <br /> <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"> - {{ wtforms_util.render_field_div(comment_form.comment) }} + {{ wtforms_util.render_field_div(comment_form.comment_content) }} <div class="form_submit_buttons"> <input type="submit" value="Post comment!" class="button" /> </div> @@ -65,7 +65,12 @@ {% if comments %} {% for comment in comments %} {% set comment_author = comment.author() %} - <div class="comment_wrapper" id="comment-{{ comment['_id'] }}"> + {% if pagination.active_id == comment._id %} + <div class="comment_wrapper comment_active" id="comment-{{ comment['_id'] }}"> + <a name="comment" id="comment"></a> + {% else %} + <div class="comment_wrapper" id="comment-{{ comment['_id'] }}"> + {% endif %} <div class="comment_content"> {% autoescape False %} {{ comment.content_html }} @@ -77,7 +82,10 @@ {{ comment_author['username'] }}</a> at <!--</div> <div class="comment_datetime">--> - <a href="#comment-{{ comment['_id'] }}"> + <a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment', + comment = comment['_id'], + user = media.uploader().username, + media = media._id) }}#comment"> {{ "%4d-%02d-%02d %02d:%02d"|format(comment.created.year, comment.created.month, comment.created.day, @@ -88,7 +96,10 @@ </div> {% endfor %} - {{ render_pagination(request, pagination) }} + {{ render_pagination(request, pagination, + request.urlgen('mediagoblin.user_pages.media_home', + user = media.uploader().username, + media = media._id)) }} </div> {% endif %} <div class="grid_5 omega"> diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html index aed330c8..9d99ac53 100644 --- a/mediagoblin/templates/mediagoblin/user_pages/user.html +++ b/mediagoblin/templates/mediagoblin/user_pages/user.html @@ -26,33 +26,25 @@ {% block mediagoblin_content -%} {% if user %} - <h1>{{ user.username }}'s profile</h1> - - {% include "mediagoblin/utils/profile.html" %} - - {% if request.user['_id'] == user['_id'] or request.user['is_admin'] %} - <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ - user.username }}">Edit profile</a> - {% endif %} - - {% if request.user['_id'] == user['_id'] %} - <p> - <a href="{{ request.urlgen('mediagoblin.submit.start') }}">Submit an item</a> - </p> - {% endif %} - - {% set pagination_base_url = user_gallery_url %} - {% include "mediagoblin/utils/object_gallery.html" %} - - <div class="clear"></div> - - <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> - {% else %} - {# This *should* not occur as the view makes sure we pass in a user. #} - <p>Sorry, no such user found.<p/> + <h1>{{ user.username }}'s profile</h1> + <div class="grid_6 alpha"> + {% include "mediagoblin/utils/profile.html" %} + {% if request.user['_id'] == user['_id'] or request.user['is_admin'] %} + <a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{ + user.username }}">Edit profile</a> + {% endif %} + </div> + <div class="grid_10 omega"> + {% set pagination_base_url = user_gallery_url %} + {% include "mediagoblin/utils/object_gallery.html" %} + <div class="clear"></div> + <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> + {% else %} + {# This *should* not occur as the view makes sure we pass in a user. #} + <p>Sorry, no such user found.<p/> + </div> {% endif %} {% endblock %} diff --git a/mediagoblin/templates/mediagoblin/utils/pagination.html b/mediagoblin/templates/mediagoblin/utils/pagination.html index aae50d22..23d49463 100644 --- a/mediagoblin/templates/mediagoblin/utils/pagination.html +++ b/mediagoblin/templates/mediagoblin/utils/pagination.html @@ -34,9 +34,16 @@ {% if pagination.has_prev %} <a href="{{ pagination.get_page_url_explicit( base_url, get_params, - pagination.page - 1) }}">« Prev</a> + pagination.page - 1) }}"><img class="pagination_arrow" src="/mgoblin_static/images/pagination_left.png" alt="Previous page" />Newer</a> {% endif %} - + {% if pagination.has_next %} + <a href="{{ pagination.get_page_url_explicit( + base_url, get_params, + pagination.page + 1) }}">Older<img class="pagination_arrow" src="/mgoblin_static/images/pagination_right.png" alt="Next page" /> + </a> + {% endif %} + <br /> + Go to page: {%- for page in pagination.iter_pages() %} {% if page %} {% if page != pagination.page %} @@ -50,12 +57,6 @@ <span class="ellipsis">…</span> {% endif %} {%- endfor %} - - {% if pagination.has_next %} - <a href="{{ pagination.get_page_url_explicit( - base_url, get_params, - pagination.page + 1) }}">Next »</a> - {% endif %} </p> </div> {% endif %} diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html index 8908c298..7cf8d2a4 100644 --- a/mediagoblin/templates/mediagoblin/utils/prev_next.html +++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html @@ -24,20 +24,23 @@ {# There are no previous entries for the very first media entry #} {% if prev_entry_url %} <a class="navigation_button navigation_left" href="{{ prev_entry_url }}"> - < + <img src="/mgoblin_static/images/navigation_left.png" alt="Previous image" /> </a> {% else %} {# This is the first entry. display greyed-out 'previous' image #} - <p class="navigation_button">X</p> + <p class="navigation_button navigation_left"> + <img src="/mgoblin_static/images/navigation_end.png" alt="No previous images" /> + </p> {% endif %} - {# Likewise, this could be the very last media entry #} {% if next_entry_url %} <a class="navigation_button" href="{{ next_entry_url }}"> - > + <img src="/mgoblin_static/images/navigation_right.png" alt="Next image" /> </a> {% else %} {# This is the last entry. display greyed-out 'next' image #} - <p class="navigation_button">X</p> + <p class="navigation_button"> + <img src="/mgoblin_static/images/navigation_end.png" alt="No following images" /> + </p> {% endif %} </div> diff --git a/mediagoblin/templates/mediagoblin/utils/profile.html b/mediagoblin/templates/mediagoblin/utils/profile.html index 72a285d2..f44defa5 100644 --- a/mediagoblin/templates/mediagoblin/utils/profile.html +++ b/mediagoblin/templates/mediagoblin/utils/profile.html @@ -17,17 +17,14 @@ #} {% block profile_content -%} - <div class="profile_content"> - {% if user.url %} - <p class="profile_homepage"> - <a href="{{ user.url }}">homepage</a> - </p> - {% endif %} - - {% if user.bio %} - <p class="profile_bio"> - {{ user.bio }} - </p> - {% endif %} - </div> -{% endblock %} + {% if user.bio %} + <p> + {{ user.bio }} + </p> + {% endif %} + {% if user.url %} + <p> + <a href="{{ user.url }}">{{ user.url }}</a> + </p> + {% endif %} +{% endblock %} diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 3a13cbb1..ad9dd35b 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -189,7 +189,7 @@ def test_register_views(test_app): "/auth/verify_email/?userid=%s&token=total_bs" % unicode( new_user['_id'])) context = util.TEMPLATE_TEST_CONTEXT[ - 'mediagoblin/auth/verify_email.html'] + 'mediagoblin/user_pages/user.html'] assert context['verification_successful'] == False new_user = mg_globals.database.User.find_one( {'username': 'happygirl'}) @@ -201,7 +201,7 @@ def test_register_views(test_app): util.clear_test_template_context() test_app.get("%s?%s" % (path, get_params)) context = util.TEMPLATE_TEST_CONTEXT[ - 'mediagoblin/auth/verify_email.html'] + 'mediagoblin/user_pages/user.html'] assert context['verification_successful'] == True new_user = mg_globals.database.User.find_one( {'username': 'happygirl'}) diff --git a/mediagoblin/user_pages/forms.py b/mediagoblin/user_pages/forms.py index 9f7d2fbd..8829b674 100644 --- a/mediagoblin/user_pages/forms.py +++ b/mediagoblin/user_pages/forms.py @@ -1,21 +1,22 @@ -# 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/>.
-
-import wtforms
-
-class MediaCommentForm(wtforms.Form):
- comment = wtforms.TextAreaField('Comment',
- [wtforms.validators.Required()])
\ No newline at end of file +# 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/>. + +import wtforms + +class MediaCommentForm(wtforms.Form): + comment_content = wtforms.TextAreaField( + 'Comment', + [wtforms.validators.Required()]) diff --git a/mediagoblin/user_pages/routing.py b/mediagoblin/user_pages/routing.py index 255b6f66..3be0617d 100644 --- a/mediagoblin/user_pages/routing.py +++ b/mediagoblin/user_pages/routing.py @@ -24,6 +24,9 @@ user_routes = [ Route('mediagoblin.user_pages.media_home', '/{user}/m/{media}/', requirements=dict(m_id="[0-9a-fA-F]{24}"), controller="mediagoblin.user_pages.views:media_home"), + Route('mediagoblin.user_pages.media_home.view_comment', + '/{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"), Route('mediagoblin.user_pages.atom_feed', '/{user}/atom/', diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 3a8684d3..a3172ebd 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -95,8 +95,14 @@ def media_home(request, media, page, **kwargs): """ 'Homepage' of a MediaEntry() """ + if ObjectId(request.matchdict.get('comment')): + pagination = Pagination( + page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE, + ObjectId(request.matchdict.get('comment'))) + else: + pagination = Pagination( + page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE) - pagination = Pagination(page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE) comments = pagination() comment_form = user_forms.MediaCommentForm(request.POST) @@ -118,7 +124,7 @@ def media_post_comment(request): comment = request.db.MediaComment() comment['media_entry'] = ObjectId(request.matchdict['media']) comment['author'] = request.user['_id'] - comment['content'] = request.POST['comment'] + comment['content'] = request.POST['comment_content'] comment['content_html'] = cleaned_markdown_conversion(comment['content']) diff --git a/mediagoblin/util.py b/mediagoblin/util.py index ab219df0..7b1e4a2a 100644 --- a/mediagoblin/util.py +++ b/mediagoblin/util.py @@ -14,6 +14,8 @@ # 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/>. +from __future__ import division + from email.MIMEText import MIMEText import gettext import pkg_resources @@ -21,7 +23,7 @@ import smtplib import sys import re import urllib -from math import ceil +from math import ceil, floor import copy from babel.localedata import exists @@ -35,6 +37,8 @@ from mediagoblin import mg_globals from mediagoblin import messages from mediagoblin.db.util import ObjectId +from itertools import izip, count + TESTS_ENABLED = False def _activate_testing(): """ @@ -133,7 +137,16 @@ def render_to_response(request, template, context): def redirect(request, *args, **kwargs): """Returns a HTTPFound(), takes a request and then urlgen params""" - return exc.HTTPFound(location=request.urlgen(*args, **kwargs)) + + querystring = None + if kwargs.get('querystring'): + querystring = kwargs.get('querystring') + del kwargs['querystring'] + + return exc.HTTPFound( + location=''.join([ + request.urlgen(*args, **kwargs), + querystring if querystring else ''])) def setup_user_in_request(request): @@ -418,7 +431,8 @@ class Pagination(object): get actual data slice through __call__(). """ - def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE): + def __init__(self, page, cursor, per_page=PAGINATION_DEFAULT_PER_PAGE, + jump_to_id=False): """ Initializes Pagination @@ -426,11 +440,25 @@ class Pagination(object): - page: requested page - per_page: number of objects per page - cursor: db cursor + - jump_to_id: ObjectId, sets the page to the page containing the object + with _id == jump_to_id. """ - self.page = page + self.page = page self.per_page = per_page self.cursor = cursor self.total_count = self.cursor.count() + self.active_id = None + + if jump_to_id: + cursor = copy.copy(self.cursor) + + for (doc, increment) in izip(cursor, count(0)): + if doc['_id'] == jump_to_id: + self.page = 1 + int(floor(increment / self.per_page)) + + self.active_id = jump_to_id + break + def __call__(self): """ diff --git a/mediagoblin/views.py b/mediagoblin/views.py index 5b6d9773..e7d9dbdd 100644 --- a/mediagoblin/views.py +++ b/mediagoblin/views.py @@ -14,6 +14,7 @@ # 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/>. +from mediagoblin import mg_globals from mediagoblin.util import render_to_response from mediagoblin.db.util import DESCENDING @@ -23,7 +24,8 @@ def root_view(request): return render_to_response( request, 'mediagoblin/root.html', - {'media_entries': media_entries}) + {'media_entries': media_entries, + 'allow_registration': mg_globals.app_config["allow_registration"]}) def simple_template_render(request): @@ -18,7 +18,7 @@ from setuptools import setup, find_packages setup( name = "mediagoblin", - version = "0.0.2", + version = "0.0.3", packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), zip_safe=False, # scripts and dependencies |