Merge branch 'master' of gitorious.org:mediagoblin/mediagoblin
Conflicts: mediagoblin/templates/mediagoblin/user_pages/user.html
This commit is contained in:
commit
817066506d
@ -94,7 +94,7 @@ class MediaGoblinApp(object):
|
||||
# object.
|
||||
#######################################################
|
||||
|
||||
setup_globals(app = self)
|
||||
setup_globals(app=self)
|
||||
|
||||
# Workbench *currently* only used by celery, so this only
|
||||
# matters in always eager mode :)
|
||||
@ -104,7 +104,6 @@ class MediaGoblinApp(object):
|
||||
self.middleware = [common.import_component(m)(self)
|
||||
for m in middleware.ENABLED_MIDDLEWARE]
|
||||
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
request = Request(environ)
|
||||
|
||||
|
@ -59,9 +59,10 @@ class ForgotPassForm(wtforms.Form):
|
||||
'Username or email',
|
||||
[wtforms.validators.Required()])
|
||||
|
||||
def validate_username(form,field):
|
||||
if not (re.match(r'^\w+$',field.data) or
|
||||
re.match(r'^.+@[^.].*\.[a-z]{2,10}$',field.data, re.IGNORECASE)):
|
||||
def validate_username(form, field):
|
||||
if not (re.match(r'^\w+$', field.data) or
|
||||
re.match(r'^.+@[^.].*\.[a-z]{2,10}$', field.data,
|
||||
re.IGNORECASE)):
|
||||
raise wtforms.ValidationError(u'Incorrect input')
|
||||
|
||||
|
||||
@ -82,4 +83,3 @@ class ChangePassForm(wtforms.Form):
|
||||
token = wtforms.HiddenField(
|
||||
'',
|
||||
[wtforms.validators.Required()])
|
||||
|
||||
|
@ -94,6 +94,7 @@ EMAIL_VERIFICATION_TEMPLATE = (
|
||||
u"http://{host}{uri}?"
|
||||
u"userid={userid}&token={verification_key}")
|
||||
|
||||
|
||||
def send_verification_email(user, request):
|
||||
"""
|
||||
Send the verification email to users to activate their accounts.
|
||||
@ -108,7 +109,7 @@ def send_verification_email(user, request):
|
||||
'verification_url': EMAIL_VERIFICATION_TEMPLATE.format(
|
||||
host=request.host,
|
||||
uri=request.urlgen('mediagoblin.auth.verify_email'),
|
||||
userid=unicode(user['_id']),
|
||||
userid=unicode(user._id),
|
||||
verification_key=user['verification_key'])})
|
||||
|
||||
# TODO: There is no error handling in place
|
||||
@ -128,6 +129,7 @@ EMAIL_FP_VERIFICATION_TEMPLATE = (
|
||||
u"http://{host}{uri}?"
|
||||
u"userid={userid}&token={fp_verification_key}")
|
||||
|
||||
|
||||
def send_fp_verification_email(user, request):
|
||||
"""
|
||||
Send the verification email to users to change their password.
|
||||
@ -142,7 +144,7 @@ def send_fp_verification_email(user, request):
|
||||
'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format(
|
||||
host=request.host,
|
||||
uri=request.urlgen('mediagoblin.auth.verify_forgot_password'),
|
||||
userid=unicode(user['_id']),
|
||||
userid=unicode(user._id),
|
||||
fp_verification_key=user['fp_verification_key'])})
|
||||
|
||||
# TODO: There is no error handling in place
|
||||
@ -151,4 +153,3 @@ def send_fp_verification_email(user, request):
|
||||
[user['email']],
|
||||
'GNU MediaGoblin - Change forgotten password!',
|
||||
rendered_email)
|
||||
|
||||
|
@ -33,7 +33,8 @@ auth_routes = [
|
||||
controller='mediagoblin.views:simple_template_render'),
|
||||
Route('mediagoblin.auth.forgot_password', '/forgot_password/',
|
||||
controller='mediagoblin.auth.views:forgot_password'),
|
||||
Route('mediagoblin.auth.verify_forgot_password', '/forgot_password/verify/',
|
||||
Route('mediagoblin.auth.verify_forgot_password',
|
||||
'/forgot_password/verify/',
|
||||
controller='mediagoblin.auth.views:verify_forgot_password'),
|
||||
Route('mediagoblin.auth.fp_changed_success',
|
||||
'/forgot_password/changed_success/',
|
||||
|
@ -87,7 +87,7 @@ def register(request):
|
||||
user.save(validate=True)
|
||||
|
||||
# log the user in
|
||||
request.session['user_id'] = unicode(user['_id'])
|
||||
request.session['user_id'] = unicode(user._id)
|
||||
request.session.save()
|
||||
|
||||
# send verification email
|
||||
@ -122,7 +122,7 @@ def login(request):
|
||||
|
||||
if user and user.check_login(request.POST['password']):
|
||||
# set up login in session
|
||||
request.session['user_id'] = unicode(user['_id'])
|
||||
request.session['user_id'] = unicode(user._id)
|
||||
request.session.save()
|
||||
|
||||
if request.POST.get('next'):
|
||||
@ -160,7 +160,7 @@ def verify_email(request):
|
||||
you are lucky :)
|
||||
"""
|
||||
# If we don't have userid and token parameters, we can't do anything; 404
|
||||
if not request.GET.has_key('userid') or not request.GET.has_key('token'):
|
||||
if not 'userid' in request.GET or not 'token' in request.GET:
|
||||
return render_404(request)
|
||||
|
||||
user = request.db.User.find_one(
|
||||
@ -253,8 +253,7 @@ def forgot_password(request):
|
||||
request, 'mediagoblin.user_pages.user_home',
|
||||
user=user['username'])
|
||||
|
||||
|
||||
# do not reveal whether or not there is a matching user, just move along
|
||||
# do not reveal whether or not there is a matching user
|
||||
return redirect(request, 'mediagoblin.auth.fp_email_sent')
|
||||
|
||||
return render_to_response(
|
||||
@ -328,6 +327,6 @@ def _process_for_token(request):
|
||||
formdata = {
|
||||
'vars': formdata_vars,
|
||||
'has_userid_and_token':
|
||||
formdata_vars.has_key('userid') and formdata_vars.has_key('token')}
|
||||
'userid' in formdata_vars and 'token' in formdata_vars}
|
||||
|
||||
return formdata
|
||||
|
@ -23,7 +23,7 @@ Database Abstraction/Wrapper Layer
|
||||
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
|
||||
|
@ -93,8 +93,9 @@ MEDIAENTRY_INDEXES = {
|
||||
('created', DESCENDING)]},
|
||||
|
||||
'state_uploader_tags_created': {
|
||||
# Indexing on processed?, media uploader, associated tags, and timestamp
|
||||
# Used for showing media items matching a tag search, most recent first.
|
||||
# Indexing on processed?, media uploader, associated tags, and
|
||||
# timestamp Used for showing media items matching a tag
|
||||
# search, most recent first.
|
||||
'index': [('state', ASCENDING),
|
||||
('uploader', ASCENDING),
|
||||
('tags.slug', DESCENDING),
|
||||
|
@ -14,7 +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/>.
|
||||
|
||||
import datetime, uuid
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from mongokit import Document
|
||||
|
||||
@ -62,22 +63,23 @@ class User(Document):
|
||||
- bio_html: biography of the user converted to proper HTML.
|
||||
"""
|
||||
__collection__ = 'users'
|
||||
use_dot_notation = True
|
||||
|
||||
structure = {
|
||||
'username': unicode,
|
||||
'email': unicode,
|
||||
'created': datetime.datetime,
|
||||
'plugin_data': dict, # plugins can dump stuff here.
|
||||
'plugin_data': dict, # plugins can dump stuff here.
|
||||
'pw_hash': unicode,
|
||||
'email_verified': bool,
|
||||
'status': unicode,
|
||||
'verification_key': unicode,
|
||||
'is_admin': bool,
|
||||
'url' : unicode,
|
||||
'bio' : unicode, # May contain markdown
|
||||
'bio_html': unicode, # May contain plaintext, or HTML
|
||||
'fp_verification_key': unicode, # forgotten password verification key
|
||||
'fp_token_expire': datetime.datetime
|
||||
'url': unicode,
|
||||
'bio': unicode, # May contain markdown
|
||||
'bio_html': unicode, # May contain plaintext, or HTML
|
||||
'fp_verification_key': unicode, # forgotten password verification key
|
||||
'fp_token_expire': datetime.datetime,
|
||||
}
|
||||
|
||||
required_fields = ['username', 'created', 'pw_hash', 'email']
|
||||
@ -172,21 +174,22 @@ class MediaEntry(Document):
|
||||
critical to this piece of media but may be usefully relevant to people
|
||||
viewing the work. (currently unused.)
|
||||
|
||||
- fail_error: path to the exception raised
|
||||
- fail_metadata:
|
||||
- fail_error: path to the exception raised
|
||||
- fail_metadata:
|
||||
"""
|
||||
__collection__ = 'media_entries'
|
||||
use_dot_notation = True
|
||||
|
||||
structure = {
|
||||
'uploader': ObjectId,
|
||||
'title': unicode,
|
||||
'slug': unicode,
|
||||
'created': datetime.datetime,
|
||||
'description': unicode, # May contain markdown/up
|
||||
'description_html': unicode, # May contain plaintext, or HTML
|
||||
'description': unicode, # May contain markdown/up
|
||||
'description_html': unicode, # May contain plaintext, or HTML
|
||||
'media_type': unicode,
|
||||
'media_data': dict, # extra data relevant to this media_type
|
||||
'plugin_data': dict, # plugins can dump stuff here.
|
||||
'media_data': dict, # extra data relevant to this media_type
|
||||
'plugin_data': dict, # plugins can dump stuff here.
|
||||
'tags': [dict],
|
||||
'state': unicode,
|
||||
|
||||
@ -216,9 +219,10 @@ class MediaEntry(Document):
|
||||
|
||||
def get_comments(self):
|
||||
return self.db.MediaComment.find({
|
||||
'media_entry': self['_id']}).sort('created', DESCENDING)
|
||||
'media_entry': self._id}).sort('created', DESCENDING)
|
||||
|
||||
def get_display_media(self, media_map, fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER):
|
||||
def get_display_media(self, media_map,
|
||||
fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER):
|
||||
"""
|
||||
Find the best media for display.
|
||||
|
||||
@ -246,7 +250,7 @@ class MediaEntry(Document):
|
||||
{'slug': self['slug']})
|
||||
|
||||
if duplicate:
|
||||
self['slug'] = "%s-%s" % (self['_id'], self['slug'])
|
||||
self['slug'] = "%s-%s" % (self._id, self['slug'])
|
||||
|
||||
def url_for_self(self, urlgen):
|
||||
"""
|
||||
@ -265,13 +269,13 @@ class MediaEntry(Document):
|
||||
return urlgen(
|
||||
'mediagoblin.user_pages.media_home',
|
||||
user=uploader['username'],
|
||||
media=unicode(self['_id']))
|
||||
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' : {"$gt": self['_id']},
|
||||
cursor = self.db.MediaEntry.find({'_id': {"$gt": self._id},
|
||||
'uploader': self['uploader'],
|
||||
'state': 'processed'}).sort(
|
||||
'_id', ASCENDING).limit(1)
|
||||
@ -284,7 +288,7 @@ class MediaEntry(Document):
|
||||
"""
|
||||
Provide a url to the next entry from this user, if there is one
|
||||
"""
|
||||
cursor = self.db.MediaEntry.find({'_id' : {"$lt": self['_id']},
|
||||
cursor = self.db.MediaEntry.find({'_id': {"$lt": self._id},
|
||||
'uploader': self['uploader'],
|
||||
'state': 'processed'}).sort(
|
||||
'_id', DESCENDING).limit(1)
|
||||
@ -319,6 +323,7 @@ class MediaComment(Document):
|
||||
"""
|
||||
|
||||
__collection__ = 'media_comments'
|
||||
use_dot_notation = True
|
||||
|
||||
structure = {
|
||||
'media_entry': ObjectId,
|
||||
@ -351,4 +356,3 @@ def register_models(connection):
|
||||
Register all models in REGISTER_MODELS with this connection.
|
||||
"""
|
||||
connection.register(REGISTER_MODELS)
|
||||
|
||||
|
@ -29,7 +29,7 @@ def connect_database_from_config(app_config, use_pymongo=False):
|
||||
port = app_config.get('db_port')
|
||||
if port:
|
||||
port = asint(port)
|
||||
|
||||
|
||||
if use_pymongo:
|
||||
connection = pymongo.Connection(
|
||||
app_config.get('db_host'), port)
|
||||
|
@ -118,11 +118,12 @@ def remove_deprecated_indexes(database, deprecated_indexes=DEPRECATED_INDEXES):
|
||||
#################
|
||||
|
||||
# The default migration registry...
|
||||
#
|
||||
#
|
||||
# Don't set this yourself! RegisterMigration will automatically fill
|
||||
# this with stuff via decorating methods in migrations.py
|
||||
|
||||
class MissingCurrentMigration(Exception): pass
|
||||
class MissingCurrentMigration(Exception):
|
||||
pass
|
||||
|
||||
|
||||
MIGRATIONS = {}
|
||||
@ -147,7 +148,7 @@ class RegisterMigration(object):
|
||||
"""
|
||||
def __init__(self, migration_number, migration_registry=MIGRATIONS):
|
||||
assert migration_number > 0, "Migration number must be > 0!"
|
||||
assert not migration_registry.has_key(migration_number), \
|
||||
assert migration_number not in migration_registry, \
|
||||
"Duplicate migration numbers detected! That's not allowed!"
|
||||
|
||||
self.migration_number = migration_number
|
||||
|
@ -60,7 +60,7 @@ def user_may_delete_media(controller):
|
||||
uploader = request.db.MediaEntry.find_one(
|
||||
{'_id': ObjectId(request.matchdict['media'])}).uploader()
|
||||
if not (request.user['is_admin'] or
|
||||
request.user['_id'] == uploader['_id']):
|
||||
request.user._id == uploader._id):
|
||||
return exc.HTTPForbidden()
|
||||
|
||||
return controller(request, *args, **kwargs)
|
||||
@ -99,7 +99,7 @@ def get_user_media_entry(controller):
|
||||
media = request.db.MediaEntry.find_one(
|
||||
{'slug': request.matchdict['media'],
|
||||
'state': 'processed',
|
||||
'uploader': user['_id']})
|
||||
'uploader': user._id})
|
||||
|
||||
# no media via slug? Grab it via ObjectId
|
||||
if not media:
|
||||
@ -107,7 +107,7 @@ def get_user_media_entry(controller):
|
||||
media = request.db.MediaEntry.find_one(
|
||||
{'_id': ObjectId(request.matchdict['media']),
|
||||
'state': 'processed',
|
||||
'uploader': user['_id']})
|
||||
'uploader': user._id})
|
||||
except InvalidId:
|
||||
return render_404(request)
|
||||
|
||||
@ -119,6 +119,7 @@ def get_user_media_entry(controller):
|
||||
|
||||
return _make_safe(wrapper, controller)
|
||||
|
||||
|
||||
def get_media_entry_by_id(controller):
|
||||
"""
|
||||
Pass in a MediaEntry based off of a url component
|
||||
@ -138,4 +139,3 @@ def get_media_entry_by_id(controller):
|
||||
return controller(request, media=media, *args, **kwargs)
|
||||
|
||||
return _make_safe(wrapper, controller)
|
||||
|
||||
|
@ -13,5 +13,3 @@
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
def may_edit_media(request, media):
|
||||
"""Check, if the request's user may edit the media details"""
|
||||
if media['uploader'] == request.user['_id']:
|
||||
if media['uploader'] == request.user._id:
|
||||
return True
|
||||
if request.user['is_admin']:
|
||||
return True
|
||||
|
@ -57,7 +57,7 @@ def edit_media(request, media):
|
||||
existing_user_slug_entries = request.db.MediaEntry.find(
|
||||
{'slug': request.POST['slug'],
|
||||
'uploader': media['uploader'],
|
||||
'_id': {'$ne': media['_id']}}).count()
|
||||
'_id': {'$ne': media._id}}).count()
|
||||
|
||||
if existing_user_slug_entries:
|
||||
form.slug.errors.append(
|
||||
@ -78,7 +78,7 @@ def edit_media(request, media):
|
||||
location=media.url_for_self(request.urlgen))
|
||||
|
||||
if request.user['is_admin'] \
|
||||
and media['uploader'] != request.user['_id'] \
|
||||
and media['uploader'] != request.user._id \
|
||||
and request.method != 'POST':
|
||||
messages.add_message(
|
||||
request, messages.WARNING,
|
||||
@ -104,7 +104,7 @@ def edit_attachments(request, media):
|
||||
|
||||
attachment_public_filepath \
|
||||
= mg_globals.public_store.get_unique_filepath(
|
||||
['media_entries', unicode(media['_id']), 'attachment',
|
||||
['media_entries', unicode(media._id), 'attachment',
|
||||
secure_filename(request.POST['attachment_file'].filename)])
|
||||
|
||||
attachment_public_file = mg_globals.public_store.get_file(
|
||||
@ -120,7 +120,7 @@ def edit_attachments(request, media):
|
||||
name=request.POST['attachment_name'] \
|
||||
or request.POST['attachment_file'].filename,
|
||||
filepath=attachment_public_filepath,
|
||||
created=datetime.utcnow()
|
||||
created=datetime.utcnow(),
|
||||
))
|
||||
|
||||
media.save()
|
||||
@ -170,7 +170,7 @@ def edit_profile(request):
|
||||
|
||||
messages.add_message(request,
|
||||
messages.SUCCESS,
|
||||
'Profile edited!')
|
||||
_("Profile edited!"))
|
||||
return redirect(request,
|
||||
'mediagoblin.user_pages.user_home',
|
||||
user=edit_username)
|
||||
|
@ -29,7 +29,7 @@ SUBCOMMAND_MAP = {
|
||||
'setup': 'mediagoblin.gmg_commands.migrate:migrate_parser_setup',
|
||||
'func': 'mediagoblin.gmg_commands.migrate:migrate',
|
||||
'help': 'Apply all unapplied bulk migrations to the database'},
|
||||
'adduser':{
|
||||
'adduser': {
|
||||
'setup': 'mediagoblin.gmg_commands.users:adduser_parser_setup',
|
||||
'func': 'mediagoblin.gmg_commands.users:adduser',
|
||||
'help': 'Creates an user'},
|
||||
@ -68,7 +68,7 @@ def main_cli():
|
||||
|
||||
subparsers = parser.add_subparsers(help='sub-command help')
|
||||
for command_name, command_struct in SUBCOMMAND_MAP.iteritems():
|
||||
if command_struct.has_key('help'):
|
||||
if 'help' in command_struct:
|
||||
subparser = subparsers.add_parser(
|
||||
command_name, help=command_struct['help'])
|
||||
else:
|
||||
@ -94,4 +94,3 @@ def main_cli():
|
||||
|
||||
if __name__ == '__main__':
|
||||
main_cli()
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin.db.open import setup_connection_and_db_from_config
|
||||
from mediagoblin.init.config import read_mediagoblin_config
|
||||
from mediagoblin.storage.filestorage import BasicFileStorage
|
||||
from mediagoblin.init import setup_storage, setup_global_and_app_config
|
||||
|
||||
@ -88,7 +87,7 @@ def _import_database(db, args):
|
||||
args.mongorestore_path,
|
||||
'-d', db.name,
|
||||
os.path.join(args._cache_path['database'], db.name)])
|
||||
|
||||
|
||||
p.wait()
|
||||
|
||||
_log.info('...Database imported')
|
||||
@ -209,7 +208,7 @@ def _export_media(db, args):
|
||||
|
||||
for entry in db.media_entries.find():
|
||||
for name, path in entry['media_files'].items():
|
||||
_log.info('Exporting {0} - {1}'.format(
|
||||
_log.info(u'Exporting {0} - {1}'.format(
|
||||
entry['title'],
|
||||
name))
|
||||
|
||||
@ -226,7 +225,8 @@ def env_export(args):
|
||||
'''
|
||||
if args.cache_path:
|
||||
if os.path.exists(args.cache_path):
|
||||
_log.error('The cache directory must not exist before you run this script')
|
||||
_log.error('The cache directory must not exist '
|
||||
'before you run this script')
|
||||
_log.error('Cache directory: {0}'.format(args.cache_path))
|
||||
|
||||
return False
|
||||
@ -242,7 +242,7 @@ def env_export(args):
|
||||
globa_config, app_config = setup_global_and_app_config(args.conf_file)
|
||||
|
||||
setup_storage()
|
||||
|
||||
|
||||
connection, db = setup_connection_and_db_from_config(
|
||||
app_config, use_pymongo=True)
|
||||
|
||||
|
@ -53,13 +53,13 @@ def migrate(args):
|
||||
for collection, index_name in removed_indexes:
|
||||
print "Removed index '%s' in collection '%s'" % (
|
||||
index_name, collection)
|
||||
|
||||
|
||||
# Migrate
|
||||
print "\n== Applying migrations... =="
|
||||
migration_manager.migrate_new(
|
||||
pre_callback=_print_started_migration,
|
||||
post_callback=_print_finished_migration)
|
||||
|
||||
|
||||
# Add new indexes
|
||||
print "\n== Adding new indexes... =="
|
||||
new_indexes = db_util.add_new_indexes(db)
|
||||
|
@ -38,7 +38,7 @@ def adduser(args):
|
||||
db = mg_globals.database
|
||||
users_with_username = \
|
||||
db.User.find({
|
||||
'username': args.username.lower()
|
||||
'username': args.username.lower(),
|
||||
}).count()
|
||||
|
||||
if users_with_username:
|
||||
@ -68,7 +68,7 @@ def makeadmin(args):
|
||||
|
||||
db = mg_globals.database
|
||||
|
||||
user = db.User.one({'username':unicode(args.username.lower())})
|
||||
user = db.User.one({'username': unicode(args.username.lower())})
|
||||
if user:
|
||||
user['is_admin'] = True
|
||||
user.save()
|
||||
@ -91,11 +91,10 @@ def changepw(args):
|
||||
|
||||
db = mg_globals.database
|
||||
|
||||
user = db.User.one({'username':unicode(args.username.lower())})
|
||||
user = db.User.one({'username': unicode(args.username.lower())})
|
||||
if user:
|
||||
user['pw_hash'] = auth_lib.bcrypt_gen_password_hash(args.password)
|
||||
user.save()
|
||||
print 'Password successfully changed'
|
||||
else:
|
||||
print 'The user doesn\'t exist'
|
||||
|
||||
|
@ -29,8 +29,12 @@ from mediagoblin.workbench import WorkbenchManager
|
||||
from mediagoblin.storage import storage_system_from_config
|
||||
|
||||
|
||||
class Error(Exception): pass
|
||||
class ImproperlyConfigured(Error): pass
|
||||
class Error(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ImproperlyConfigured(Error):
|
||||
pass
|
||||
|
||||
|
||||
def setup_global_and_app_config(config_path):
|
||||
@ -76,8 +80,8 @@ def setup_database():
|
||||
"in fact they appear to be from the future?!")
|
||||
|
||||
setup_globals(
|
||||
db_connection = connection,
|
||||
database = db)
|
||||
db_connection=connection,
|
||||
database=db)
|
||||
|
||||
return connection, db
|
||||
|
||||
@ -99,10 +103,10 @@ def get_jinja_loader(user_template_path=None):
|
||||
|
||||
|
||||
def get_staticdirector(app_config):
|
||||
if app_config.has_key('direct_remote_path'):
|
||||
if 'direct_remote_path' in app_config:
|
||||
return staticdirect.RemoteStaticDirect(
|
||||
app_config['direct_remote_path'].strip())
|
||||
elif app_config.has_key('direct_remote_paths'):
|
||||
elif 'direct_remote_paths' in app_config:
|
||||
direct_remote_path_lines = app_config[
|
||||
'direct_remote_paths'].strip().splitlines()
|
||||
return staticdirect.MultiRemoteStaticDirect(
|
||||
@ -126,8 +130,8 @@ def setup_storage():
|
||||
queue_store = storage_system_from_config(global_config[key_long])
|
||||
|
||||
setup_globals(
|
||||
public_store = public_store,
|
||||
queue_store = queue_store)
|
||||
public_store=public_store,
|
||||
queue_store=queue_store)
|
||||
|
||||
return public_store, queue_store
|
||||
|
||||
@ -137,7 +141,7 @@ def setup_workbench():
|
||||
|
||||
workbench_manager = WorkbenchManager(app_config['workbench_path'])
|
||||
|
||||
setup_globals(workbench_manager = workbench_manager)
|
||||
setup_globals(workbench_manager=workbench_manager)
|
||||
|
||||
|
||||
def setup_beaker_cache():
|
||||
|
@ -40,25 +40,25 @@ def setup_celery_from_config(app_config, global_config,
|
||||
- set_environ: if set, this will CELERY_CONFIG_MODULE to the
|
||||
settings_module
|
||||
"""
|
||||
if global_config.has_key('celery'):
|
||||
if 'celery' in global_config:
|
||||
celery_conf = global_config['celery']
|
||||
else:
|
||||
celery_conf = {}
|
||||
|
||||
|
||||
celery_settings = {}
|
||||
|
||||
# set up mongodb stuff
|
||||
celery_settings['CELERY_RESULT_BACKEND'] = 'mongodb'
|
||||
if not celery_settings.has_key('BROKER_BACKEND'):
|
||||
if 'BROKER_BACKEND' not in celery_settings:
|
||||
celery_settings['BROKER_BACKEND'] = 'mongodb'
|
||||
|
||||
celery_mongo_settings = {}
|
||||
|
||||
if app_config.has_key('db_host'):
|
||||
if 'db_host' in app_config:
|
||||
celery_mongo_settings['host'] = app_config['db_host']
|
||||
if celery_settings['BROKER_BACKEND'] == 'mongodb':
|
||||
celery_settings['BROKER_HOST'] = app_config['db_host']
|
||||
if app_config.has_key('db_port'):
|
||||
if 'db_port' in app_config:
|
||||
celery_mongo_settings['port'] = app_config['db_port']
|
||||
if celery_settings['BROKER_BACKEND'] == 'mongodb':
|
||||
celery_settings['BROKER_PORT'] = app_config['db_port']
|
||||
@ -84,6 +84,6 @@ def setup_celery_from_config(app_config, global_config,
|
||||
|
||||
for key, value in celery_settings.iteritems():
|
||||
setattr(this_module, key, value)
|
||||
|
||||
|
||||
if set_environ:
|
||||
os.environ['CELERY_CONFIG_MODULE'] = settings_module
|
||||
|
@ -44,7 +44,7 @@ def setup_self(check_environ_for_conf=True, module_name=OUR_MODULENAME,
|
||||
if not os.path.exists(mgoblin_conf_file):
|
||||
raise IOError(
|
||||
"MEDIAGOBLIN_CONFIG not set or file does not exist")
|
||||
|
||||
|
||||
# By setting the environment variable here we should ensure that
|
||||
# this is the module that gets set up.
|
||||
os.environ['CELERY_CONFIG_MODULE'] = module_name
|
||||
|
@ -73,7 +73,7 @@ def read_mediagoblin_config(config_path, config_spec=CONFIG_SPEC_PATH):
|
||||
# For now the validator just works with the default functions,
|
||||
# but in the future if we want to add additional validation/configuration
|
||||
# functions we'd add them to validator.functions here.
|
||||
#
|
||||
#
|
||||
# See also:
|
||||
# http://www.voidspace.org.uk/python/validate.html#adding-functions
|
||||
validator = Validator()
|
||||
|
@ -25,4 +25,3 @@ tag_routes = [
|
||||
Route('mediagoblin.listings.tag_atom_feed', "/{tag}/atom/",
|
||||
controller="mediagoblin.listings.views:tag_atom_feed"),
|
||||
]
|
||||
|
||||
|
@ -47,7 +47,7 @@ def tag_listing(request, page):
|
||||
{u'state': u'processed',
|
||||
u'tags.slug': tag_slug})
|
||||
cursor = cursor.sort('created', DESCENDING)
|
||||
|
||||
|
||||
pagination = Pagination(page, cursor)
|
||||
media_entries = pagination()
|
||||
|
||||
@ -64,6 +64,7 @@ def tag_listing(request, page):
|
||||
|
||||
ATOM_DEFAULT_NR_OF_UPDATED_ITEMS = 15
|
||||
|
||||
|
||||
def tag_atom_feed(request):
|
||||
"""
|
||||
generates the atom feed with the tag images
|
||||
|
@ -20,11 +20,13 @@ SUCCESS = 'success'
|
||||
WARNING = 'warning'
|
||||
ERROR = 'error'
|
||||
|
||||
|
||||
def add_message(request, level, text):
|
||||
messages = request.session.setdefault('messages', [])
|
||||
messages.append({'level': level, 'text': text})
|
||||
request.session.save()
|
||||
|
||||
|
||||
def fetch_messages(request, clear_from_session=True):
|
||||
messages = request.session.get('messages')
|
||||
if messages and clear_from_session:
|
||||
|
@ -98,7 +98,7 @@ class CsrfMiddleware(object):
|
||||
httponly=True)
|
||||
|
||||
# update the Vary header
|
||||
response.vary = (response.vary or []) + ['Cookie']
|
||||
response.vary = (getattr(response, 'vary', None) or []) + ['Cookie']
|
||||
|
||||
def _make_token(self, request):
|
||||
"""Generate a new token to use for CSRF protection."""
|
||||
|
@ -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/>.
|
||||
|
||||
|
||||
class NoOpMiddleware(object):
|
||||
|
||||
def __init__(self, mg_app):
|
||||
|
@ -14,8 +14,9 @@
|
||||
# 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 Image
|
||||
import os
|
||||
|
||||
import Image
|
||||
from celery.task import Task
|
||||
from celery import registry
|
||||
|
||||
@ -31,7 +32,7 @@ MEDIUM_SIZE = 640, 640
|
||||
def create_pub_filepath(entry, filename):
|
||||
return mgg.public_store.get_unique_filepath(
|
||||
['media_entries',
|
||||
unicode(entry['_id']),
|
||||
unicode(entry._id),
|
||||
filename])
|
||||
|
||||
|
||||
@ -55,7 +56,7 @@ class ProcessMedia(Task):
|
||||
try:
|
||||
process_image(entry)
|
||||
except BaseProcessingFail, exc:
|
||||
mark_entry_failed(entry[u'_id'], exc)
|
||||
mark_entry_failed(entry._id, exc)
|
||||
return
|
||||
|
||||
entry['state'] = u'processed'
|
||||
@ -65,9 +66,10 @@ class ProcessMedia(Task):
|
||||
"""
|
||||
If the processing failed we should mark that in the database.
|
||||
|
||||
Assuming that the exception raised is a subclass of BaseProcessingFail,
|
||||
we can use that to get more information about the failure and store that
|
||||
for conveying information to users about the failure, etc.
|
||||
Assuming that the exception raised is a subclass of
|
||||
BaseProcessingFail, we can use that to get more information
|
||||
about the failure and store that for conveying information to
|
||||
users about the failure, etc.
|
||||
"""
|
||||
entry_id = args[0]
|
||||
mark_entry_failed(entry_id, exc)
|
||||
@ -80,10 +82,10 @@ def mark_entry_failed(entry_id, exc):
|
||||
"""
|
||||
Mark a media entry as having failed in its conversion.
|
||||
|
||||
Uses the exception that was raised to mark more information. If the
|
||||
exception is a derivative of BaseProcessingFail then we can store extra
|
||||
information that can be useful for users telling them why their media failed
|
||||
to process.
|
||||
Uses the exception that was raised to mark more information. If
|
||||
the exception is a derivative of BaseProcessingFail then we can
|
||||
store extra information that can be useful for users telling them
|
||||
why their media failed to process.
|
||||
|
||||
Args:
|
||||
- entry_id: The id of the media entry
|
||||
@ -122,21 +124,20 @@ def process_image(entry):
|
||||
mgg.queue_store, queued_filepath,
|
||||
'source')
|
||||
|
||||
extension = os.path.splitext(queued_filename)[1]
|
||||
|
||||
try:
|
||||
thumb = Image.open(queued_filename)
|
||||
except IOError:
|
||||
raise BadMediaFail()
|
||||
|
||||
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_filepath = create_pub_filepath(entry, 'thumbnail' + extension)
|
||||
thumb_file = mgg.public_store.get_file(thumb_filepath, 'w')
|
||||
|
||||
with thumb_file:
|
||||
thumb.save(thumb_file, "JPEG", quality=90)
|
||||
thumb.save(thumb_file)
|
||||
|
||||
# If the size of the original file exceeds the specified size of a `medium`
|
||||
# file, a `medium.jpg` files is created and later associated with the media
|
||||
@ -147,14 +148,11 @@ def process_image(entry):
|
||||
if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]:
|
||||
medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS)
|
||||
|
||||
if medium.mode != "RGB":
|
||||
medium = medium.convert("RGB")
|
||||
|
||||
medium_filepath = create_pub_filepath(entry, 'medium.jpg')
|
||||
medium_filepath = create_pub_filepath(entry, 'medium' + extension)
|
||||
medium_file = mgg.public_store.get_file(medium_filepath, 'w')
|
||||
|
||||
with medium_file:
|
||||
medium.save(medium_file, "JPEG", quality=90)
|
||||
medium.save(medium_file)
|
||||
medium_processed = True
|
||||
|
||||
# we have to re-read because unlike PIL, not everything reads
|
||||
@ -164,7 +162,8 @@ def process_image(entry):
|
||||
with queued_file:
|
||||
original_filepath = create_pub_filepath(entry, queued_filepath[-1])
|
||||
|
||||
with mgg.public_store.get_file(original_filepath, 'wb') as original_file:
|
||||
with mgg.public_store.get_file(original_filepath, 'wb') \
|
||||
as original_file:
|
||||
original_file.write(queued_file.read())
|
||||
|
||||
mgg.queue_store.delete_file(queued_filepath)
|
||||
|
@ -16,17 +16,18 @@
|
||||
|
||||
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
|
||||
|
||||
|
||||
class BaseProcessingFail(Exception):
|
||||
"""
|
||||
Base exception that all other processing failure messages should
|
||||
subclass from.
|
||||
|
||||
|
||||
You shouldn't call this itself; instead you should subclass it
|
||||
and provid the exception_path and general_message applicable to
|
||||
this error.
|
||||
"""
|
||||
general_message = u''
|
||||
|
||||
|
||||
@property
|
||||
def exception_path(self):
|
||||
return u"%s:%s" % (
|
||||
@ -34,8 +35,8 @@ class BaseProcessingFail(Exception):
|
||||
|
||||
def __init__(self, **metadata):
|
||||
self.metadata = metadata or {}
|
||||
|
||||
|
||||
|
||||
|
||||
class BadMediaFail(BaseProcessingFail):
|
||||
"""
|
||||
Error that should be raised when an inappropriate file was given
|
||||
|
@ -21,24 +21,24 @@ import urlparse
|
||||
# Staticdirect infrastructure.
|
||||
# Borrowed largely from cc.engine
|
||||
# by Chris Webber & Creative Commons
|
||||
#
|
||||
#
|
||||
# This needs documentation!
|
||||
####################################
|
||||
|
||||
import pkg_resources
|
||||
import urlparse
|
||||
|
||||
|
||||
class StaticDirect(object):
|
||||
def __init__(self):
|
||||
self.cache = {}
|
||||
|
||||
def __call__(self, filepath):
|
||||
if self.cache.has_key(filepath):
|
||||
if filepath in self.cache:
|
||||
return self.cache[filepath]
|
||||
|
||||
static_direction = self.cache[filepath] = self.get(filepath)
|
||||
return static_direction
|
||||
|
||||
|
||||
def get(self, filepath):
|
||||
# should be implemented by the individual staticdirector
|
||||
|
@ -27,6 +27,7 @@ from mediagoblin.storage import StorageInterface, clean_listy_filepath
|
||||
import cloudfiles
|
||||
import mimetypes
|
||||
|
||||
|
||||
class CloudFilesStorage(StorageInterface):
|
||||
'''
|
||||
OpenStack/Rackspace Cloud's Swift/CloudFiles support
|
||||
|
@ -13,5 +13,3 @@
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
|
||||
|
@ -16,9 +16,9 @@
|
||||
|
||||
from mimetypes import guess_type
|
||||
|
||||
|
||||
ALLOWED = ['image/jpeg', 'image/png', 'image/tiff', 'image/gif']
|
||||
|
||||
|
||||
def check_filetype(posted_file):
|
||||
if not guess_type(posted_file.filename)[0] in ALLOWED:
|
||||
return False
|
||||
|
@ -39,7 +39,7 @@ def submit_start(request):
|
||||
submit_form = submit_forms.SubmitStartForm(request.POST)
|
||||
|
||||
if request.method == 'POST' and submit_form.validate():
|
||||
if not (request.POST.has_key('file')
|
||||
if not ('file' in request.POST
|
||||
and isinstance(request.POST['file'], FieldStorage)
|
||||
and request.POST['file'].file):
|
||||
submit_form.file.errors.append(
|
||||
@ -60,9 +60,9 @@ def submit_start(request):
|
||||
entry['description'] = unicode(request.POST.get('description'))
|
||||
entry['description_html'] = cleaned_markdown_conversion(
|
||||
entry['description'])
|
||||
|
||||
entry['media_type'] = u'image' # heh
|
||||
entry['uploader'] = request.user['_id']
|
||||
|
||||
entry['media_type'] = u'image' # heh
|
||||
entry['uploader'] = request.user._id
|
||||
|
||||
# Process the user's folksonomy "tags"
|
||||
entry['tags'] = convert_to_tag_list_of_dicts(
|
||||
@ -74,7 +74,7 @@ def submit_start(request):
|
||||
# Now store generate the queueing related filename
|
||||
queue_filepath = request.app.queue_store.get_unique_filepath(
|
||||
['media_entries',
|
||||
unicode(entry['_id']),
|
||||
unicode(entry._id),
|
||||
secure_filename(filename)])
|
||||
|
||||
# queue appropriately
|
||||
@ -89,8 +89,10 @@ def submit_start(request):
|
||||
|
||||
# We generate this ourselves so we know what the taks id is for
|
||||
# retrieval later.
|
||||
# (If we got it off the task's auto-generation, there'd be a risk of
|
||||
# a race condition when we'd save after sending off the task)
|
||||
|
||||
# (If we got it off the task's auto-generation, there'd be
|
||||
# a risk of a race condition when we'd save after sending
|
||||
# off the task)
|
||||
task_id = unicode(uuid.uuid4())
|
||||
entry['queued_task_id'] = task_id
|
||||
|
||||
@ -103,7 +105,7 @@ def submit_start(request):
|
||||
# conditions with changes to the document via processing code)
|
||||
try:
|
||||
process_media.apply_async(
|
||||
[unicode(entry['_id'])], {},
|
||||
[unicode(entry._id)], {},
|
||||
task_id=task_id)
|
||||
except BaseException as exc:
|
||||
# The purpose of this section is because when running in "lazy"
|
||||
@ -112,16 +114,16 @@ def submit_start(request):
|
||||
# expect a lot of users to run things in this way we have to
|
||||
# capture stuff here.
|
||||
#
|
||||
# ... not completely the diaper pattern because the exception is
|
||||
# re-raised :)
|
||||
mark_entry_failed(entry[u'_id'], exc)
|
||||
# ... not completely the diaper pattern because the
|
||||
# exception is re-raised :)
|
||||
mark_entry_failed(entry._id, exc)
|
||||
# re-raise the exception
|
||||
raise
|
||||
|
||||
add_message(request, SUCCESS, _('Woohoo! Submitted!'))
|
||||
|
||||
return redirect(request, "mediagoblin.user_pages.user_home",
|
||||
user = request.user['username'])
|
||||
user=request.user['username'])
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
|
@ -67,7 +67,7 @@
|
||||
user= request.user['username']) }}">
|
||||
{{ request.user['username'] }}</a>
|
||||
|
||||
(<a href="{{ request.urlgen('mediagoblin.auth.logout') }}">log out</a>)
|
||||
(<a href="{{ request.urlgen('mediagoblin.auth.logout') }}">{% trans %}log out{% endtrans %}</a>)
|
||||
{% else %}
|
||||
<a href="{{ request.urlgen('mediagoblin.auth.login') }}">
|
||||
{% trans %}Log in{% endtrans %}</a>
|
||||
|
@ -26,9 +26,13 @@
|
||||
tag=tag_slug) }}">
|
||||
{% endblock mediagoblin_head %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}Media tagged with: {{ tag_name }}{% endtrans %} — {{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block mediagoblin_content -%}
|
||||
<h1>
|
||||
{% trans %}Media tagged with:{% endtrans %} {{ tag_name }}
|
||||
{% trans %}Media tagged with: {{ tag_name }}{% endtrans %}
|
||||
</h1>
|
||||
|
||||
<div class="container_16 media_gallery">
|
||||
|
@ -26,29 +26,30 @@
|
||||
user=user.username) }}">
|
||||
{% endblock mediagoblin_head %}
|
||||
|
||||
{% block title %}
|
||||
{%- trans username=user.username -%}
|
||||
{{ username }}'s media
|
||||
{%- endtrans %} — {{ super() }}
|
||||
{% endblock %}
|
||||
|
||||
{% block mediagoblin_content -%}
|
||||
{% if user %}
|
||||
<h1>
|
||||
{%- trans username=user.username,
|
||||
user_url=request.urlgen(
|
||||
'mediagoblin.user_pages.user_home',
|
||||
user=user.username) -%}
|
||||
<a href="{{ user_url }}">{{ username }}</a>'s media
|
||||
{%- endtrans %}
|
||||
</h1>
|
||||
<h1>
|
||||
{%- trans username=user.username,
|
||||
user_url=request.urlgen(
|
||||
'mediagoblin.user_pages.user_home',
|
||||
user=user.username) -%}
|
||||
<a href="{{ user_url }}">{{ username }}</a>'s media
|
||||
{%- endtrans %}
|
||||
</h1>
|
||||
|
||||
<div class="container_16 media_gallery">
|
||||
{{ object_gallery(request, media_entries, pagination) }}
|
||||
</div>
|
||||
<div class="container_16 media_gallery">
|
||||
{{ object_gallery(request, media_entries, pagination) }}
|
||||
</div>
|
||||
|
||||
<div class="grid_16">
|
||||
{% set feed_url = request.urlgen(
|
||||
'mediagoblin.user_pages.atom_feed',
|
||||
user=user.username) %}
|
||||
{% include "mediagoblin/utils/feed_link.html" %}
|
||||
</div>
|
||||
{% else %}
|
||||
{# This *should* not occur as the view makes sure we pass in a user. #}
|
||||
<p>{% trans %}Sorry, no such user found.{% endtrans %}<p/>
|
||||
{% endif %}
|
||||
<div class="grid_16">
|
||||
{% set feed_url = request.urlgen(
|
||||
'mediagoblin.user_pages.atom_feed',
|
||||
user=user.username) %}
|
||||
{% include "mediagoblin/utils/feed_link.html" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -20,6 +20,8 @@
|
||||
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
|
||||
{% from "mediagoblin/utils/pagination.html" import render_pagination %}
|
||||
|
||||
{% block title %}{{ media.title }} — {{ super() }}{% endblock %}
|
||||
|
||||
{% block mediagoblin_content %}
|
||||
{% if media %}
|
||||
<div class="grid_11 alpha">
|
||||
@ -60,17 +62,17 @@
|
||||
{%- endtrans %}
|
||||
</p>
|
||||
<h3></h3>
|
||||
{% if request.user %}
|
||||
{% if request.user and comments.count() %}
|
||||
<p><a href="#comment_form">{% trans %}Post a comment{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
{% if comments %}
|
||||
{% for comment in comments %}
|
||||
{% set comment_author = comment.author() %}
|
||||
{% if pagination.active_id == comment._id %}
|
||||
<div class="comment_wrapper comment_active" id="comment-{{ 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'] }}">
|
||||
<div class="comment_wrapper" id="comment-{{ comment._id }}">
|
||||
{% endif %}
|
||||
|
||||
<div class="comment_content">{% autoescape False %}{{ comment.content_html }}
|
||||
@ -81,7 +83,7 @@
|
||||
{{ comment_author['username'] }}</a>
|
||||
{% trans %}at{% endtrans %}
|
||||
<a href="{{ request.urlgen('mediagoblin.user_pages.media_home.view_comment',
|
||||
comment = comment['_id'],
|
||||
comment = comment._id,
|
||||
user = media.uploader().username,
|
||||
media = media._id) }}#comment">
|
||||
{{ comment.created.strftime("%I:%M%p %Y-%m-%d") }}
|
||||
@ -112,7 +114,7 @@
|
||||
<div class="grid_5 omega">
|
||||
{% include "mediagoblin/utils/prev_next.html" %}
|
||||
|
||||
{% if media['uploader'] == request.user['_id'] or
|
||||
{% if media['uploader'] == request.user._id or
|
||||
request.user['is_admin'] %}
|
||||
<h3>{% trans %}Actions{% endtrans %}</h3>
|
||||
<p>
|
||||
@ -149,7 +151,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if app_config['allow_attachments']
|
||||
and (media['uploader'] == request.user['_id']
|
||||
and (media['uploader'] == request.user._id
|
||||
or request.user['is_admin']) %}
|
||||
<p>
|
||||
<a href="{{ request.urlgen('mediagoblin.edit.attachments',
|
||||
|
@ -26,6 +26,17 @@
|
||||
user=user.username) }}">
|
||||
{% endblock mediagoblin_head %}
|
||||
|
||||
{% block title %}
|
||||
{%- if user -%}
|
||||
{%- trans username=user.username -%}
|
||||
{{ username }}'s profile
|
||||
{%- endtrans %} — {{ super() }}
|
||||
{%- else -%}
|
||||
{{ super() }}
|
||||
{%- endif -%}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block mediagoblin_content -%}
|
||||
{# If no user... #}
|
||||
{% if not user %}
|
||||
@ -79,7 +90,7 @@
|
||||
</h1>
|
||||
|
||||
{% if not user['url'] and not user['bio'] %}
|
||||
{% if request.user['_id'] == user['_id'] %}
|
||||
{% if request.user._id == user._id %}
|
||||
<div class="grid_6 alpha empty_space">
|
||||
<p>
|
||||
{% trans %}Here's a spot to tell others about yourself.{% endtrans %}
|
||||
@ -102,7 +113,7 @@
|
||||
{% else %}
|
||||
<div class="grid_6 alpha">
|
||||
{% include "mediagoblin/utils/profile.html" %}
|
||||
{% if request.user['_id'] == user['_id'] or request.user['is_admin'] %}
|
||||
{% if request.user._id == user._id or request.user['is_admin'] %}
|
||||
<a href="{{ request.urlgen('mediagoblin.edit.profile') }}?username={{
|
||||
user.username }}">
|
||||
{%- trans %}Edit profile{% endtrans -%}
|
||||
@ -129,7 +140,7 @@
|
||||
{% include "mediagoblin/utils/feed_link.html" %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% if request.user['_id'] == user['_id'] %}
|
||||
{% if request.user._id == user._id %}
|
||||
<div class="grid_10 omega empty_space">
|
||||
<p>
|
||||
{% trans -%}
|
||||
|
@ -168,7 +168,7 @@ def test_register_views(test_app):
|
||||
## Make sure user is logged in
|
||||
request = template.TEMPLATE_TEST_CONTEXT[
|
||||
'mediagoblin/user_pages/user.html']['request']
|
||||
assert request.session['user_id'] == unicode(new_user['_id'])
|
||||
assert request.session['user_id'] == unicode(new_user._id)
|
||||
|
||||
## Make sure we get email confirmation, and try verifying
|
||||
assert len(mail.EMAIL_TEST_INBOX) == 1
|
||||
@ -185,7 +185,7 @@ def test_register_views(test_app):
|
||||
|
||||
### user should have these same parameters
|
||||
assert parsed_get_params['userid'] == [
|
||||
unicode(new_user['_id'])]
|
||||
unicode(new_user._id)]
|
||||
assert parsed_get_params['token'] == [
|
||||
new_user['verification_key']]
|
||||
|
||||
@ -193,7 +193,7 @@ def test_register_views(test_app):
|
||||
template.clear_test_template_context()
|
||||
response = test_app.get(
|
||||
"/auth/verify_email/?userid=%s&token=total_bs" % unicode(
|
||||
new_user['_id']))
|
||||
new_user._id))
|
||||
response.follow()
|
||||
context = template.TEMPLATE_TEST_CONTEXT[
|
||||
'mediagoblin/user_pages/user.html']
|
||||
@ -269,7 +269,7 @@ def test_register_views(test_app):
|
||||
|
||||
# user should have matching parameters
|
||||
new_user = mg_globals.database.User.find_one({'username': 'happygirl'})
|
||||
assert parsed_get_params['userid'] == [unicode(new_user['_id'])]
|
||||
assert parsed_get_params['userid'] == [unicode(new_user._id)]
|
||||
assert parsed_get_params['token'] == [new_user['fp_verification_key']]
|
||||
|
||||
### The forgotten password token should be set to expire in ~ 10 days
|
||||
@ -280,7 +280,7 @@ def test_register_views(test_app):
|
||||
template.clear_test_template_context()
|
||||
response = test_app.get(
|
||||
"/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode(
|
||||
new_user['_id']), status=400)
|
||||
new_user._id), status=400)
|
||||
assert response.status == '400 Bad Request'
|
||||
|
||||
## Try using an expired token to change password, shouldn't work
|
||||
@ -412,7 +412,7 @@ def test_authentication_views(test_app):
|
||||
# Make sure user is in the session
|
||||
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html']
|
||||
session = context['request'].session
|
||||
assert session['user_id'] == unicode(test_user['_id'])
|
||||
assert session['user_id'] == unicode(test_user._id)
|
||||
|
||||
# Successful logout
|
||||
# -----------------
|
||||
|
@ -177,7 +177,7 @@ class TestSubmission:
|
||||
request.urlgen('mediagoblin.user_pages.media_confirm_delete',
|
||||
# No work: user=media.uploader().username,
|
||||
user=self.test_user['username'],
|
||||
media=media['_id']),
|
||||
media=media._id),
|
||||
# no value means no confirm
|
||||
{})
|
||||
|
||||
@ -197,7 +197,7 @@ class TestSubmission:
|
||||
request.urlgen('mediagoblin.user_pages.media_confirm_delete',
|
||||
# No work: user=media.uploader().username,
|
||||
user=self.test_user['username'],
|
||||
media=media['_id']),
|
||||
media=media._id),
|
||||
{'confirm': 'y'})
|
||||
|
||||
response.follow()
|
||||
@ -208,7 +208,7 @@ class TestSubmission:
|
||||
# Does media entry still exist?
|
||||
assert_false(
|
||||
request.db.MediaEntry.find(
|
||||
{'_id': media['_id']}).count())
|
||||
{'_id': media._id}).count())
|
||||
|
||||
def test_malicious_uploads(self):
|
||||
# Test non-suppoerted file with non-supported extension
|
||||
|
@ -21,6 +21,7 @@ DISPLAY_IMAGE_FETCHING_ORDER = [u'medium', u'original', u'thumb']
|
||||
global TESTS_ENABLED
|
||||
TESTS_ENABLED = False
|
||||
|
||||
|
||||
def import_component(import_string):
|
||||
"""
|
||||
Import a module component defined by STRING. Probably a method,
|
||||
|
@ -24,7 +24,7 @@ from mediagoblin.tools import common
|
||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
# We have two "test inboxes" here:
|
||||
#
|
||||
#
|
||||
# EMAIL_TEST_INBOX:
|
||||
# ----------------
|
||||
# If you're writing test views, you'll probably want to check this.
|
||||
@ -44,11 +44,12 @@ from mediagoblin.tools import common
|
||||
# ***IMPORTANT!***
|
||||
# ----------------
|
||||
# Before running tests that call functions which send email, you should
|
||||
# always call _clear_test_inboxes() to "wipe" the inboxes clean.
|
||||
# always call _clear_test_inboxes() to "wipe" the inboxes clean.
|
||||
|
||||
EMAIL_TEST_INBOX = []
|
||||
EMAIL_TEST_MBOX_INBOX = []
|
||||
|
||||
|
||||
class FakeMhost(object):
|
||||
"""
|
||||
Just a fake mail host so we can capture and test messages
|
||||
@ -63,12 +64,14 @@ class FakeMhost(object):
|
||||
'to': to_addrs,
|
||||
'message': message})
|
||||
|
||||
|
||||
def _clear_test_inboxes():
|
||||
global EMAIL_TEST_INBOX
|
||||
global EMAIL_TEST_MBOX_INBOX
|
||||
EMAIL_TEST_INBOX = []
|
||||
EMAIL_TEST_MBOX_INBOX = []
|
||||
|
||||
|
||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
### </Special email test stuff>
|
||||
### ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -19,8 +19,10 @@ import copy
|
||||
from math import ceil, floor
|
||||
from itertools import izip, count
|
||||
|
||||
|
||||
PAGINATION_DEFAULT_PER_PAGE = 30
|
||||
|
||||
|
||||
class Pagination(object):
|
||||
"""
|
||||
Pagination class for mongodb queries.
|
||||
@ -37,9 +39,9 @@ class Pagination(object):
|
||||
Args:
|
||||
- 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.
|
||||
- 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.per_page = per_page
|
||||
@ -51,7 +53,7 @@ class Pagination(object):
|
||||
cursor = copy.copy(self.cursor)
|
||||
|
||||
for (doc, increment) in izip(cursor, count(0)):
|
||||
if doc['_id'] == jump_to_id:
|
||||
if doc._id == jump_to_id:
|
||||
self.page = 1 + int(floor(increment / self.per_page))
|
||||
|
||||
self.active_id = jump_to_id
|
||||
@ -91,19 +93,19 @@ class Pagination(object):
|
||||
last = num
|
||||
|
||||
def get_page_url_explicit(self, base_url, get_params, page_no):
|
||||
"""
|
||||
"""
|
||||
Get a page url by adding a page= parameter to the base url
|
||||
"""
|
||||
"""
|
||||
new_get_params = copy.copy(get_params or {})
|
||||
new_get_params['page'] = page_no
|
||||
return "%s?%s" % (
|
||||
base_url, urllib.urlencode(new_get_params))
|
||||
|
||||
def get_page_url(self, request, page_no):
|
||||
"""
|
||||
"""
|
||||
Get a new page url based of the request, and the new page number.
|
||||
|
||||
This is a nice wrapper around get_page_url_explicit()
|
||||
"""
|
||||
"""
|
||||
return self.get_page_url_explicit(
|
||||
request.full_path, request.GET, page_no)
|
||||
|
@ -17,12 +17,14 @@
|
||||
from webob import Response, exc
|
||||
from mediagoblin.tools.template import render_template
|
||||
|
||||
|
||||
def render_to_response(request, template, context, status=200):
|
||||
"""Much like Django's shortcut.render()"""
|
||||
return Response(
|
||||
render_template(request, template, context),
|
||||
status=status)
|
||||
|
||||
|
||||
def render_404(request):
|
||||
"""
|
||||
Render a 404.
|
||||
@ -30,9 +32,10 @@ def render_404(request):
|
||||
return render_to_response(
|
||||
request, 'mediagoblin/404.html', {}, status=400)
|
||||
|
||||
|
||||
def redirect(request, *args, **kwargs):
|
||||
"""Returns a HTTPFound(), takes a request and then urlgen params"""
|
||||
|
||||
|
||||
querystring = None
|
||||
if kwargs.get('querystring'):
|
||||
querystring = kwargs.get('querystring')
|
||||
|
@ -17,18 +17,19 @@
|
||||
from math import ceil
|
||||
import jinja2
|
||||
from babel.localedata import exists
|
||||
from babel.support import LazyProxy
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin import messages
|
||||
from mediagoblin.tools import common
|
||||
from mediagoblin.tools.translate import setup_gettext
|
||||
from mediagoblin.middleware.csrf import render_csrf_form_token
|
||||
|
||||
|
||||
SETUP_JINJA_ENVS = {}
|
||||
|
||||
|
||||
def get_jinja_env(template_loader, locale):
|
||||
"""
|
||||
Set up the Jinja environment,
|
||||
Set up the Jinja environment,
|
||||
|
||||
(In the future we may have another system for providing theming;
|
||||
for now this is good enough.)
|
||||
@ -60,6 +61,7 @@ def get_jinja_env(template_loader, locale):
|
||||
|
||||
return template_env
|
||||
|
||||
|
||||
# We'll store context information here when doing unit tests
|
||||
TEMPLATE_TEST_CONTEXT = {}
|
||||
|
||||
@ -76,8 +78,8 @@ def render_template(request, template_path, context):
|
||||
context['request'] = request
|
||||
context['csrf_token'] = render_csrf_form_token(request)
|
||||
rendered = template.render(context)
|
||||
|
||||
if common.TESTS_ENABLED:
|
||||
|
||||
if common.TESTS_ENABLED:
|
||||
TEMPLATE_TEST_CONTEXT[template_path] = context
|
||||
|
||||
return rendered
|
||||
@ -87,6 +89,7 @@ def clear_test_template_context():
|
||||
global TEMPLATE_TEST_CONTEXT
|
||||
TEMPLATE_TEST_CONTEXT = {}
|
||||
|
||||
|
||||
def gridify_list(this_list, num_cols=5):
|
||||
"""
|
||||
Generates a list of lists where each sub-list's length depends on
|
||||
|
@ -21,6 +21,7 @@ from lxml.html.clean import Cleaner
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin.tools import url
|
||||
|
||||
|
||||
# A super strict version of the lxml.html cleaner class
|
||||
HTML_CLEANER = Cleaner(
|
||||
scripts=True,
|
||||
@ -42,6 +43,7 @@ HTML_CLEANER = Cleaner(
|
||||
host_whitelist=(),
|
||||
whitelist_tags=set([]))
|
||||
|
||||
|
||||
def clean_html(html):
|
||||
# clean_html barfs on an empty string
|
||||
if not html:
|
||||
@ -49,6 +51,7 @@ def clean_html(html):
|
||||
|
||||
return HTML_CLEANER.clean_html(html)
|
||||
|
||||
|
||||
def convert_to_tag_list_of_dicts(tag_string):
|
||||
"""
|
||||
Filter input from incoming string containing user tags,
|
||||
@ -73,6 +76,7 @@ def convert_to_tag_list_of_dicts(tag_string):
|
||||
'slug': url.slugify(tag.strip())})
|
||||
return taglist
|
||||
|
||||
|
||||
def media_tags_as_string(media_entry_tags):
|
||||
"""
|
||||
Generate a string from a media item's tags, stored as a list of dicts
|
||||
@ -85,9 +89,11 @@ def media_tags_as_string(media_entry_tags):
|
||||
[tag['name'] for tag in media_entry_tags])
|
||||
return media_tag_string
|
||||
|
||||
|
||||
TOO_LONG_TAG_WARNING = \
|
||||
u'Tags must be shorter than %s characters. Tags that are too long: %s'
|
||||
|
||||
|
||||
def tag_length_validator(form, field):
|
||||
"""
|
||||
Make sure tags do not exceed the maximum tag length.
|
||||
@ -105,6 +111,7 @@ def tag_length_validator(form, field):
|
||||
|
||||
MARKDOWN_INSTANCE = markdown.Markdown(safe_mode='escape')
|
||||
|
||||
|
||||
def cleaned_markdown_conversion(text):
|
||||
"""
|
||||
Take a block of text, run it through MarkDown, and clean its HTML.
|
||||
|
@ -17,8 +17,10 @@
|
||||
import re
|
||||
import translitcodec
|
||||
|
||||
|
||||
_punct_re = re.compile(r'[\t !"#$%&\'()*\-/<=>?@\[\\\]^_`{|},.]+')
|
||||
|
||||
|
||||
def slugify(text, delim=u'-'):
|
||||
"""
|
||||
Generates an ASCII-only slug. Taken from http://flask.pocoo.org/snippets/5/
|
||||
|
@ -13,5 +13,3 @@
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
|
||||
|
@ -45,7 +45,7 @@ def user_home(request, page):
|
||||
{'user': user})
|
||||
|
||||
cursor = request.db.MediaEntry.find(
|
||||
{'uploader': user['_id'],
|
||||
{'uploader': user._id,
|
||||
'state': 'processed'}).sort('created', DESCENDING)
|
||||
|
||||
pagination = Pagination(page, cursor)
|
||||
@ -54,7 +54,7 @@ def user_home(request, page):
|
||||
#if no data is available, return NotFound
|
||||
if media_entries == None:
|
||||
return render_404(request)
|
||||
|
||||
|
||||
user_gallery_url = request.urlgen(
|
||||
'mediagoblin.user_pages.user_gallery',
|
||||
user=user['username'])
|
||||
@ -67,6 +67,7 @@ def user_home(request, page):
|
||||
'media_entries': media_entries,
|
||||
'pagination': pagination})
|
||||
|
||||
|
||||
@uses_pagination
|
||||
def user_gallery(request, page):
|
||||
"""'Gallery' of a User()"""
|
||||
@ -77,7 +78,7 @@ def user_gallery(request, page):
|
||||
return render_404(request)
|
||||
|
||||
cursor = request.db.MediaEntry.find(
|
||||
{'uploader': user['_id'],
|
||||
{'uploader': user._id,
|
||||
'state': 'processed'}).sort('created', DESCENDING)
|
||||
|
||||
pagination = Pagination(page, cursor)
|
||||
@ -86,7 +87,7 @@ def user_gallery(request, page):
|
||||
#if no data is available, return NotFound
|
||||
if media_entries == None:
|
||||
return render_404(request)
|
||||
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/user_pages/gallery.html',
|
||||
@ -96,6 +97,7 @@ def user_gallery(request, page):
|
||||
|
||||
MEDIA_COMMENTS_PER_PAGE = 50
|
||||
|
||||
|
||||
@get_user_media_entry
|
||||
@uses_pagination
|
||||
def media_home(request, media, page, **kwargs):
|
||||
@ -133,8 +135,8 @@ def media_post_comment(request, media):
|
||||
assert request.method == 'POST'
|
||||
|
||||
comment = request.db.MediaComment()
|
||||
comment['media_entry'] = media['_id']
|
||||
comment['author'] = request.user['_id']
|
||||
comment['media_entry'] = media._id
|
||||
comment['author'] = request.user._id
|
||||
comment['content'] = unicode(request.POST['comment_content'])
|
||||
comment['content_html'] = cleaned_markdown_conversion(comment['content'])
|
||||
|
||||
@ -177,7 +179,7 @@ def media_confirm_delete(request, media):
|
||||
location=media.url_for_self(request.urlgen))
|
||||
|
||||
if ((request.user[u'is_admin'] and
|
||||
request.user[u'_id'] != media.uploader()[u'_id'])):
|
||||
request.user._id != media.uploader()._id)):
|
||||
messages.add_message(
|
||||
request, messages.WARNING,
|
||||
_("You are about to delete another user's media. "
|
||||
@ -192,6 +194,7 @@ def media_confirm_delete(request, media):
|
||||
|
||||
ATOM_DEFAULT_NR_OF_UPDATED_ITEMS = 15
|
||||
|
||||
|
||||
def atom_feed(request):
|
||||
"""
|
||||
generates the atom feed with the newest images
|
||||
@ -204,7 +207,7 @@ def atom_feed(request):
|
||||
return render_404(request)
|
||||
|
||||
cursor = request.db.MediaEntry.find({
|
||||
'uploader': user['_id'],
|
||||
'uploader': user._id,
|
||||
'state': 'processed'}) \
|
||||
.sort('created', DESCENDING) \
|
||||
.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS)
|
||||
@ -212,7 +215,7 @@ def atom_feed(request):
|
||||
feed = AtomFeed(request.matchdict['user'],
|
||||
feed_url=request.url,
|
||||
url=request.host_url)
|
||||
|
||||
|
||||
for entry in cursor:
|
||||
feed.add(entry.get('title'),
|
||||
entry.get('description_html'),
|
||||
@ -248,7 +251,7 @@ def processing_panel(request):
|
||||
#
|
||||
# Make sure we have permission to access this user's panel. Only
|
||||
# admins and this user herself should be able to do so.
|
||||
if not (user[u'_id'] == request.user[u'_id']
|
||||
if not (user._id == request.user._id
|
||||
or request.user.is_admin):
|
||||
# No? Let's simply redirect to this user's homepage then.
|
||||
return redirect(
|
||||
@ -257,12 +260,12 @@ def processing_panel(request):
|
||||
|
||||
# Get media entries which are in-processing
|
||||
processing_entries = request.db.MediaEntry.find(
|
||||
{'uploader': user['_id'],
|
||||
{'uploader': user._id,
|
||||
'state': 'processing'}).sort('created', DESCENDING)
|
||||
|
||||
# Get media entries which have failed to process
|
||||
failed_entries = request.db.MediaEntry.find(
|
||||
{'uploader': user['_id'],
|
||||
{'uploader': user._id,
|
||||
'state': 'failed'}).sort('created', DESCENDING)
|
||||
|
||||
# Render to response
|
||||
|
@ -20,6 +20,7 @@ from mediagoblin.tools.response import render_to_response
|
||||
from mediagoblin.db.util import DESCENDING
|
||||
from mediagoblin.decorators import uses_pagination
|
||||
|
||||
|
||||
@uses_pagination
|
||||
def root_view(request, page):
|
||||
cursor = request.db.MediaEntry.find(
|
||||
|
@ -42,8 +42,10 @@ class Workbench(object):
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.dir)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.dir)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.dir)
|
||||
|
||||
@ -140,7 +142,7 @@ class WorkbenchManager(object):
|
||||
self.base_workbench_dir = os.path.abspath(base_workbench_dir)
|
||||
if not os.path.exists(self.base_workbench_dir):
|
||||
os.makedirs(self.base_workbench_dir)
|
||||
|
||||
|
||||
def create_workbench(self):
|
||||
"""
|
||||
Create and return the path to a new workbench (directory).
|
||||
|
12
setup.py
12
setup.py
@ -29,16 +29,17 @@ def get_version():
|
||||
if mo:
|
||||
return mo.group(1)
|
||||
else:
|
||||
raise RuntimeError("Unable to find version string in %s." % VERSIONFILE)
|
||||
raise RuntimeError("Unable to find version string in %s." %
|
||||
VERSIONFILE)
|
||||
|
||||
|
||||
setup(
|
||||
name = "mediagoblin",
|
||||
version = get_version(),
|
||||
name="mediagoblin",
|
||||
version=get_version(),
|
||||
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
|
||||
zip_safe=False,
|
||||
# scripts and dependencies
|
||||
install_requires = [
|
||||
install_requires=[
|
||||
'setuptools',
|
||||
'PasteScript',
|
||||
'beaker',
|
||||
@ -66,7 +67,7 @@ setup(
|
||||
# 'lxml',
|
||||
],
|
||||
test_suite='nose.collector',
|
||||
entry_points = """\
|
||||
entry_points="""\
|
||||
[console_scripts]
|
||||
gmg = mediagoblin.gmg_commands:main_cli
|
||||
pybabel = mediagoblin.babel.messages.frontend:main
|
||||
@ -83,7 +84,6 @@ setup(
|
||||
[babel.extractors]
|
||||
jinja2 = jinja2.ext:babel_extract
|
||||
""",
|
||||
|
||||
license='AGPLv3',
|
||||
author='Free Software Foundation and contributors',
|
||||
author_email='cwebber@gnu.org',
|
||||
|
Loading…
x
Reference in New Issue
Block a user