Merge branch 'master' into test_submission_views_365
@ -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
|
||||
|
@ -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/
|
||||
|
||||
|
@ -20,18 +20,12 @@ import urllib
|
||||
import routes
|
||||
from webob import Request, exc
|
||||
|
||||
from mediagoblin import routing, util, storage, staticdirect
|
||||
from mediagoblin.init.config import (
|
||||
read_mediagoblin_config, generate_validation_report)
|
||||
from mediagoblin import routing, util, storage
|
||||
from mediagoblin.db.open import setup_connection_and_db_from_config
|
||||
from mediagoblin.mg_globals import setup_globals
|
||||
from mediagoblin.init.celery import setup_celery_from_config
|
||||
from mediagoblin.init import get_jinja_loader
|
||||
from mediagoblin.workbench import WorkbenchManager
|
||||
|
||||
|
||||
class Error(Exception): pass
|
||||
class ImproperlyConfigured(Error): pass
|
||||
from mediagoblin.init import get_jinja_loader, get_staticdirector, \
|
||||
setup_global_and_app_config, setup_workbench
|
||||
|
||||
|
||||
class MediaGoblinApp(object):
|
||||
@ -55,13 +49,7 @@ class MediaGoblinApp(object):
|
||||
##############
|
||||
|
||||
# Open and setup the config
|
||||
global_config, validation_result = read_mediagoblin_config(config_path)
|
||||
app_config = global_config['mediagoblin']
|
||||
# report errors if necessary
|
||||
validation_report = generate_validation_report(
|
||||
global_config, validation_result)
|
||||
if validation_report:
|
||||
raise ImproperlyConfigured(validation_report)
|
||||
global_config, app_config = setup_global_and_app_config(config_path)
|
||||
|
||||
##########################################
|
||||
# Setup other connections / useful objects
|
||||
@ -85,19 +73,7 @@ class MediaGoblinApp(object):
|
||||
self.routing = routing.get_mapper()
|
||||
|
||||
# set up staticdirector tool
|
||||
if app_config.has_key('direct_remote_path'):
|
||||
self.staticdirector = staticdirect.RemoteStaticDirect(
|
||||
app_config['direct_remote_path'].strip())
|
||||
elif app_config.has_key('direct_remote_paths'):
|
||||
direct_remote_path_lines = app_config[
|
||||
'direct_remote_paths'].strip().splitlines()
|
||||
self.staticdirector = staticdirect.MultiRemoteStaticDirect(
|
||||
dict([line.strip().split(' ', 1)
|
||||
for line in direct_remote_path_lines]))
|
||||
else:
|
||||
raise ImproperlyConfigured(
|
||||
"One of direct_remote_path or "
|
||||
"direct_remote_paths must be provided")
|
||||
self.staticdirector = get_staticdirector(app_config)
|
||||
|
||||
# Setup celery, if appropriate
|
||||
if setup_celery and not app_config.get('celery_setup_elsewhere'):
|
||||
@ -117,9 +93,6 @@ class MediaGoblinApp(object):
|
||||
#######################################################
|
||||
|
||||
setup_globals(
|
||||
app_config=app_config,
|
||||
global_config=global_config,
|
||||
|
||||
# TODO: No need to set these two up as globals, we could
|
||||
# just read them out of mg_globals.app_config
|
||||
email_sender_address=app_config['email_sender_address'],
|
||||
@ -130,8 +103,11 @@ class MediaGoblinApp(object):
|
||||
db_connection=self.connection,
|
||||
database=self.db,
|
||||
public_store=self.public_store,
|
||||
queue_store=self.queue_store,
|
||||
workbench_manager=WorkbenchManager(app_config['workbench_path']))
|
||||
queue_store=self.queue_store)
|
||||
|
||||
# Workbench *currently* only used by celery, so this only
|
||||
# matters in always eager mode :)
|
||||
setup_workbench()
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
request = Request(environ)
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
celery_imports = string_list()
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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'
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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):
|
||||
@ -31,4 +32,5 @@ class EditProfileForm(wtforms.Form):
|
||||
[wtforms.validators.Length(min=0, max=500)])
|
||||
url = wtforms.TextField(
|
||||
'Website',
|
||||
[wtforms.validators.URL(message='Improperly formed URL')])
|
||||
[wtforms.validators.Optional(),
|
||||
wtforms.validators.URL(message='Improperly formed URL')])
|
||||
|
@ -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,
|
||||
|
@ -15,8 +15,33 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import jinja2
|
||||
from mediagoblin import staticdirect
|
||||
from mediagoblin.init.config import (
|
||||
read_mediagoblin_config, generate_validation_report)
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin.mg_globals import setup_globals
|
||||
from mediagoblin.workbench import WorkbenchManager
|
||||
|
||||
|
||||
class Error(Exception): pass
|
||||
class ImproperlyConfigured(Error): pass
|
||||
|
||||
|
||||
def setup_global_and_app_config(config_path):
|
||||
global_config, validation_result = read_mediagoblin_config(config_path)
|
||||
app_config = global_config['mediagoblin']
|
||||
# report errors if necessary
|
||||
validation_report = generate_validation_report(
|
||||
global_config, validation_result)
|
||||
if validation_report:
|
||||
raise ImproperlyConfigured(validation_report)
|
||||
|
||||
setup_globals(
|
||||
app_config=app_config,
|
||||
global_config=global_config)
|
||||
|
||||
return global_config, app_config
|
||||
|
||||
def get_jinja_loader(user_template_path=None):
|
||||
"""
|
||||
Set up the Jinja template loaders, possibly allowing for user
|
||||
@ -31,3 +56,27 @@ def get_jinja_loader(user_template_path=None):
|
||||
jinja2.PackageLoader('mediagoblin', 'templates')])
|
||||
else:
|
||||
return jinja2.PackageLoader('mediagoblin', 'templates')
|
||||
|
||||
|
||||
def get_staticdirector(app_config):
|
||||
if app_config.has_key('direct_remote_path'):
|
||||
return staticdirect.RemoteStaticDirect(
|
||||
app_config['direct_remote_path'].strip())
|
||||
elif app_config.has_key('direct_remote_paths'):
|
||||
direct_remote_path_lines = app_config[
|
||||
'direct_remote_paths'].strip().splitlines()
|
||||
return staticdirect.MultiRemoteStaticDirect(
|
||||
dict([line.strip().split(' ', 1)
|
||||
for line in direct_remote_path_lines]))
|
||||
else:
|
||||
raise ImproperlyConfigured(
|
||||
"One of direct_remote_path or "
|
||||
"direct_remote_paths must be provided")
|
||||
|
||||
|
||||
def setup_workbench():
|
||||
app_config = mg_globals.app_config
|
||||
|
||||
workbench_manager = WorkbenchManager(app_config['workbench_path'])
|
||||
|
||||
setup_globals(workbench_manager = workbench_manager)
|
||||
|
@ -1,6 +1,6 @@
|
||||
body {
|
||||
background-color: #272727;
|
||||
color: #f7f7f7;
|
||||
background-color: #1F1F1F;
|
||||
color: #aaa;
|
||||
font-family: sans-serif;
|
||||
padding:none;
|
||||
margin:0px;
|
||||
@ -18,7 +18,7 @@ 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 */
|
||||
@ -33,13 +33,8 @@ 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;
|
||||
@ -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,11 +262,3 @@ ul.mediagoblin_messages {
|
||||
background-color: #f7f7f7;
|
||||
color:#272727;
|
||||
}
|
||||
|
||||
/* profile stuff */
|
||||
|
||||
.profile_content {
|
||||
padding: 6px;
|
||||
background-color: #393939;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
BIN
mediagoblin/static/images/logo.png
Normal file
After Width: | Height: | Size: 839 B |
BIN
mediagoblin/static/images/navigation_end.png
Normal file
After Width: | Height: | Size: 718 B |
BIN
mediagoblin/static/images/navigation_left.png
Normal file
After Width: | Height: | Size: 406 B |
BIN
mediagoblin/static/images/navigation_right.png
Normal file
After Width: | Height: | Size: 383 B |
BIN
mediagoblin/static/images/pagination_left.png
Normal file
After Width: | Height: | Size: 252 B |
BIN
mediagoblin/static/images/pagination_right.png
Normal file
After Width: | Height: | Size: 249 B |
@ -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')]
|
||||
|
@ -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', {})
|
||||
|
@ -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 %}
|
||||
|
@ -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 %}
|
@ -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',
|
||||
|
@ -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 ;) #}
|
||||
|
@ -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 %}
|
@ -55,7 +55,7 @@
|
||||
<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">
|
||||
|
@ -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 %}
|
||||
|
@ -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 %}
|
||||
|
@ -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>
|
||||
|
@ -17,19 +17,14 @@
|
||||
#}
|
||||
|
||||
{% block profile_content -%}
|
||||
{% if user.url or user.bio %}
|
||||
<div class="profile_content">
|
||||
{% if user.url %}
|
||||
<div class="profile_homepage">
|
||||
<a href="{{ user.url }}">{{ user.url }}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if user.bio %}
|
||||
<div class="profile_bio">
|
||||
{{ user.bio }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if user.bio %}
|
||||
<p>
|
||||
{{ user.bio }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% if user.url %}
|
||||
<p>
|
||||
<a href="{{ user.url }}">{{ user.url }}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
@ -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'})
|
||||
|
@ -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()])
|
||||
# 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()])
|
||||
|
@ -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/',
|
||||
|
@ -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'])
|
||||
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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):
|
||||
|