Merge branch 'master' of git://gitorious.org/mediagoblin/mediagoblin

This commit is contained in:
xray7224 2013-07-14 15:27:52 +01:00
commit e49263564b
48 changed files with 395 additions and 261 deletions

View File

@ -74,6 +74,7 @@ This guide covers writing new GNU MediaGoblin plugins.
pluginwriter/database pluginwriter/database
pluginwriter/api pluginwriter/api
pluginwriter/tests pluginwriter/tests
pluginwriter/media_type_hooks
Part 4: Developer's Zone Part 4: Developer's Zone

View File

@ -0,0 +1,38 @@
==================
Media Type hooks
==================
This documents the hooks that are currently available for ``media_type`` plugins.
What hooks are available?
=========================
'sniff_handler'
---------------
This hook is used by ``sniff_media`` in ``mediagoblin.media_types.__init__``.
Your media type should return its ``sniff_media`` method when this hook is
called.
.. Note::
Your ``sniff_media`` method should return either the ``media_type`` or
``None``.
'get_media_type_and_manager'
----------------------------
This hook is used by ``get_media_type_and_manager`` in
``mediagoblin.media_types.__init__``. When this hook is called, your media type
plugin should check if it can handle the given extension. If so, your media
type plugin should return the media type and media manager.
('media_manager', MEDIA_TYPE)
-----------------------------
If you already know the string representing the media type of a type
of media, you can pull down the manager specifically. Note that this
hook is not a string but a tuple of two strings, the latter being the
name of the media type.
This is used by media entries to pull down their media managers, and
so on.

View File

@ -18,16 +18,18 @@ Media Types
==================== ====================
In the future, there will be all sorts of media types you can enable, In the future, there will be all sorts of media types you can enable,
but in the meanwhile there are three additional media types: video, audio but in the meanwhile there are five additional media types: video, audio,
and ascii art. ascii art, STL/3d models, PDF and Document.
First, you should probably read ":doc:`configuration`" to make sure First, you should probably read ":doc:`configuration`" to make sure
you know how to modify the mediagoblin config file. you know how to modify the mediagoblin config file.
Enabling Media Types Enabling Media Types
==================== ====================
.. note::
Media types are now plugins
Media types are enabled in your mediagoblin configuration file, typically it is Media types are enabled in your mediagoblin configuration file, typically it is
created by copying ``mediagoblin.ini`` to ``mediagoblin_local.ini`` and then created by copying ``mediagoblin.ini`` to ``mediagoblin_local.ini`` and then
applying your changes to ``mediagoblin_local.ini``. If you don't already have a applying your changes to ``mediagoblin_local.ini``. If you don't already have a
@ -37,11 +39,13 @@ Most media types have additional dependencies that you will have to install.
You will find descriptions on how to satisfy the requirements of each media type You will find descriptions on how to satisfy the requirements of each media type
on this page. on this page.
To enable a media type, edit the ``media_types`` list in your To enable a media type, add the the media type under the ``[plugins]`` section
``mediagoblin_local.ini``. For example, if your system supported image and in you ``mediagoblin_local.ini``. For example, if your system supported image
video media types, then the list would look like this:: and video media types, then it would look like this::
media_types = mediagoblin.media_types.image, mediagoblin.media_types.video [plugins]
[[mediagoblin.media_types.image]]
[[mediagoblin.media_types.video]]
Note that after enabling new media types, you must run dbupdate like so:: Note that after enabling new media types, you must run dbupdate like so::
@ -83,8 +87,8 @@ good/bad/ugly). On Debianoid systems
gstreamer0.10-ffmpeg gstreamer0.10-ffmpeg
Add ``mediagoblin.media_types.video`` to the ``media_types`` list in your Add ``[[mediagoblin.media_types.video]]`` under the ``[plugins]`` section in
``mediagoblin_local.ini`` and restart MediaGoblin. your ``mediagoblin_local.ini`` and restart MediaGoblin.
Run Run
@ -133,7 +137,7 @@ Then install ``scikits.audiolab`` for the spectrograms::
./bin/pip install scikits.audiolab ./bin/pip install scikits.audiolab
Add ``mediagoblin.media_types.audio`` to the ``media_types`` list in your Add ``[[mediagoblin.media_types.audio]]`` under the ``[plugins]`` section in your
``mediagoblin_local.ini`` and restart MediaGoblin. ``mediagoblin_local.ini`` and restart MediaGoblin.
Run Run
@ -158,13 +162,8 @@ library, which is necessary for creating thumbnails of ascii art
Next, modify (and possibly copy over from ``mediagoblin.ini``) your Next, modify (and possibly copy over from ``mediagoblin.ini``) your
``mediagoblin_local.ini``. In the ``[mediagoblin]`` section, add ``mediagoblin_local.ini``. In the ``[plugins]`` section, add
``mediagoblin.media_types.ascii`` to the ``media_types`` list. ``[[mediagoblin.media_types.ascii]]``.
For example, if your system supported image and ascii art media types, then
the list would look like this::
media_types = mediagoblin.media_types.image, mediagoblin.media_types.ascii
Run Run
@ -184,7 +183,7 @@ your execution path. This feature has been tested with Blender 2.63.
It may work on some earlier versions, but that is not guaranteed (and It may work on some earlier versions, but that is not guaranteed (and
is surely not to work prior to Blender 2.5X). is surely not to work prior to Blender 2.5X).
Add ``mediagoblin.media_types.stl`` to the ``media_types`` list in your Add ``[[mediagoblin.media_types.stl]]`` under the ``[plugins]`` section in your
``mediagoblin_local.ini`` and restart MediaGoblin. ``mediagoblin_local.ini`` and restart MediaGoblin.
Run Run
@ -233,7 +232,7 @@ This feature has been tested on Fedora with:
It may work on some earlier versions, but that is not guaranteed. It may work on some earlier versions, but that is not guaranteed.
Add ``mediagoblin.media_types.pdf`` to the ``media_types`` list in your Add ``[[mediagoblin.media_types.pdf]]`` under the ``[plugins]`` section in your
``mediagoblin_local.ini`` and restart MediaGoblin. ``mediagoblin_local.ini`` and restart MediaGoblin.
Run Run

View File

@ -11,19 +11,15 @@ email_sender_address = "notice@mediagoblin.example.org"
## Uncomment and change to your DB's appropiate setting. ## Uncomment and change to your DB's appropiate setting.
## Default is a local sqlite db "mediagoblin.db". ## Default is a local sqlite db "mediagoblin.db".
## Don't forget to run `./bin/gmg dbupdate` after having changed it.
# sql_engine = postgresql:///mediagoblin # sql_engine = postgresql:///mediagoblin
# set to false to enable sending notices # Set to false to enable sending notices
email_debug_mode = true email_debug_mode = true
# Set to false to disable registrations # Set to false to disable registrations
allow_registration = true allow_registration = true
## Uncomment this to turn on video or enable other media types
## You may have to install dependencies, and will have to run ./bin/gmg dbupdate
## See http://docs.mediagoblin.org/siteadmin/media-types.html for details.
# media_types = mediagoblin.media_types.image, mediagoblin.media_types.video
## Uncomment this to put some user-overriding templates here ## Uncomment this to put some user-overriding templates here
# local_templates = %(here)s/user_dev/templates/ # local_templates = %(here)s/user_dev/templates/
@ -43,8 +39,9 @@ base_url = /mgoblin_media/
[celery] [celery]
# Put celery stuff here # Put celery stuff here
# place plugins here---each in their own subsection of [plugins]. see # Place plugins here, each in their own subsection of [plugins].
# documentation for details. # See http://docs.mediagoblin.org/siteadmin/plugins.html for details.
[plugins] [plugins]
[[mediagoblin.plugins.geolocation]] [[mediagoblin.plugins.geolocation]]
[[mediagoblin.plugins.basic_auth]] [[mediagoblin.plugins.basic_auth]]
[[mediagoblin.media_types.image]]

View File

@ -29,6 +29,7 @@ from mediagoblin.tools import common, session, translate, template
from mediagoblin.tools.response import render_http_exception from mediagoblin.tools.response import render_http_exception
from mediagoblin.tools.theme import register_themes from mediagoblin.tools.theme import register_themes
from mediagoblin.tools import request as mg_request from mediagoblin.tools import request as mg_request
from mediagoblin.media_types.tools import media_type_warning
from mediagoblin.mg_globals import setup_globals from mediagoblin.mg_globals import setup_globals
from mediagoblin.init.celery import setup_celery_from_config from mediagoblin.init.celery import setup_celery_from_config
from mediagoblin.init.plugins import setup_plugins from mediagoblin.init.plugins import setup_plugins
@ -69,6 +70,8 @@ class MediaGoblinApp(object):
# Open and setup the config # Open and setup the config
global_config, app_config = setup_global_and_app_config(config_path) global_config, app_config = setup_global_and_app_config(config_path)
media_type_warning()
setup_crypto() setup_crypto()
########################################## ##########################################

View File

@ -88,6 +88,8 @@ def login(request):
if user: if user:
# set up login in session # set up login in session
if login_form.stay_logged_in.data:
request.session['stay_logged_in'] = True
request.session['user_id'] = unicode(user.id) request.session['user_id'] = unicode(user.id)
request.session.save() request.session.save()

View File

@ -5,9 +5,6 @@ html_title = string(default="GNU MediaGoblin")
# link to source for this MediaGoblin site # link to source for this MediaGoblin site
source_link = string(default="https://gitorious.org/mediagoblin/mediagoblin") source_link = string(default="https://gitorious.org/mediagoblin/mediagoblin")
# Enabled media types
media_types = string_list(default=list("mediagoblin.media_types.image"))
# database stuff # database stuff
sql_engine = string(default="sqlite:///%(here)s/mediagoblin.db") sql_engine = string(default="sqlite:///%(here)s/mediagoblin.db")

View File

@ -24,18 +24,6 @@ Session = scoped_session(sessionmaker())
class GMGTableBase(object): class GMGTableBase(object):
query = Session.query_property() query = Session.query_property()
@classmethod
def find(cls, query_dict):
return cls.query.filter_by(**query_dict)
@classmethod
def find_one(cls, query_dict):
return cls.query.filter_by(**query_dict).first()
@classmethod
def one(cls, query_dict):
return cls.find(query_dict).one()
def get(self, key): def get(self, key):
return getattr(self, key) return getattr(self, key)

View File

@ -175,8 +175,7 @@ class MigrationManager(object):
if self.name == u'__main__': if self.name == u'__main__':
return u"main mediagoblin tables" return u"main mediagoblin tables"
else: else:
# TODO: Use the friendlier media manager "human readable" name return u'plugin "%s"' % self.name
return u'media type "%s"' % self.name
def init_or_migrate(self): def init_or_migrate(self):
""" """

View File

@ -29,15 +29,14 @@ real objects.
import uuid import uuid
import re import re
import datetime
from datetime import datetime from datetime import datetime
from werkzeug.utils import cached_property from werkzeug.utils import cached_property
from mediagoblin import mg_globals from mediagoblin import mg_globals
from mediagoblin.media_types import get_media_managers, FileTypeNotSupported from mediagoblin.media_types import FileTypeNotSupported
from mediagoblin.tools import common, licenses from mediagoblin.tools import common, licenses
from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.tools.text import cleaned_markdown_conversion from mediagoblin.tools.text import cleaned_markdown_conversion
from mediagoblin.tools.url import slugify from mediagoblin.tools.url import slugify
@ -204,14 +203,14 @@ class MediaEntryMixin(GenerateSlugMixin):
Raises FileTypeNotSupported in case no such manager is enabled Raises FileTypeNotSupported in case no such manager is enabled
""" """
# TODO, we should be able to make this a simple lookup rather manager = hook_handle(('media_manager', self.media_type))
# than iterating through all media managers. if manager:
for media_type, manager in get_media_managers(): return manager(self)
if media_type == self.media_type:
return manager(self)
# Not found? Then raise an error # Not found? Then raise an error
raise FileTypeNotSupported( raise FileTypeNotSupported(
"MediaManager not in enabled types. Check media_types in config?") "MediaManager not in enabled types. Check media_type plugins are"
" enabled in config?")
def get_fail_exception(self): def get_fail_exception(self):
""" """

View File

@ -52,10 +52,6 @@ class DatabaseMaster(object):
def load_models(app_config): def load_models(app_config):
import mediagoblin.db.models import mediagoblin.db.models
for media_type in app_config['media_types']:
_log.debug("Loading %s.models", media_type)
__import__(media_type + ".models")
for plugin in mg_globals.global_config.get('plugins', {}).keys(): for plugin in mg_globals.global_config.get('plugins', {}).keys():
_log.debug("Loading %s.models", plugin) _log.debug("Loading %s.models", plugin)
try: try:

View File

@ -24,7 +24,7 @@ from mediagoblin.db.models import MediaEntry, Tag, MediaTag, Collection
def atomic_update(table, query_dict, update_values): def atomic_update(table, query_dict, update_values):
table.find(query_dict).update(update_values, table.query.filter_by(**query_dict).update(update_values,
synchronize_session=False) synchronize_session=False)
Session.commit() Session.commit()

View File

@ -90,8 +90,8 @@ def user_may_alter_collection(controller):
""" """
@wraps(controller) @wraps(controller)
def wrapper(request, *args, **kwargs): def wrapper(request, *args, **kwargs):
creator_id = request.db.User.find_one( creator_id = request.db.User.query.filter_by(
{'username': request.matchdict['user']}).id username=request.matchdict['user']).first().id
if not (request.user.is_admin or if not (request.user.is_admin or
request.user.id == creator_id): request.user.id == creator_id):
raise Forbidden() raise Forbidden()
@ -165,15 +165,15 @@ def get_user_collection(controller):
""" """
@wraps(controller) @wraps(controller)
def wrapper(request, *args, **kwargs): def wrapper(request, *args, **kwargs):
user = request.db.User.find_one( user = request.db.User.query.filter_by(
{'username': request.matchdict['user']}) username=request.matchdict['user']).first()
if not user: if not user:
return render_404(request) return render_404(request)
collection = request.db.Collection.find_one( collection = request.db.Collection.query.filter_by(
{'slug': request.matchdict['collection'], slug=request.matchdict['collection'],
'creator': user.id}) creator=user.id).first()
# Still no collection? Okay, 404. # Still no collection? Okay, 404.
if not collection: if not collection:
@ -190,14 +190,14 @@ def get_user_collection_item(controller):
""" """
@wraps(controller) @wraps(controller)
def wrapper(request, *args, **kwargs): def wrapper(request, *args, **kwargs):
user = request.db.User.find_one( user = request.db.User.query.filter_by(
{'username': request.matchdict['user']}) username=request.matchdict['user']).first()
if not user: if not user:
return render_404(request) return render_404(request)
collection_item = request.db.CollectionItem.find_one( collection_item = request.db.CollectionItem.query.filter_by(
{'id': request.matchdict['collection_item'] }) id=request.matchdict['collection_item']).first()
# Still no collection item? Okay, 404. # Still no collection item? Okay, 404.
if not collection_item: if not collection_item:

View File

@ -66,7 +66,6 @@ class EditAccountForm(wtforms.Form):
[wtforms.validators.Optional(), [wtforms.validators.Optional(),
normalize_user_or_email_field(allow_user=False)]) normalize_user_or_email_field(allow_user=False)])
wants_comment_notification = wtforms.BooleanField( wants_comment_notification = wtforms.BooleanField(
label='',
description=_("Email me when others comment on my media")) description=_("Email me when others comment on my media"))
license_preference = wtforms.SelectField( license_preference = wtforms.SelectField(
_('License preference'), _('License preference'),

View File

@ -305,9 +305,9 @@ def edit_collection(request, collection):
form.slug.data, collection.id) form.slug.data, collection.id)
# Make sure there isn't already a Collection with this title # Make sure there isn't already a Collection with this title
existing_collection = request.db.Collection.find_one({ existing_collection = request.db.Collection.query.filter_by(
'creator': request.user.id, creator=request.user.id,
'title':form.title.data}) title=form.title.data).first()
if existing_collection and existing_collection.id != collection.id: if existing_collection and existing_collection.id != collection.id:
messages.add_message( messages.add_message(

View File

@ -42,7 +42,7 @@ class DatabaseData(object):
self.name, self.models, self.migrations, session) self.name, self.models, self.migrations, session)
def gather_database_data(media_types, plugins): def gather_database_data(plugins):
""" """
Gather all database data relevant to the extensions we have Gather all database data relevant to the extensions we have
installed so we can do migrations and table initialization. installed so we can do migrations and table initialization.
@ -59,13 +59,6 @@ def gather_database_data(media_types, plugins):
DatabaseData( DatabaseData(
u'__main__', MAIN_MODELS, MAIN_MIGRATIONS)) u'__main__', MAIN_MODELS, MAIN_MIGRATIONS))
# Then get all registered media managers (eventually, plugins)
for media_type in media_types:
models = import_component('%s.models:MODELS' % media_type)
migrations = import_component('%s.migrations:MIGRATIONS' % media_type)
managed_dbdata.append(
DatabaseData(media_type, models, migrations))
for plugin in plugins: for plugin in plugins:
try: try:
models = import_component('{0}.models:MODELS'.format(plugin)) models = import_component('{0}.models:MODELS'.format(plugin))
@ -127,7 +120,6 @@ def run_all_migrations(db, app_config, global_config):
""" """
# Gather information from all media managers / projects # Gather information from all media managers / projects
dbdatas = gather_database_data( dbdatas = gather_database_data(
app_config['media_types'],
global_config.get('plugins', {}).keys()) global_config.get('plugins', {}).keys())
Session = sessionmaker(bind=db.engine) Session = sessionmaker(bind=db.engine)

View File

@ -63,7 +63,7 @@ def _import_media(db, args):
# TODO: Add import of queue files # TODO: Add import of queue files
queue_cache = BasicFileStorage(args._cache_path['queue']) queue_cache = BasicFileStorage(args._cache_path['queue'])
for entry in db.MediaEntry.find(): for entry in db.MediaEntry.query.filter_by():
for name, path in entry.media_files.items(): for name, path in entry.media_files.items():
_log.info('Importing: {0} - {1}'.format( _log.info('Importing: {0} - {1}'.format(
entry.title.encode('ascii', 'replace'), entry.title.encode('ascii', 'replace'),
@ -204,7 +204,7 @@ def _export_media(db, args):
# TODO: Add export of queue files # TODO: Add export of queue files
queue_cache = BasicFileStorage(args._cache_path['queue']) queue_cache = BasicFileStorage(args._cache_path['queue'])
for entry in db.MediaEntry.find(): for entry in db.MediaEntry.query.filter_by():
for name, path in entry.media_files.items(): for name, path in entry.media_files.items():
_log.info(u'Exporting {0} - {1}'.format( _log.info(u'Exporting {0} - {1}'.format(
entry.title, entry.title,

View File

@ -40,9 +40,9 @@ def adduser(args):
db = mg_globals.database db = mg_globals.database
users_with_username = \ users_with_username = \
db.User.find({ db.User.query.filter_by(
'username': args.username.lower(), username=args.username.lower()
}).count() ).count()
if users_with_username: if users_with_username:
print u'Sorry, a user with that name already exists.' print u'Sorry, a user with that name already exists.'
@ -71,7 +71,8 @@ def makeadmin(args):
db = mg_globals.database db = mg_globals.database
user = db.User.one({'username': unicode(args.username.lower())}) user = db.User.query.filter_by(
username=unicode(args.username.lower())).one()
if user: if user:
user.is_admin = True user.is_admin = True
user.save() user.save()
@ -94,7 +95,8 @@ def changepw(args):
db = mg_globals.database db = mg_globals.database
user = db.User.one({'username': unicode(args.username.lower())}) user = db.User.query.filter_by(
username=unicode(args.username.lower())).one()
if user: if user:
user.pw_hash = auth.gen_password_hash(args.password) user.pw_hash = auth.gen_password_hash(args.password)
user.save() user.save()

View File

@ -14,6 +14,7 @@
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from mediagoblin import mg_globals
from mediagoblin.db.models import MediaEntry from mediagoblin.db.models import MediaEntry
from mediagoblin.db.util import media_entries_for_tag_slug from mediagoblin.db.util import media_entries_for_tag_slug
from mediagoblin.tools.pagination import Pagination from mediagoblin.tools.pagination import Pagination
@ -80,6 +81,17 @@ def atom_feed(request):
link = request.urlgen('index', qualified=True) link = request.urlgen('index', qualified=True)
feed_title += "for all recent items" feed_title += "for all recent items"
atomlinks = [
{'href': link,
'rel': 'alternate',
'type': 'text/html'}]
if mg_globals.app_config["push_urls"]:
for push_url in mg_globals.app_config["push_urls"]:
atomlinks.append({
'rel': 'hub',
'href': push_url})
cursor = cursor.order_by(MediaEntry.created.desc()) cursor = cursor.order_by(MediaEntry.created.desc())
cursor = cursor.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) cursor = cursor.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS)
@ -87,9 +99,8 @@ def atom_feed(request):
feed_title, feed_title,
feed_url=request.url, feed_url=request.url,
id=link, id=link,
links=[{'href': link, links=atomlinks)
'rel': 'alternate',
'type': 'text/html'}])
for entry in cursor: for entry in cursor:
feed.add(entry.get('title'), feed.add(entry.get('title'),
entry.description_html, entry.description_html,

View File

@ -15,12 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import sys
import logging import logging
import tempfile import tempfile
from mediagoblin import mg_globals from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.tools.common import import_component
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
@ -52,36 +50,6 @@ class MediaManagerBase(object):
return hasattr(self, i) return hasattr(self, i)
class CompatMediaManager(object):
def __init__(self, mm_dict, entry=None):
self.mm_dict = mm_dict
self.entry = entry
def __call__(self, entry):
"So this object can look like a class too, somehow"
assert self.entry is None
return self.__class__(self.mm_dict, entry)
def __getitem__(self, i):
return self.mm_dict[i]
def __contains__(self, i):
return (i in self.mm_dict)
@property
def media_fetch_order(self):
return self.mm_dict.get('media_fetch_order')
def sniff_handler(self, *args, **kwargs):
func = self.mm_dict.get("sniff_handler", None)
if func is not None:
return func(*args, **kwargs)
return False
def __getattr__(self, i):
return self.mm_dict[i]
def sniff_media(media): def sniff_media(media):
''' '''
Iterate through the enabled media types and find those suited Iterate through the enabled media types and find those suited
@ -98,40 +66,18 @@ def sniff_media(media):
media_file.write(media.stream.read()) media_file.write(media.stream.read())
media.stream.seek(0) media.stream.seek(0)
for media_type, manager in get_media_managers(): media_type = hook_handle('sniff_handler', media_file, media=media)
_log.info('Sniffing {0}'.format(media_type)) if media_type:
if manager.sniff_handler(media_file, media=media): _log.info('{0} accepts the file'.format(media_type))
_log.info('{0} accepts the file'.format(media_type)) return media_type, hook_handle(('media_manager', media_type))
return media_type, manager else:
else: _log.debug('{0} did not accept the file'.format(media_type))
_log.debug('{0} did not accept the file'.format(media_type))
raise FileTypeNotSupported( raise FileTypeNotSupported(
# TODO: Provide information on which file types are supported # TODO: Provide information on which file types are supported
_(u'Sorry, I don\'t support that file type :(')) _(u'Sorry, I don\'t support that file type :('))
def get_media_types():
"""
Generator, yields the available media types
"""
for media_type in mg_globals.app_config['media_types']:
yield media_type
def get_media_managers():
'''
Generator, yields all enabled media managers
'''
for media_type in get_media_types():
mm = import_component(media_type + ":MEDIA_MANAGER")
if isinstance(mm, dict):
mm = CompatMediaManager(mm)
yield media_type, mm
def get_media_type_and_manager(filename): def get_media_type_and_manager(filename):
''' '''
Try to find the media type based on the file name, extension Try to find the media type based on the file name, extension
@ -142,11 +88,10 @@ def get_media_type_and_manager(filename):
# Get the file extension # Get the file extension
ext = os.path.splitext(filename)[1].lower() ext = os.path.splitext(filename)[1].lower()
for media_type, manager in get_media_managers(): # Omit the dot from the extension and match it against
# Omit the dot from the extension and match it against # the media manager
# the media manager if hook_handle('get_media_type_and_manager', ext[1:]):
if ext[1:] in manager.accepted_extensions: return hook_handle('get_media_type_and_manager', ext[1:])
return media_type, manager
else: else:
_log.info('File {0} has no file extension, let\'s hope the sniffers get it.'.format( _log.info('File {0} has no file extension, let\'s hope the sniffers get it.'.format(
filename)) filename))

View File

@ -17,15 +17,31 @@
from mediagoblin.media_types import MediaManagerBase from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.ascii.processing import process_ascii, \ from mediagoblin.media_types.ascii.processing import process_ascii, \
sniff_handler sniff_handler
from mediagoblin.tools import pluginapi
ACCEPTED_EXTENSIONS = ["txt", "asc", "nfo"]
MEDIA_TYPE = 'mediagoblin.media_types.ascii'
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
class ASCIIMediaManager(MediaManagerBase): class ASCIIMediaManager(MediaManagerBase):
human_readable = "ASCII" human_readable = "ASCII"
processor = staticmethod(process_ascii) processor = staticmethod(process_ascii)
sniff_handler = staticmethod(sniff_handler)
display_template = "mediagoblin/media_displays/ascii.html" display_template = "mediagoblin/media_displays/ascii.html"
default_thumb = "images/media_thumbs/ascii.jpg" default_thumb = "images/media_thumbs/ascii.jpg"
accepted_extensions = ["txt", "asc", "nfo"]
MEDIA_MANAGER = ASCIIMediaManager
def get_media_type_and_manager(ext):
if ext in ACCEPTED_EXTENSIONS:
return MEDIA_TYPE, ASCIIMediaManager
hooks = {
'setup': setup_plugin,
'get_media_type_and_manager': get_media_type_and_manager,
('media_manager', MEDIA_TYPE): lambda: ASCIIMediaManager,
'sniff_handler': sniff_handler,
}

View File

@ -28,17 +28,19 @@ from mediagoblin.media_types.ascii import asciitoimage
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
SUPPORTED_EXTENSIONS = ['txt', 'asc', 'nfo'] SUPPORTED_EXTENSIONS = ['txt', 'asc', 'nfo']
MEDIA_TYPE = 'mediagoblin.media_types.ascii'
def sniff_handler(media_file, **kw): def sniff_handler(media_file, **kw):
_log.info('Sniffing {0}'.format(MEDIA_TYPE))
if kw.get('media') is not None: if kw.get('media') is not None:
name, ext = os.path.splitext(kw['media'].filename) name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower() clean_ext = ext[1:].lower()
if clean_ext in SUPPORTED_EXTENSIONS: if clean_ext in SUPPORTED_EXTENSIONS:
return True return MEDIA_TYPE
return False return None
def process_ascii(proc_state): def process_ascii(proc_state):

View File

@ -17,14 +17,29 @@
from mediagoblin.media_types import MediaManagerBase from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.audio.processing import process_audio, \ from mediagoblin.media_types.audio.processing import process_audio, \
sniff_handler sniff_handler
from mediagoblin.tools import pluginapi
ACCEPTED_EXTENSIONS = ["mp3", "flac", "wav", "m4a"]
MEDIA_TYPE = 'mediagoblin.media_types.audio'
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
class AudioMediaManager(MediaManagerBase): class AudioMediaManager(MediaManagerBase):
human_readable = "Audio" human_readable = "Audio"
processor = staticmethod(process_audio) processor = staticmethod(process_audio)
sniff_handler = staticmethod(sniff_handler)
display_template = "mediagoblin/media_displays/audio.html" display_template = "mediagoblin/media_displays/audio.html"
accepted_extensions = ["mp3", "flac", "wav", "m4a"]
MEDIA_MANAGER = AudioMediaManager def get_media_type_and_manager(ext):
if ext in ACCEPTED_EXTENSIONS:
return MEDIA_TYPE, AudioMediaManager
hooks = {
'setup': setup_plugin,
'get_media_type_and_manager': get_media_type_and_manager,
'sniff_handler': sniff_handler,
('media_manager', MEDIA_TYPE): lambda: AudioMediaManager,
}

View File

@ -27,19 +27,22 @@ from mediagoblin.media_types.audio.transcoders import (AudioTranscoder,
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
MEDIA_TYPE = 'mediagoblin.media_types.audio'
def sniff_handler(media_file, **kw): def sniff_handler(media_file, **kw):
_log.info('Sniffing {0}'.format(MEDIA_TYPE))
try: try:
transcoder = AudioTranscoder() transcoder = AudioTranscoder()
data = transcoder.discover(media_file.name) data = transcoder.discover(media_file.name)
except BadMediaFail: except BadMediaFail:
_log.debug('Audio discovery raised BadMediaFail') _log.debug('Audio discovery raised BadMediaFail')
return False return None
if data.is_audio == True and data.is_video == False: if data.is_audio == True and data.is_video == False:
return True return MEDIA_TYPE
return False return None
def process_audio(proc_state): def process_audio(proc_state):

View File

@ -13,23 +13,30 @@
# #
# You should have received a copy of the GNU Affero General Public License # 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import datetime import datetime
from mediagoblin.media_types import MediaManagerBase from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.image.processing import process_image, \ from mediagoblin.media_types.image.processing import process_image, \
sniff_handler sniff_handler
from mediagoblin.tools import pluginapi
ACCEPTED_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "tiff"]
MEDIA_TYPE = 'mediagoblin.media_types.image'
def setup_plugin():
config = pluginapi.get_config('mediagoblin.media_types.image')
class ImageMediaManager(MediaManagerBase): class ImageMediaManager(MediaManagerBase):
human_readable = "Image" human_readable = "Image"
processor = staticmethod(process_image) processor = staticmethod(process_image)
sniff_handler = staticmethod(sniff_handler)
display_template = "mediagoblin/media_displays/image.html" display_template = "mediagoblin/media_displays/image.html"
default_thumb = "images/media_thumbs/image.png" default_thumb = "images/media_thumbs/image.png"
accepted_extensions = ["jpg", "jpeg", "png", "gif", "tiff"]
media_fetch_order = [u'medium', u'original', u'thumb'] media_fetch_order = [u'medium', u'original', u'thumb']
def get_original_date(self): def get_original_date(self):
""" """
Get the original date and time from the EXIF information. Returns Get the original date and time from the EXIF information. Returns
@ -52,4 +59,14 @@ class ImageMediaManager(MediaManagerBase):
return None return None
MEDIA_MANAGER = ImageMediaManager def get_media_type_and_manager(ext):
if ext in ACCEPTED_EXTENSIONS:
return MEDIA_TYPE, ImageMediaManager
hooks = {
'setup': setup_plugin,
'get_media_type_and_manager': get_media_type_and_manager,
'sniff_handler': sniff_handler,
('media_manager', MEDIA_TYPE): lambda: ImageMediaManager,
}

View File

@ -35,6 +35,8 @@ PIL_FILTERS = {
'BICUBIC': Image.BICUBIC, 'BICUBIC': Image.BICUBIC,
'ANTIALIAS': Image.ANTIALIAS} 'ANTIALIAS': Image.ANTIALIAS}
MEDIA_TYPE = 'mediagoblin.media_types.image'
def resize_image(proc_state, resized, keyname, target_name, new_size, def resize_image(proc_state, resized, keyname, target_name, new_size,
exif_tags, workdir): exif_tags, workdir):
@ -95,17 +97,18 @@ def resize_tool(proc_state, force, keyname, target_name,
exif_tags, conversions_subdir) exif_tags, conversions_subdir)
SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg'] SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg', 'tiff']
def sniff_handler(media_file, **kw): def sniff_handler(media_file, **kw):
_log.info('Sniffing {0}'.format(MEDIA_TYPE))
if kw.get('media') is not None: # That's a double negative! if kw.get('media') is not None: # That's a double negative!
name, ext = os.path.splitext(kw['media'].filename) name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower() # Strip the . from ext and make lowercase clean_ext = ext[1:].lower() # Strip the . from ext and make lowercase
if clean_ext in SUPPORTED_FILETYPES: if clean_ext in SUPPORTED_FILETYPES:
_log.info('Found file extension in supported filetypes') _log.info('Found file extension in supported filetypes')
return True return MEDIA_TYPE
else: else:
_log.debug('Media present, extension not found in {0}'.format( _log.debug('Media present, extension not found in {0}'.format(
SUPPORTED_FILETYPES)) SUPPORTED_FILETYPES))
@ -113,7 +116,7 @@ def sniff_handler(media_file, **kw):
_log.warning('Need additional information (keyword argument \'media\')' _log.warning('Need additional information (keyword argument \'media\')'
' to be able to handle sniffing') ' to be able to handle sniffing')
return False return None
def process_image(proc_state): def process_image(proc_state):

View File

@ -17,15 +17,31 @@
from mediagoblin.media_types import MediaManagerBase from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.pdf.processing import process_pdf, \ from mediagoblin.media_types.pdf.processing import process_pdf, \
sniff_handler sniff_handler
from mediagoblin.tools import pluginapi
ACCEPTED_EXTENSIONS = ['pdf']
MEDIA_TYPE = 'mediagoblin.media_types.pdf'
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
class PDFMediaManager(MediaManagerBase): class PDFMediaManager(MediaManagerBase):
human_readable = "PDF" human_readable = "PDF"
processor = staticmethod(process_pdf) processor = staticmethod(process_pdf)
sniff_handler = staticmethod(sniff_handler)
display_template = "mediagoblin/media_displays/pdf.html" display_template = "mediagoblin/media_displays/pdf.html"
default_thumb = "images/media_thumbs/pdf.jpg" default_thumb = "images/media_thumbs/pdf.jpg"
accepted_extensions = ["pdf"]
MEDIA_MANAGER = PDFMediaManager def get_media_type_and_manager(ext):
if ext in ACCEPTED_EXTENSIONS:
return MEDIA_TYPE, PDFMediaManager
hooks = {
'setup': setup_plugin,
'get_media_type_and_manager': get_media_type_and_manager,
'sniff_handler': sniff_handler,
('media_manager', MEDIA_TYPE): lambda: PDFMediaManager,
}

View File

@ -25,6 +25,8 @@ from mediagoblin.tools.translate import fake_ugettext_passthrough as _
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
MEDIA_TYPE = 'mediagoblin.media_types.pdf'
# TODO - cache (memoize) util # TODO - cache (memoize) util
# This is a list created via uniconv --show and hand removing some types that # This is a list created via uniconv --show and hand removing some types that
@ -163,16 +165,17 @@ def check_prerequisites():
return True return True
def sniff_handler(media_file, **kw): def sniff_handler(media_file, **kw):
_log.info('Sniffing {0}'.format(MEDIA_TYPE))
if not check_prerequisites(): if not check_prerequisites():
return False return None
if kw.get('media') is not None: if kw.get('media') is not None:
name, ext = os.path.splitext(kw['media'].filename) name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower() clean_ext = ext[1:].lower()
if clean_ext in supported_extensions(): if clean_ext in supported_extensions():
return True return MEDIA_TYPE
return False return None
def create_pdf_thumb(original, thumb_filename, width, height): def create_pdf_thumb(original, thumb_filename, width, height):
# Note: pdftocairo adds '.png', remove it # Note: pdftocairo adds '.png', remove it

View File

@ -17,15 +17,30 @@
from mediagoblin.media_types import MediaManagerBase from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.stl.processing import process_stl, \ from mediagoblin.media_types.stl.processing import process_stl, \
sniff_handler sniff_handler
from mediagoblin.tools import pluginapi
MEDIA_TYPE = 'mediagoblin.media_types.stl'
ACCEPTED_EXTENSIONS = ["obj", "stl"]
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
class STLMediaManager(MediaManagerBase): class STLMediaManager(MediaManagerBase):
human_readable = "stereo lithographics" human_readable = "stereo lithographics"
processor = staticmethod(process_stl) processor = staticmethod(process_stl)
sniff_handler = staticmethod(sniff_handler)
display_template = "mediagoblin/media_displays/stl.html" display_template = "mediagoblin/media_displays/stl.html"
default_thumb = "images/media_thumbs/video.jpg" default_thumb = "images/media_thumbs/video.jpg"
accepted_extensions = ["obj", "stl"]
MEDIA_MANAGER = STLMediaManager def get_media_type_and_manager(ext):
if ext in ACCEPTED_EXTENSIONS:
return MEDIA_TYPE, STLMediaManager
hooks = {
'setup': setup_plugin,
'get_media_type_and_manager': get_media_type_and_manager,
'sniff_handler': sniff_handler,
('media_manager', MEDIA_TYPE): lambda: STLMediaManager,
}

View File

@ -29,6 +29,7 @@ from mediagoblin.media_types.stl import model_loader
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
SUPPORTED_FILETYPES = ['stl', 'obj'] SUPPORTED_FILETYPES = ['stl', 'obj']
MEDIA_TYPE = 'mediagoblin.media_types.stl'
BLEND_FILE = pkg_resources.resource_filename( BLEND_FILE = pkg_resources.resource_filename(
'mediagoblin.media_types.stl', 'mediagoblin.media_types.stl',
@ -43,13 +44,14 @@ BLEND_SCRIPT = pkg_resources.resource_filename(
def sniff_handler(media_file, **kw): def sniff_handler(media_file, **kw):
_log.info('Sniffing {0}'.format(MEDIA_TYPE))
if kw.get('media') is not None: if kw.get('media') is not None:
name, ext = os.path.splitext(kw['media'].filename) name, ext = os.path.splitext(kw['media'].filename)
clean_ext = ext[1:].lower() clean_ext = ext[1:].lower()
if clean_ext in SUPPORTED_FILETYPES: if clean_ext in SUPPORTED_FILETYPES:
_log.info('Found file extension in supported filetypes') _log.info('Found file extension in supported filetypes')
return True return MEDIA_TYPE
else: else:
_log.debug('Media present, extension not found in {0}'.format( _log.debug('Media present, extension not found in {0}'.format(
SUPPORTED_FILETYPES)) SUPPORTED_FILETYPES))
@ -57,7 +59,7 @@ def sniff_handler(media_file, **kw):
_log.warning('Need additional information (keyword argument \'media\')' _log.warning('Need additional information (keyword argument \'media\')'
' to be able to handle sniffing') ' to be able to handle sniffing')
return False return None
def blender_render(config): def blender_render(config):

View File

@ -0,0 +1,27 @@
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
#
# 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 logging
from mediagoblin import mg_globals
_log = logging.getLogger(__name__)
def media_type_warning():
if mg_globals.app_config.get('media_types'):
_log.warning('Media_types have been converted to plugins. Old'
' media_types will no longer work. Please convert them'
' to plugins to continue using them.')

View File

@ -17,20 +17,35 @@
from mediagoblin.media_types import MediaManagerBase from mediagoblin.media_types import MediaManagerBase
from mediagoblin.media_types.video.processing import process_video, \ from mediagoblin.media_types.video.processing import process_video, \
sniff_handler sniff_handler
from mediagoblin.tools import pluginapi
MEDIA_TYPE = 'mediagoblin.media_types.video'
ACCEPTED_EXTENSIONS = [
"mp4", "mov", "webm", "avi", "3gp", "3gpp", "mkv", "ogv", "m4v"]
def setup_plugin():
config = pluginapi.get_config(MEDIA_TYPE)
class VideoMediaManager(MediaManagerBase): class VideoMediaManager(MediaManagerBase):
human_readable = "Video" human_readable = "Video"
processor = staticmethod(process_video) processor = staticmethod(process_video)
sniff_handler = staticmethod(sniff_handler)
display_template = "mediagoblin/media_displays/video.html" display_template = "mediagoblin/media_displays/video.html"
default_thumb = "images/media_thumbs/video.jpg" default_thumb = "images/media_thumbs/video.jpg"
accepted_extensions = [
"mp4", "mov", "webm", "avi", "3gp", "3gpp", "mkv", "ogv", "m4v"]
# Used by the media_entry.get_display_media method # Used by the media_entry.get_display_media method
media_fetch_order = [u'webm_640', u'original'] media_fetch_order = [u'webm_640', u'original']
default_webm_type = 'video/webm; codecs="vp8, vorbis"' default_webm_type = 'video/webm; codecs="vp8, vorbis"'
MEDIA_MANAGER = VideoMediaManager def get_media_type_and_manager(ext):
if ext in ACCEPTED_EXTENSIONS:
return MEDIA_TYPE, VideoMediaManager
hooks = {
'setup': setup_plugin,
'get_media_type_and_manager': get_media_type_and_manager,
'sniff_handler': sniff_handler,
('media_manager', MEDIA_TYPE): lambda: VideoMediaManager,
}

View File

@ -29,6 +29,8 @@ from .util import skip_transcode
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG) _log.setLevel(logging.DEBUG)
MEDIA_TYPE = 'mediagoblin.media_types.video'
class VideoTranscodingFail(BaseProcessingFail): class VideoTranscodingFail(BaseProcessingFail):
''' '''
@ -41,17 +43,18 @@ def sniff_handler(media_file, **kw):
transcoder = transcoders.VideoTranscoder() transcoder = transcoders.VideoTranscoder()
data = transcoder.discover(media_file.name) data = transcoder.discover(media_file.name)
_log.info('Sniffing {0}'.format(MEDIA_TYPE))
_log.debug('Discovered: {0}'.format(data)) _log.debug('Discovered: {0}'.format(data))
if not data: if not data:
_log.error('Could not discover {0}'.format( _log.error('Could not discover {0}'.format(
kw.get('media'))) kw.get('media')))
return False return None
if data['is_video'] == True: if data['is_video'] == True:
return True return MEDIA_TYPE
return False return None
def process_video(proc_state): def process_video(proc_state):
@ -186,7 +189,7 @@ def store_metadata(media_entry, metadata):
[(key, tags_metadata[key]) [(key, tags_metadata[key])
for key in [ for key in [
"application-name", "artist", "audio-codec", "bitrate", "application-name", "artist", "audio-codec", "bitrate",
"container-format", "copyright", "encoder", "container-format", "copyright", "encoder",
"encoder-version", "license", "nominal-bitrate", "title", "encoder-version", "license", "nominal-bitrate", "title",
"video-codec"] "video-codec"]
if key in tags_metadata]) if key in tags_metadata])
@ -203,7 +206,7 @@ def store_metadata(media_entry, metadata):
dt.get_year(), dt.get_month(), dt.get_day(), dt.get_hour(), dt.get_year(), dt.get_month(), dt.get_day(), dt.get_hour(),
dt.get_minute(), dt.get_second(), dt.get_minute(), dt.get_second(),
dt.get_microsecond()).isoformat() dt.get_microsecond()).isoformat()
metadata['tags'] = tags metadata['tags'] = tags
# Only save this field if there's something to save # Only save this field if there's something to save

View File

@ -41,3 +41,6 @@ class LoginForm(wtforms.Form):
normalize_user_or_email_field()]) normalize_user_or_email_field()])
password = wtforms.PasswordField( password = wtforms.PasswordField(
_('Password')) _('Password'))
stay_logged_in = wtforms.BooleanField(
label='',
description=_('Stay logged in'))

View File

@ -334,6 +334,10 @@ text-align: center;
width: 20px; width: 20px;
} }
.boolean {
margin-bottom: 8px;
}
textarea#description, textarea#bio { textarea#description, textarea#bio {
resize: vertical; resize: vertical;
height: 100px; height: 100px;

View File

@ -19,6 +19,7 @@ import mediagoblin.mg_globals as mg_globals
from os.path import splitext from os.path import splitext
import logging import logging
import uuid
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
@ -53,6 +54,10 @@ def submit_start(request):
try: try:
filename = request.files['file'].filename filename = request.files['file'].filename
# If the filename contains non ascii generate a unique name
if not all(ord(c) < 128 for c in filename):
filename = unicode(uuid.uuid4()) + splitext(filename)[-1]
# Sniff the submitted media to determine which # Sniff the submitted media to determine which
# media plugin should handle processing # media plugin should handle processing
media_type, media_manager = sniff_media( media_type, media_manager = sniff_media(
@ -63,7 +68,7 @@ def submit_start(request):
entry.media_type = unicode(media_type) entry.media_type = unicode(media_type)
entry.title = ( entry.title = (
unicode(submit_form.title.data) unicode(submit_form.title.data)
or unicode(splitext(filename)[0])) or unicode(splitext(request.files['file'].filename)[0]))
entry.description = unicode(submit_form.description.data) entry.description = unicode(submit_form.description.data)
@ -133,9 +138,9 @@ def add_collection(request, media=None):
collection.generate_slug() collection.generate_slug()
# Make sure this user isn't duplicating an existing collection # Make sure this user isn't duplicating an existing collection
existing_collection = request.db.Collection.find_one({ existing_collection = request.db.Collection.query.filter_by(
'creator': request.user.id, creator=request.user.id,
'title':collection.title}) title=collection.title).first()
if existing_collection: if existing_collection:
add_message(request, messages.ERROR, add_message(request, messages.ERROR,

View File

@ -39,7 +39,7 @@
Changing {{ username }}'s password Changing {{ username }}'s password
{%- endtrans -%} {%- endtrans -%}
</h1> </h1>
{{ wtforms_util.render_divs(form) }} {{ wtforms_util.render_divs(form, True) }}
{{ csrf_token }} {{ csrf_token }}
<div class="form_submit_buttons"> <div class="form_submit_buttons">
<input type="submit" value="{% trans %}Save{% endtrans %}" <input type="submit" value="{% trans %}Save{% endtrans %}"

View File

@ -108,32 +108,26 @@ window.show_things = function () {
<div style="padding: 4px;"> <div style="padding: 4px;">
<a class="button_action" onclick="show('perspective');" <a class="button_action" onclick="show('perspective');">
title="{%- trans %}Toggle Rotate{% endtrans -%}">
{%- trans %}Perspective{% endtrans -%} {%- trans %}Perspective{% endtrans -%}
</a> </a>
<a class="button_action" onclick="show('front_view');" <a class="button_action" onclick="show('front_view');">
title="{%- trans %}Front{% endtrans -%}">
{%- trans %}Front{% endtrans -%} {%- trans %}Front{% endtrans -%}
</a> </a>
<a class="button_action" onclick="show('top_view');" <a class="button_action" onclick="show('top_view');">
title="{%- trans %}Top{% endtrans -%}">
{%- trans %}Top{% endtrans -%} {%- trans %}Top{% endtrans -%}
</a> </a>
<a class="button_action" onclick="show('side_view');" <a class="button_action" onclick="show('side_view');">
title="{%- trans %}Side{% endtrans -%}">
{%- trans %}Side{% endtrans -%} {%- trans %}Side{% endtrans -%}
</a> </a>
{% if media.media_data.file_type == "stl" %} {% if media.media_data.file_type == "stl" %}
<a id="webgl_button" class="button_action" <a id="webgl_button" class="button_action"
onclick="show_things();" onclick="show_things();">
title="{%- trans %}WebGL{% endtrans -%}">
{%- trans %}WebGL{% endtrans -%} {%- trans %}WebGL{% endtrans -%}
</a> </a>
{% endif %} {% endif %}
<a class="button_action" href="{{ model_download }}" <a class="button_action" href="{{ model_download }}"
title="{%- trans %}Download{% endtrans -%}"
style="float:right;"> style="float:right;">
{%- trans %}Download model{% endtrans -%} {%- trans %}Download model{% endtrans -%}
</a> </a>

View File

@ -21,13 +21,13 @@
{% if not subscription or not subscription.notify %} {% if not subscription or not subscription.notify %}
<a type="submit" href="{{ request.urlgen('mediagoblin.notifications.subscribe_comments', <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.subscribe_comments',
user=media.get_uploader.username, user=media.get_uploader.username,
media=media.slug)}}" media=media.slug_or_id)}}"
class="button_action">Subscribe to comments class="button_action">Subscribe to comments
</a> </a>
{% else %} {% else %}
<a type="submit" href="{{ request.urlgen('mediagoblin.notifications.silence_comments', <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.silence_comments',
user=media.get_uploader.username, user=media.get_uploader.username,
media=media.slug)}}" media=media.slug_or_id)}}"
class="button_action">Silence comments class="button_action">Silence comments
</a> </a>
{% endif %} {% endif %}

View File

@ -34,26 +34,26 @@
{# Generically render a field #} {# Generically render a field #}
{% macro render_field_div(field, autofocus_first=False) %} {% macro render_field_div(field, autofocus_first=False) %}
{{- render_label_p(field) }} {% if field.type == 'BooleanField' %}
<div class="form_field_input"> {{ render_bool(field) }}
{% if autofocus_first %} {% else %}
{{ field(autofocus=True) }} {{- render_label_p(field) }}
{% else %} <div class="form_field_input">
{{ field }} {% if autofocus_first %}
{% endif %} {{ field(autofocus=True) }}
{%- if field.errors -%}
{% for error in field.errors %}
<p class="form_field_error">{{ error }}</p>
{% endfor %}
{%- endif %}
{%- if field.description %}
{% if field.type == 'BooleanField' %}
<label for="{{ field.label.field_id }}">{{ field.description|safe }}</label>
{% else %} {% else %}
<p class="form_field_description">{{ field.description|safe }}</p> {{ field }}
{% endif %} {% endif %}
{%- endif %} {%- if field.errors -%}
</div> {% for error in field.errors %}
<p class="form_field_error">{{ error }}</p>
{% endfor %}
{%- endif %}
{%- if field.description %}
<p class="form_field_description">{{ field.description|safe }}</p>
{%- endif %}
</div>
{% endif %}
{%- endmacro %} {%- endmacro %}
{# Auto-render a form as a series of divs #} {# Auto-render a form as a series of divs #}
@ -86,3 +86,19 @@
</tr> </tr>
{% endfor %} {% endfor %}
{%- endmacro %} {%- endmacro %}
{# Render a boolean field #}
{% macro render_bool(field) %}
<div class="boolean">
<label for="{{ field.label.field_id }}">
{{ field }}</input>
{{ field.description|safe }}
</label>
{%- if field.errors -%}
{% for error in field.errors %}
<p class="form_field_error">{{ error }}</p>
{% endfor %}
{% endif %}
</div>
{% endmacro %}

View File

@ -93,8 +93,8 @@ def test_register_views(test_app):
assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT
## Make sure user is in place ## Make sure user is in place
new_user = mg_globals.database.User.find_one( new_user = mg_globals.database.User.query.filter_by(
{'username': u'happygirl'}) username=u'happygirl').first()
assert new_user assert new_user
assert new_user.status == u'needs_email_verification' assert new_user.status == u'needs_email_verification'
assert new_user.email_verified == False assert new_user.email_verified == False
@ -128,8 +128,8 @@ def test_register_views(test_app):
# assert context['verification_successful'] == True # assert context['verification_successful'] == True
# TODO: Would be good to test messages here when we can do so... # TODO: Would be good to test messages here when we can do so...
new_user = mg_globals.database.User.find_one( new_user = mg_globals.database.User.query.filter_by(
{'username': u'happygirl'}) username=u'happygirl').first()
assert new_user assert new_user
assert new_user.status == u'needs_email_verification' assert new_user.status == u'needs_email_verification'
assert new_user.email_verified == False assert new_user.email_verified == False
@ -142,8 +142,8 @@ def test_register_views(test_app):
'mediagoblin/user_pages/user.html'] 'mediagoblin/user_pages/user.html']
# assert context['verification_successful'] == True # assert context['verification_successful'] == True
# TODO: Would be good to test messages here when we can do so... # TODO: Would be good to test messages here when we can do so...
new_user = mg_globals.database.User.find_one( new_user = mg_globals.database.User.query.filter_by(
{'username': u'happygirl'}) username=u'happygirl').first()
assert new_user assert new_user
assert new_user.status == u'active' assert new_user.status == u'active'
assert new_user.email_verified == True assert new_user.email_verified == True

View File

@ -190,8 +190,8 @@ class TestUserEdit(object):
assert urlparse.urlsplit(res.location)[2] == '/' assert urlparse.urlsplit(res.location)[2] == '/'
# Email shouldn't be saved # Email shouldn't be saved
email_in_db = mg_globals.database.User.find_one( email_in_db = mg_globals.database.User.query.filter_by(
{'email': 'new@example.com'}) email='new@example.com').first()
email = User.query.filter_by(username='chris').first().email email = User.query.filter_by(username='chris').first().email
assert email_in_db is None assert email_in_db is None
assert email == 'chris@example.com' assert email == 'chris@example.com'

View File

@ -13,8 +13,6 @@ tags_max_length = 50
# So we can start to test attachments: # So we can start to test attachments:
allow_attachments = True allow_attachments = True
media_types = mediagoblin.media_types.image, mediagoblin.media_types.pdf
[storage:publicstore] [storage:publicstore]
base_dir = %(here)s/user_dev/media/public base_dir = %(here)s/user_dev/media/public
base_url = /mgoblin_media/ base_url = /mgoblin_media/
@ -34,3 +32,5 @@ BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
[[mediagoblin.plugins.piwigo]] [[mediagoblin.plugins.piwigo]]
[[mediagoblin.plugins.basic_auth]] [[mediagoblin.plugins.basic_auth]]
[[mediagoblin.plugins.openid]] [[mediagoblin.plugins.openid]]
[[mediagoblin.media_types.image]]
[[mediagoblin.media_types.pdf]]

View File

@ -186,8 +186,8 @@ class TestOpenIDPlugin(object):
openid_plugin_app.get('/auth/logout') openid_plugin_app.get('/auth/logout')
# Get user and detach from session # Get user and detach from session
test_user = mg_globals.database.User.find_one({ test_user = mg_globals.database.User.query.filter_by(
'username': u'chris'}) username=u'chris').first()
Session.expunge(test_user) Session.expunge(test_user)
# Log back in # Log back in
@ -314,8 +314,8 @@ class TestOpenIDPlugin(object):
assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
# OpenID Added? # OpenID Added?
new_openid = mg_globals.database.OpenIDUserURL.find_one( new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
{'openid_url': u'http://add.myopenid.com'}) openid_url=u'http://add.myopenid.com').first()
assert new_openid assert new_openid
_test_add() _test_add()
@ -365,8 +365,8 @@ class TestOpenIDPlugin(object):
assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
# OpenID deleted? # OpenID deleted?
new_openid = mg_globals.database.OpenIDUserURL.find_one( new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
{'openid_url': u'http://add.myopenid.com'}) openid_url=u'http://add.myopenid.com').first()
assert not new_openid assert not new_openid
_test_delete(self, test_user) _test_delete(self, test_user)

View File

@ -26,7 +26,7 @@ from mediagoblin.tests.tools import fixture_add_user
from mediagoblin import mg_globals from mediagoblin import mg_globals
from mediagoblin.db.models import MediaEntry from mediagoblin.db.models import MediaEntry
from mediagoblin.tools import template from mediagoblin.tools import template
from mediagoblin.media_types.image import MEDIA_MANAGER as img_MEDIA_MANAGER from mediagoblin.media_types.image import ImageMediaManager
from mediagoblin.media_types.pdf.processing import check_prerequisites as pdf_check_prerequisites from mediagoblin.media_types.pdf.processing import check_prerequisites as pdf_check_prerequisites
from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \ from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
@ -77,7 +77,7 @@ class TestSubmission:
return {'upload_files': [('file', filename)]} return {'upload_files': [('file', filename)]}
def check_comments(self, request, media_id, count): def check_comments(self, request, media_id, count):
comments = request.db.MediaComment.find({'media_entry': media_id}) comments = request.db.MediaComment.query.filter_by(media_entry=media_id)
assert count == len(list(comments)) assert count == len(list(comments))
def test_missing_fields(self): def test_missing_fields(self):
@ -122,7 +122,7 @@ class TestSubmission:
assert 'mediagoblin/user_pages/user.html' in context assert 'mediagoblin/user_pages/user.html' in context
def check_media(self, request, find_data, count=None): def check_media(self, request, find_data, count=None):
media = MediaEntry.find(find_data) media = MediaEntry.query.filter_by(**find_data)
if count is not None: if count is not None:
assert media.count() == count assert media.count() == count
if count == 0: if count == 0:
@ -219,7 +219,7 @@ class TestSubmission:
media = self.check_media(request, {'title': u'Balanced Goblin'}, 1) media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
assert media.media_type == u'mediagoblin.media_types.image' assert media.media_type == u'mediagoblin.media_types.image'
assert isinstance(media.media_manager, img_MEDIA_MANAGER) assert isinstance(media.media_manager, ImageMediaManager)
assert media.media_manager.entry == media assert media.media_manager.entry == media
@ -240,8 +240,8 @@ class TestSubmission:
request = context['request'] request = context['request']
media = request.db.MediaEntry.find_one({ media = request.db.MediaEntry.query.filter_by(
u'title': u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE'}) title=u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE').first()
assert media.media_type == 'mediagoblin.media_types.image' assert media.media_type == 'mediagoblin.media_types.image'
@ -252,7 +252,7 @@ class TestSubmission:
response, context = self.do_post({'title': title}, do_follow=True, response, context = self.do_post({'title': title}, do_follow=True,
**self.upload_data(filename)) **self.upload_data(filename))
self.check_url(response, '/u/{0}/'.format(self.test_user.username)) self.check_url(response, '/u/{0}/'.format(self.test_user.username))
entry = mg_globals.database.MediaEntry.find_one({'title': title}) entry = mg_globals.database.MediaEntry.query.filter_by(title=title).first()
assert entry.state == 'failed' assert entry.state == 'failed'
assert entry.fail_error == u'mediagoblin.processing:BadMediaFail' assert entry.fail_error == u'mediagoblin.processing:BadMediaFail'

View File

@ -164,7 +164,7 @@ def assert_db_meets_expected(db, expected):
for collection_name, collection_data in expected.iteritems(): for collection_name, collection_data in expected.iteritems():
collection = db[collection_name] collection = db[collection_name]
for expected_document in collection_data: for expected_document in collection_data:
document = collection.find_one({'id': expected_document['id']}) document = collection.query.filter_by(id=expected_document['id']).first()
assert document is not None # make sure it exists assert document is not None # make sure it exists
assert document == expected_document # make sure it matches assert document == expected_document # make sure it matches

View File

@ -21,6 +21,8 @@ import crypto
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
MAX_AGE = 30 * 24 * 60 * 60
class Session(dict): class Session(dict):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.send_new_cookie = False self.send_new_cookie = False
@ -64,5 +66,10 @@ class SessionManager(object):
elif not session: elif not session:
response.delete_cookie(self.cookie_name) response.delete_cookie(self.cookie_name)
else: else:
if session.get('stay_logged_in', False):
max_age = MAX_AGE
else:
max_age = None
response.set_cookie(self.cookie_name, self.signer.dumps(session), response.set_cookie(self.cookie_name, self.signer.dumps(session),
httponly=True) max_age=max_age, httponly=True)

View File

@ -142,7 +142,7 @@ def media_home(request, media, page, **kwargs):
comment_form = user_forms.MediaCommentForm(request.form) comment_form = user_forms.MediaCommentForm(request.form)
media_template_name = media.media_manager['display_template'] media_template_name = media.media_manager.display_template
return render_to_response( return render_to_response(
request, request,