Merge branch 'master' of git://gitorious.org/mediagoblin/mediagoblin
authorxray7224 <xray7224@googlemail.com>
Sun, 14 Jul 2013 14:27:52 +0000 (15:27 +0100)
committerxray7224 <xray7224@googlemail.com>
Sun, 14 Jul 2013 14:27:52 +0000 (15:27 +0100)
48 files changed:
docs/source/index.rst
docs/source/pluginwriter/media_type_hooks.rst [new file with mode: 0644]
docs/source/siteadmin/media-types.rst
mediagoblin.ini
mediagoblin/app.py
mediagoblin/auth/views.py
mediagoblin/config_spec.ini
mediagoblin/db/base.py
mediagoblin/db/migration_tools.py
mediagoblin/db/mixin.py
mediagoblin/db/open.py
mediagoblin/db/util.py
mediagoblin/decorators.py
mediagoblin/edit/forms.py
mediagoblin/edit/views.py
mediagoblin/gmg_commands/dbupdate.py
mediagoblin/gmg_commands/import_export.py
mediagoblin/gmg_commands/users.py
mediagoblin/listings/views.py
mediagoblin/media_types/__init__.py
mediagoblin/media_types/ascii/__init__.py
mediagoblin/media_types/ascii/processing.py
mediagoblin/media_types/audio/__init__.py
mediagoblin/media_types/audio/processing.py
mediagoblin/media_types/image/__init__.py
mediagoblin/media_types/image/processing.py
mediagoblin/media_types/pdf/__init__.py
mediagoblin/media_types/pdf/processing.py
mediagoblin/media_types/stl/__init__.py
mediagoblin/media_types/stl/processing.py
mediagoblin/media_types/tools.py [new file with mode: 0644]
mediagoblin/media_types/video/__init__.py
mediagoblin/media_types/video/processing.py
mediagoblin/plugins/basic_auth/forms.py
mediagoblin/static/css/base.css
mediagoblin/submit/views.py
mediagoblin/templates/mediagoblin/edit/change_pass.html
mediagoblin/templates/mediagoblin/media_displays/stl.html
mediagoblin/templates/mediagoblin/utils/comment-subscription.html
mediagoblin/templates/mediagoblin/utils/wtforms.html
mediagoblin/tests/test_auth.py
mediagoblin/tests/test_edit.py
mediagoblin/tests/test_mgoblin_app.ini
mediagoblin/tests/test_openid.py
mediagoblin/tests/test_submission.py
mediagoblin/tests/tools.py
mediagoblin/tools/session.py
mediagoblin/user_pages/views.py

index c8a3f040ccb56955daef5a13e07e350f22cc3727..de6c9c0d7795362ac5ba957602264fad0b741ef7 100644 (file)
@@ -74,6 +74,7 @@ This guide covers writing new GNU MediaGoblin plugins.
    pluginwriter/database
    pluginwriter/api
    pluginwriter/tests
+   pluginwriter/media_type_hooks
 
 
 Part 4: Developer's Zone
diff --git a/docs/source/pluginwriter/media_type_hooks.rst b/docs/source/pluginwriter/media_type_hooks.rst
new file mode 100644 (file)
index 0000000..498b0b5
--- /dev/null
@@ -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.
index 1527bc70528616e8cd2ff4123b149a012134b799..3e8a94e9e5ade4156ed9c8188330dd009e067986 100644 (file)
@@ -18,16 +18,18 @@ Media Types
 ====================
 
 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
-and ascii art.
+but in the meanwhile there are five additional media types: video, audio,
+ascii art, STL/3d models, PDF and Document.
 
 First, you should probably read ":doc:`configuration`" to make sure
 you know how to modify the mediagoblin config file.
 
-
 Enabling Media Types
 ====================
 
+.. note::
+    Media types are now plugins
+
 Media types are enabled in your mediagoblin configuration file, typically it is
 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
@@ -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
 on this page.
 
-To enable a media type, edit the ``media_types`` list in your
-``mediagoblin_local.ini``. For example, if your system supported image and
-video media types, then the list would look like this::
+To enable a media type, add the the media type under the ``[plugins]`` section
+in you ``mediagoblin_local.ini``. For example, if your system supported image
+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::
 
@@ -83,8 +87,8 @@ good/bad/ugly).  On Debianoid systems
         gstreamer0.10-ffmpeg
 
 
-Add ``mediagoblin.media_types.video`` to the ``media_types`` list in your
-``mediagoblin_local.ini`` and restart MediaGoblin.
+Add ``[[mediagoblin.media_types.video]]`` under the ``[plugins]`` section in
+your ``mediagoblin_local.ini`` and restart MediaGoblin.
 
 Run
 
@@ -133,7 +137,7 @@ Then install ``scikits.audiolab`` for the spectrograms::
 
     ./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.
 
 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
-``mediagoblin_local.ini``.  In the ``[mediagoblin]`` section, add
-``mediagoblin.media_types.ascii`` to the ``media_types`` list.
-
-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
+``mediagoblin_local.ini``.  In the ``[plugins]`` section, add
+``[[mediagoblin.media_types.ascii]]``.
 
 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
 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. 
 
 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.
 
-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. 
 
 Run
index e878a4780bceef555ab1a6f5c5e9c3c563f2351f..30dacadf3ec30d3b966d4918691a634ae816cac9 100644 (file)
@@ -11,19 +11,15 @@ email_sender_address = "notice@mediagoblin.example.org"
 
 ## Uncomment and change to your DB's appropiate setting.
 ## Default is a local sqlite db "mediagoblin.db".
+## Don't forget to run `./bin/gmg dbupdate` after having changed it.
 # sql_engine = postgresql:///mediagoblin
 
-# set to false to enable sending notices
+# Set to false to enable sending notices
 email_debug_mode = true
 
 # Set to false to disable registrations
 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
 # local_templates = %(here)s/user_dev/templates/
 
@@ -43,8 +39,9 @@ base_url = /mgoblin_media/
 [celery]
 # Put celery stuff here
 
-# place plugins here---each in their own subsection of [plugins]. see
-# documentation for details.
+# Place plugins here, each in their own subsection of [plugins].
+# See http://docs.mediagoblin.org/siteadmin/plugins.html for details.
 [plugins]
 [[mediagoblin.plugins.geolocation]]
 [[mediagoblin.plugins.basic_auth]]
+[[mediagoblin.media_types.image]]
index ada0c8ba268eebaf014cfb513197dd1d811fd690..57e09e49feda4782d8732a319ef3bb57b730c677 100644 (file)
@@ -29,6 +29,7 @@ from mediagoblin.tools import common, session, translate, template
 from mediagoblin.tools.response import render_http_exception
 from mediagoblin.tools.theme import register_themes
 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.init.celery import setup_celery_from_config
 from mediagoblin.init.plugins import setup_plugins
@@ -69,6 +70,8 @@ class MediaGoblinApp(object):
         # Open and setup the config
         global_config, app_config = setup_global_and_app_config(config_path)
 
+        media_type_warning()
+
         setup_crypto()
 
         ##########################################
index 1cff8dcc5b149b0ba904098dddd34a5fb430091d..d54762b0cb2f3ff07e6a702e7b72652f00fb1391 100644 (file)
@@ -88,6 +88,8 @@ def login(request):
 
             if user:
                 # 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.save()
 
index 12af2f57ab767444474879e341388eecce644eb2..d2ada1635d69e6567c6e5fd15f4e41ce7a8cc906 100644 (file)
@@ -5,9 +5,6 @@ html_title = string(default="GNU MediaGoblin")
 # link to source for this MediaGoblin site
 source_link = string(default="https://gitorious.org/mediagoblin/mediagoblin")
 
-# Enabled media types
-media_types = string_list(default=list("mediagoblin.media_types.image"))
-
 # database stuff
 sql_engine = string(default="sqlite:///%(here)s/mediagoblin.db")
 
index 699a503abf4f04e4ce1fc729d7ff4ceeee883d5f..c0cefdc27024d2c9ba44c957f00c8baafc0c65ec 100644 (file)
@@ -24,18 +24,6 @@ Session = scoped_session(sessionmaker())
 class GMGTableBase(object):
     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):
         return getattr(self, key)
 
index c0c7e9981e717329262bcbcbd79682fce79150e4..aa22ef94525a79204bd7c5edc2951ca8d5899a95 100644 (file)
@@ -175,8 +175,7 @@ class MigrationManager(object):
         if self.name == u'__main__':
             return u"main mediagoblin tables"
         else:
-            # TODO: Use the friendlier media manager "human readable" name
-            return u'media type "%s"' % self.name
+            return u'plugin "%s"' % self.name
 
     def init_or_migrate(self):
         """
index 1b32d83810b6982dbc873461f4c10587d4c809fc..57b27d83a976dc5afa2ea76ea42ae2847478b704 100644 (file)
@@ -29,15 +29,14 @@ real objects.
 
 import uuid
 import re
-import datetime
-
 from datetime import datetime
 
 from werkzeug.utils import cached_property
 
 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.pluginapi import hook_handle
 from mediagoblin.tools.text import cleaned_markdown_conversion
 from mediagoblin.tools.url import slugify
 
@@ -204,14 +203,14 @@ class MediaEntryMixin(GenerateSlugMixin):
 
         Raises FileTypeNotSupported in case no such manager is enabled
         """
-        # TODO, we should be able to make this a simple lookup rather
-        # than iterating through all media managers.
-        for media_type, manager in get_media_managers():
-            if media_type == self.media_type:
-                return manager(self)
+        manager = hook_handle(('media_manager', self.media_type))
+        if manager:
+            return manager(self)
+
         # Not found?  Then raise an error
         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):
         """
index 0b1679fb180b05903a9f4040b6b3226b58b7c850..4ff0945ffcc1b9c8cc378b7b90e955f68cd57d4d 100644 (file)
@@ -52,10 +52,6 @@ class DatabaseMaster(object):
 def load_models(app_config):
     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():
         _log.debug("Loading %s.models", plugin)
         try:
index 6ffec44da18e58665119c4fb4ba05ab87fbda666..8431361a89fc6dc6d22c962e238816fb9e3e0e60 100644 (file)
@@ -24,7 +24,7 @@ from mediagoblin.db.models import MediaEntry, Tag, MediaTag, Collection
 
 
 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)
     Session.commit()
 
index bb2ba7a5620263cc51362b73854324e5e6cb72c7..302ab2472a97c1594fa0ac6eb6f6f14288fc5c09 100644 (file)
@@ -90,8 +90,8 @@ def user_may_alter_collection(controller):
     """
     @wraps(controller)
     def wrapper(request, *args, **kwargs):
-        creator_id = request.db.User.find_one(
-            {'username': request.matchdict['user']}).id
+        creator_id = request.db.User.query.filter_by(
+            username=request.matchdict['user']).first().id
         if not (request.user.is_admin or
                 request.user.id == creator_id):
             raise Forbidden()
@@ -165,15 +165,15 @@ def get_user_collection(controller):
     """
     @wraps(controller)
     def wrapper(request, *args, **kwargs):
-        user = request.db.User.find_one(
-            {'username': request.matchdict['user']})
+        user = request.db.User.query.filter_by(
+            username=request.matchdict['user']).first()
 
         if not user:
             return render_404(request)
 
-        collection = request.db.Collection.find_one(
-            {'slug': request.matchdict['collection'],
-             'creator': user.id})
+        collection = request.db.Collection.query.filter_by(
+            slug=request.matchdict['collection'],
+            creator=user.id).first()
 
         # Still no collection?  Okay, 404.
         if not collection:
@@ -190,14 +190,14 @@ def get_user_collection_item(controller):
     """
     @wraps(controller)
     def wrapper(request, *args, **kwargs):
-        user = request.db.User.find_one(
-            {'username': request.matchdict['user']})
+        user = request.db.User.query.filter_by(
+            username=request.matchdict['user']).first()
 
         if not user:
             return render_404(request)
 
-        collection_item = request.db.CollectionItem.find_one(
-            {'id': request.matchdict['collection_item'] })
+        collection_item = request.db.CollectionItem.query.filter_by(
+            id=request.matchdict['collection_item']).first()
 
         # Still no collection item?  Okay, 404.
         if not collection_item:
index e0147a0c0ad1ad27acd3788bb8d8a3e74f865466..85c243a0dcb1d5277a7447ff48db94865522f557 100644 (file)
@@ -66,7 +66,6 @@ class EditAccountForm(wtforms.Form):
         [wtforms.validators.Optional(),
          normalize_user_or_email_field(allow_user=False)])
     wants_comment_notification = wtforms.BooleanField(
-        label='',
         description=_("Email me when others comment on my media"))
     license_preference = wtforms.SelectField(
         _('License preference'),
index 7a8d6185123dff9401f7032c332b6d061279c76b..6aa2acd94d5d3d5b1019b87968193f076af80e25 100644 (file)
@@ -305,9 +305,9 @@ def edit_collection(request, collection):
                 form.slug.data, collection.id)
 
         # Make sure there isn't already a Collection with this title
-        existing_collection = request.db.Collection.find_one({
-                'creator': request.user.id,
-                'title':form.title.data})
+        existing_collection = request.db.Collection.query.filter_by(
+                creator=request.user.id,
+                title=form.title.data).first()
 
         if existing_collection and existing_collection.id != collection.id:
             messages.add_message(
index 22ad426c1046dd0fbe8bfb9518490870c4335326..00007567948999e365f28a6bb31c162b10ef0e6a 100644 (file)
@@ -42,7 +42,7 @@ class DatabaseData(object):
             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
     installed so we can do migrations and table initialization.
@@ -59,13 +59,6 @@ def gather_database_data(media_types, plugins):
         DatabaseData(
             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:
         try:
             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
     dbdatas = gather_database_data(
-            app_config['media_types'],
             global_config.get('plugins', {}).keys())
 
     Session = sessionmaker(bind=db.engine)
index d51a1e3e66e2dcc4f6307b80b10a0d6bcb5d3216..98ec617d9d30432ee35a7870f5756de56bf7eeb8 100644 (file)
@@ -63,7 +63,7 @@ def _import_media(db, args):
     # TODO: Add import of queue files
     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():
             _log.info('Importing: {0} - {1}'.format(
                     entry.title.encode('ascii', 'replace'),
@@ -204,7 +204,7 @@ def _export_media(db, args):
     # TODO: Add export of queue files
     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():
             _log.info(u'Exporting {0} - {1}'.format(
                     entry.title,
index 1f3294598f18e7cd94d0c2aad47240de1e80a3ff..e44b0aa9b481bbee3f9d653c48602de6f7605843 100644 (file)
@@ -40,9 +40,9 @@ def adduser(args):
 
     db = mg_globals.database
     users_with_username = \
-        db.User.find({
-            'username': args.username.lower(),
-        }).count()
+        db.User.query.filter_by(
+            username=args.username.lower()
+        ).count()
 
     if users_with_username:
         print u'Sorry, a user with that name already exists.'
@@ -71,7 +71,8 @@ def makeadmin(args):
 
     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:
         user.is_admin = True
         user.save()
@@ -94,7 +95,8 @@ def changepw(args):
 
     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:
         user.pw_hash = auth.gen_password_hash(args.password)
         user.save()
index 35af7148d93e8a04dafdf6aa0789f9dfab514934..07dbb3d504b98cda4ad9572a2429b80cd1d35131 100644 (file)
@@ -14,6 +14,7 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+from mediagoblin import mg_globals
 from mediagoblin.db.models import MediaEntry
 from mediagoblin.db.util import media_entries_for_tag_slug
 from mediagoblin.tools.pagination import Pagination
@@ -80,6 +81,17 @@ def atom_feed(request):
         link = request.urlgen('index', qualified=True)
         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.limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS)
 
@@ -87,9 +99,8 @@ def atom_feed(request):
         feed_title,
         feed_url=request.url,
         id=link,
-        links=[{'href': link,
-            'rel': 'alternate',
-            'type': 'text/html'}])
+        links=atomlinks)
+
     for entry in cursor:
         feed.add(entry.get('title'),
             entry.description_html,
index 20e1918e6caf157d0a58482b789ed7a48b096143..134157dcb0ca7054fdf5043bef82548137ef7373 100644 (file)
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
-import sys
 import logging
 import tempfile
 
-from mediagoblin import mg_globals
-from mediagoblin.tools.common import import_component
+from mediagoblin.tools.pluginapi import hook_handle
 from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
 
 _log = logging.getLogger(__name__)
@@ -52,36 +50,6 @@ class MediaManagerBase(object):
         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):
     '''
     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.stream.seek(0)
 
-        for media_type, manager in get_media_managers():
-            _log.info('Sniffing {0}'.format(media_type))
-            if manager.sniff_handler(media_file, media=media):
-                _log.info('{0} accepts the file'.format(media_type))
-                return media_type, manager
-            else:
-                _log.debug('{0} did not accept the file'.format(media_type))
+        media_type = hook_handle('sniff_handler', media_file, media=media)
+        if media_type:
+            _log.info('{0} accepts the file'.format(media_type))
+            return media_type, hook_handle(('media_manager', media_type))
+        else:
+            _log.debug('{0} did not accept the file'.format(media_type))
 
     raise FileTypeNotSupported(
         # TODO: Provide information on which file types are supported
         _(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):
     '''
     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
         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
-            # the media manager
-            if ext[1:] in manager.accepted_extensions:
-                return media_type, manager
+        # Omit the dot from the extension and match it against
+        # the media manager
+        if hook_handle('get_media_type_and_manager', ext[1:]):
+            return hook_handle('get_media_type_and_manager', ext[1:])
     else:
         _log.info('File {0} has no file extension, let\'s hope the sniffers get it.'.format(
             filename))
index 0931e83a0f9755d20d451ef329261da623dfb739..4baf8dd383b6b2fc1587d901b16772de87f50874 100644 (file)
 from mediagoblin.media_types import MediaManagerBase
 from mediagoblin.media_types.ascii.processing import process_ascii, \
     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):
     human_readable = "ASCII"
     processor = staticmethod(process_ascii)
-    sniff_handler = staticmethod(sniff_handler)
     display_template = "mediagoblin/media_displays/ascii.html"
     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,
+}
index 2f6079be444a2f7ee54144da3cc1863aae34f5ab..aca784e8c6c375ba30391122eb91a1bf1d41a33d 100644 (file)
@@ -28,17 +28,19 @@ from mediagoblin.media_types.ascii import asciitoimage
 _log = logging.getLogger(__name__)
 
 SUPPORTED_EXTENSIONS = ['txt', 'asc', 'nfo']
+MEDIA_TYPE = 'mediagoblin.media_types.ascii'
 
 
 def sniff_handler(media_file, **kw):
+    _log.info('Sniffing {0}'.format(MEDIA_TYPE))
     if kw.get('media') is not None:
         name, ext = os.path.splitext(kw['media'].filename)
         clean_ext = ext[1:].lower()
 
         if clean_ext in SUPPORTED_EXTENSIONS:
-            return True
+            return MEDIA_TYPE
 
-    return False
+    return None
 
 
 def process_ascii(proc_state):
index 2eb7300e3e12e44f127f76340b58cb3325d1daba..90f842baa8e73d5d2475ee126f6afe46d856c976 100644 (file)
 from mediagoblin.media_types import MediaManagerBase
 from mediagoblin.media_types.audio.processing import process_audio, \
     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):
     human_readable = "Audio"
     processor = staticmethod(process_audio)
-    sniff_handler = staticmethod(sniff_handler)
     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,
+}
index 101b83e5f8ace58c20af65954c1eddbf6d665811..22383bc1918aec51729dea0a1ce01f5be7c39006 100644 (file)
@@ -27,19 +27,22 @@ from mediagoblin.media_types.audio.transcoders import (AudioTranscoder,
 
 _log = logging.getLogger(__name__)
 
+MEDIA_TYPE = 'mediagoblin.media_types.audio'
+
 
 def sniff_handler(media_file, **kw):
+    _log.info('Sniffing {0}'.format(MEDIA_TYPE))
     try:
         transcoder = AudioTranscoder()
         data = transcoder.discover(media_file.name)
     except BadMediaFail:
         _log.debug('Audio discovery raised BadMediaFail')
-        return False
+        return None
 
     if data.is_audio == True and data.is_video == False:
-        return True
+        return MEDIA_TYPE
 
-    return False
+    return None
 
 
 def process_audio(proc_state):
index 5130ef48fce96ce60415b983744bbddce86451ae..1bb9c6f3edb9a1ffae69beb98266c339abb65af8 100644 (file)
 #
 # 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
 
 from mediagoblin.media_types import MediaManagerBase
 from mediagoblin.media_types.image.processing import process_image, \
     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):
     human_readable = "Image"
     processor = staticmethod(process_image)
-    sniff_handler = staticmethod(sniff_handler)
     display_template = "mediagoblin/media_displays/image.html"
     default_thumb = "images/media_thumbs/image.png"
-    accepted_extensions = ["jpg", "jpeg", "png", "gif", "tiff"]
+
     media_fetch_order = [u'medium', u'original', u'thumb']
-    
+
     def get_original_date(self):
         """
         Get the original date and time from the EXIF information. Returns
@@ -52,4 +59,14 @@ class ImageMediaManager(MediaManagerBase):
             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,
+}
index bc0ce3f8925a33e8caa64e25462cff87af678a86..baf2ac7e991a34de360d8b35d66d7df565bf806d 100644 (file)
@@ -35,6 +35,8 @@ PIL_FILTERS = {
     'BICUBIC': Image.BICUBIC,
     'ANTIALIAS': Image.ANTIALIAS}
 
+MEDIA_TYPE = 'mediagoblin.media_types.image'
+
 
 def resize_image(proc_state, resized, keyname, target_name, new_size,
                  exif_tags, workdir):
@@ -95,17 +97,18 @@ def resize_tool(proc_state, force, keyname, target_name,
             exif_tags, conversions_subdir)
 
 
-SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg']
+SUPPORTED_FILETYPES = ['png', 'gif', 'jpg', 'jpeg', 'tiff']
 
 
 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!
         name, ext = os.path.splitext(kw['media'].filename)
         clean_ext = ext[1:].lower()  # Strip the . from ext and make lowercase
 
         if clean_ext in SUPPORTED_FILETYPES:
             _log.info('Found file extension in supported filetypes')
-            return True
+            return MEDIA_TYPE
         else:
             _log.debug('Media present, extension not found in {0}'.format(
                     SUPPORTED_FILETYPES))
@@ -113,7 +116,7 @@ def sniff_handler(media_file, **kw):
         _log.warning('Need additional information (keyword argument \'media\')'
                      ' to be able to handle sniffing')
 
-    return False
+    return None
 
 
 def process_image(proc_state):
index f0ba7867d6177dea621c1e90fa84a3d386f96dd6..67509ddc5196835c1f111c05dfc9e396f84aced9 100644 (file)
 from mediagoblin.media_types import MediaManagerBase
 from mediagoblin.media_types.pdf.processing import process_pdf, \
     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):
     human_readable = "PDF"
     processor = staticmethod(process_pdf)
-    sniff_handler = staticmethod(sniff_handler)
     display_template = "mediagoblin/media_displays/pdf.html"
     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,
+}
index b5adb5e6fd7405ac201bf12737954abf0af55bf3..f35b4376490cab3deac118122f276452603a5764 100644 (file)
@@ -25,6 +25,8 @@ from mediagoblin.tools.translate import fake_ugettext_passthrough as _
 
 _log = logging.getLogger(__name__)
 
+MEDIA_TYPE = 'mediagoblin.media_types.pdf'
+
 # TODO - cache (memoize) util
 
 # This is a list created via uniconv --show and hand removing some types that
@@ -163,16 +165,17 @@ def check_prerequisites():
     return True
 
 def sniff_handler(media_file, **kw):
+    _log.info('Sniffing {0}'.format(MEDIA_TYPE))
     if not check_prerequisites():
-        return False
+        return None
     if kw.get('media') is not None:
         name, ext = os.path.splitext(kw['media'].filename)
         clean_ext = ext[1:].lower()
 
         if clean_ext in supported_extensions():
-            return True
+            return MEDIA_TYPE
 
-    return False
+    return None
 
 def create_pdf_thumb(original, thumb_filename, width, height):
     # Note: pdftocairo adds '.png', remove it
index 6ae8a8b9b5f926b4c98b09b32bc265617e7aacca..1d2a8478c9b4633e992278b573132773fe8c0cfa 100644 (file)
 from mediagoblin.media_types import MediaManagerBase
 from mediagoblin.media_types.stl.processing import process_stl, \
     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):
     human_readable = "stereo lithographics"
     processor = staticmethod(process_stl)
-    sniff_handler = staticmethod(sniff_handler)
     display_template = "mediagoblin/media_displays/stl.html"
     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,
+}
index ce7a5d3711fbd0d9a2f6de83d401c46f45c7e35f..537514165d92d281218096a7de8782b077c39989 100644 (file)
@@ -29,6 +29,7 @@ from mediagoblin.media_types.stl import model_loader
 
 _log = logging.getLogger(__name__)
 SUPPORTED_FILETYPES = ['stl', 'obj']
+MEDIA_TYPE = 'mediagoblin.media_types.stl'
 
 BLEND_FILE = pkg_resources.resource_filename(
     'mediagoblin.media_types.stl',
@@ -43,13 +44,14 @@ BLEND_SCRIPT = pkg_resources.resource_filename(
 
 
 def sniff_handler(media_file, **kw):
+    _log.info('Sniffing {0}'.format(MEDIA_TYPE))
     if kw.get('media') is not None:
         name, ext = os.path.splitext(kw['media'].filename)
         clean_ext = ext[1:].lower()
 
         if clean_ext in SUPPORTED_FILETYPES:
             _log.info('Found file extension in supported filetypes')
-            return True
+            return MEDIA_TYPE
         else:
             _log.debug('Media present, extension not found in {0}'.format(
                     SUPPORTED_FILETYPES))
@@ -57,7 +59,7 @@ def sniff_handler(media_file, **kw):
         _log.warning('Need additional information (keyword argument \'media\')'
                      ' to be able to handle sniffing')
 
-    return False
+    return None
 
 
 def blender_render(config):
diff --git a/mediagoblin/media_types/tools.py b/mediagoblin/media_types/tools.py
new file mode 100644 (file)
index 0000000..fe7b377
--- /dev/null
@@ -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.')
index 569cf11a3525b9529160c988636e72a3e2047adb..e8a4308bc7386b943f12ff51bc84a2eee4d3d473 100644 (file)
 from mediagoblin.media_types import MediaManagerBase
 from mediagoblin.media_types.video.processing import process_video, \
     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):
     human_readable = "Video"
     processor = staticmethod(process_video)
-    sniff_handler = staticmethod(sniff_handler)
     display_template = "mediagoblin/media_displays/video.html"
     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
     media_fetch_order = [u'webm_640', u'original']
     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,
+}
index ff2c94a02bd8b6422723ca6f89ba74cb74dc1e6a..5386ba60b6983cc9451607c951eeb7402409e533 100644 (file)
@@ -29,6 +29,8 @@ from .util import skip_transcode
 _log = logging.getLogger(__name__)
 _log.setLevel(logging.DEBUG)
 
+MEDIA_TYPE = 'mediagoblin.media_types.video'
+
 
 class VideoTranscodingFail(BaseProcessingFail):
     '''
@@ -41,17 +43,18 @@ def sniff_handler(media_file, **kw):
     transcoder = transcoders.VideoTranscoder()
     data = transcoder.discover(media_file.name)
 
+    _log.info('Sniffing {0}'.format(MEDIA_TYPE))
     _log.debug('Discovered: {0}'.format(data))
 
     if not data:
         _log.error('Could not discover {0}'.format(
                 kw.get('media')))
-        return False
+        return None
 
     if data['is_video'] == True:
-        return True
+        return MEDIA_TYPE
 
-    return False
+    return None
 
 
 def process_video(proc_state):
@@ -186,7 +189,7 @@ def store_metadata(media_entry, metadata):
             [(key, tags_metadata[key])
              for key in [
                      "application-name", "artist", "audio-codec", "bitrate",
-                     "container-format", "copyright", "encoder", 
+                     "container-format", "copyright", "encoder",
                      "encoder-version", "license", "nominal-bitrate", "title",
                      "video-codec"]
              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_minute(), dt.get_second(),
                 dt.get_microsecond()).isoformat()
-    
+
         metadata['tags'] = tags
 
     # Only save this field if there's something to save
index 72d99dffaf8519c6446fc84d5badb7d642fc9360..6cf01b38305766a5e22b404851b0087bc10e8585 100644 (file)
@@ -41,3 +41,6 @@ class LoginForm(wtforms.Form):
          normalize_user_or_email_field()])
     password = wtforms.PasswordField(
         _('Password'))
+    stay_logged_in = wtforms.BooleanField(
+        label='',
+        description=_('Stay logged in'))
index 0d813bf5cf31f6973a72401541eea05c7fbfac9f..d96b9200833bf440a5b8cc4629bec5d37cfc12e6 100644 (file)
@@ -334,6 +334,10 @@ text-align: center;
   width: 20px;
 }
 
+.boolean {
+  margin-bottom: 8px;
+  }
+
 textarea#description, textarea#bio {
   resize: vertical;
   height: 100px;
index 64e6791b36a93081f98c2a262cece956642af3d9..3f9d5b2df2ac0adf654934d52cb4e8075586ffa7 100644 (file)
@@ -19,6 +19,7 @@ import mediagoblin.mg_globals as mg_globals
 from os.path import splitext
 
 import logging
+import uuid
 
 _log = logging.getLogger(__name__)
 
@@ -53,6 +54,10 @@ def submit_start(request):
             try:
                 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
                 # media plugin should handle processing
                 media_type, media_manager = sniff_media(
@@ -63,7 +68,7 @@ def submit_start(request):
                 entry.media_type = unicode(media_type)
                 entry.title = (
                     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)
 
@@ -133,9 +138,9 @@ def add_collection(request, media=None):
         collection.generate_slug()
 
         # Make sure this user isn't duplicating an existing collection
-        existing_collection = request.db.Collection.find_one({
-                'creator': request.user.id,
-                'title':collection.title})
+        existing_collection = request.db.Collection.query.filter_by(
+                creator=request.user.id,
+                title=collection.title).first()
 
         if existing_collection:
             add_message(request, messages.ERROR,
index ff909b077d27c566a26a2679e5a171b31f17236b..2a1ffee0f423780cdb9c77507b2a2c049563b894 100644 (file)
@@ -39,7 +39,7 @@
           Changing {{ username }}'s password
         {%- endtrans -%}
       </h1>
-      {{ wtforms_util.render_divs(form) }}
+      {{ wtforms_util.render_divs(form, True) }}
       {{ csrf_token }}
       <div class="form_submit_buttons">
         <input type="submit" value="{% trans %}Save{% endtrans %}"
index a89e0b4fe72bff8c13e1d6d4248e0a43e3fc5afa..bc12ce4e34853223e1782ed3df4809f02a9f331f 100644 (file)
@@ -108,32 +108,26 @@ window.show_things = function () {
 
 
 <div style="padding: 4px;">
-  <a class="button_action" onclick="show('perspective');"
-     title="{%- trans %}Toggle Rotate{% endtrans -%}">
+  <a class="button_action" onclick="show('perspective');">
     {%- trans %}Perspective{% endtrans -%}
   </a>
-  <a class="button_action" onclick="show('front_view');"
-     title="{%- trans %}Front{% endtrans -%}">
+  <a class="button_action" onclick="show('front_view');">
     {%- trans %}Front{% endtrans -%}
   </a>
-  <a class="button_action" onclick="show('top_view');"
-     title="{%- trans %}Top{% endtrans -%}">
+  <a class="button_action" onclick="show('top_view');">
     {%- trans %}Top{% endtrans -%}
   </a>
-  <a class="button_action" onclick="show('side_view');"
-     title="{%- trans %}Side{% endtrans -%}">
+  <a class="button_action" onclick="show('side_view');">
     {%- trans %}Side{% endtrans -%}
   </a>
 {% if media.media_data.file_type == "stl" %}
   <a id="webgl_button" class="button_action"
-     onclick="show_things();"
-     title="{%- trans %}WebGL{% endtrans -%}">
+     onclick="show_things();">
     {%- trans %}WebGL{% endtrans -%}
   </a>
 {% endif %}
 
   <a class="button_action" href="{{ model_download }}"
-     title="{%- trans %}Download{% endtrans -%}"
      style="float:right;">
     {%- trans %}Download model{% endtrans -%}
   </a>
index 8ee8c883b9d6d1ec1fe7ad381242e805a50886d8..bd367e8066cc4fe68af09bfd27558d813b74e842 100644 (file)
     {% if not subscription or not subscription.notify %}
         <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.subscribe_comments',
             user=media.get_uploader.username,
-            media=media.slug)}}"
+            media=media.slug_or_id)}}"
             class="button_action">Subscribe to comments
         </a>
     {% else %}
         <a type="submit" href="{{ request.urlgen('mediagoblin.notifications.silence_comments',
             user=media.get_uploader.username,
-            media=media.slug)}}"
+            media=media.slug_or_id)}}"
             class="button_action">Silence comments
         </a>
     {% endif %}
index a4c33f1aed5aaf989a8f9f6065654ef3be643b6b..e079274edb74af400299bf982b570d3bacef5ebb 100644 (file)
 
 {# Generically render a field #}
 {% macro render_field_div(field, autofocus_first=False) %}
-  {{- render_label_p(field) }}
-  <div class="form_field_input">
-    {% if autofocus_first %}
-      {{ field(autofocus=True) }}
-    {% else %}
-      {{ field }}
-    {% endif %}
-    {%- 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>
+  {% if field.type == 'BooleanField' %}
+    {{ render_bool(field) }}
+  {% else %}
+    {{- render_label_p(field) }}
+    <div class="form_field_input">
+      {% if autofocus_first %}
+        {{ field(autofocus=True) }}
       {% else %}
-        <p class="form_field_description">{{ field.description|safe }}</p>
+        {{ field }}
       {% endif %}
-    {%- endif %}
-  </div>
+      {%- if field.errors -%}
+        {% 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 %}
 
 {# Auto-render a form as a series of divs #}
     </tr>
   {% endfor %}
 {%- 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 %}
+
index 5bd8bf2c66590cd268fe65605548180151e42aae..61503d328a12f058ad7827fafda71e8384cf996b 100644 (file)
@@ -93,8 +93,8 @@ def test_register_views(test_app):
     assert 'mediagoblin/user_pages/user.html' in template.TEMPLATE_TEST_CONTEXT
 
     ## Make sure user is in place
-    new_user = mg_globals.database.User.find_one(
-        {'username': u'happygirl'})
+    new_user = mg_globals.database.User.query.filter_by(
+        username=u'happygirl').first()
     assert new_user
     assert new_user.status == u'needs_email_verification'
     assert new_user.email_verified == False
@@ -128,8 +128,8 @@ def test_register_views(test_app):
 
     # assert context['verification_successful'] == True
     # TODO: Would be good to test messages here when we can do so...
-    new_user = mg_globals.database.User.find_one(
-        {'username': u'happygirl'})
+    new_user = mg_globals.database.User.query.filter_by(
+        username=u'happygirl').first()
     assert new_user
     assert new_user.status == u'needs_email_verification'
     assert new_user.email_verified == False
@@ -142,8 +142,8 @@ def test_register_views(test_app):
         'mediagoblin/user_pages/user.html']
     # assert context['verification_successful'] == True
     # TODO: Would be good to test messages here when we can do so...
-    new_user = mg_globals.database.User.find_one(
-        {'username': u'happygirl'})
+    new_user = mg_globals.database.User.query.filter_by(
+        username=u'happygirl').first()
     assert new_user
     assert new_user.status == u'active'
     assert new_user.email_verified == True
index acc638d9f7afbb33e04191a5d0ec2b91722453e4..d70d0478fa5080b06f98c25647511e10ad98afb6 100644 (file)
@@ -190,8 +190,8 @@ class TestUserEdit(object):
         assert urlparse.urlsplit(res.location)[2] == '/'
 
         # Email shouldn't be saved
-        email_in_db = mg_globals.database.User.find_one(
-            {'email': 'new@example.com'})
+        email_in_db = mg_globals.database.User.query.filter_by(
+            email='new@example.com').first()
         email = User.query.filter_by(username='chris').first().email
         assert email_in_db is None
         assert email == 'chris@example.com'
index 5c3c46e7e7048c9d08912fa4cdabd18a22882e44..535cf1c1dfbccdaaaa6fa7ae20b2267f7d7db3e2 100644 (file)
@@ -13,8 +13,6 @@ tags_max_length = 50
 # So we can start to test attachments:
 allow_attachments = True
 
-media_types = mediagoblin.media_types.image, mediagoblin.media_types.pdf
-
 [storage:publicstore]
 base_dir = %(here)s/user_dev/media/public
 base_url = /mgoblin_media/
@@ -34,3 +32,5 @@ BROKER_HOST = "sqlite:///%(here)s/user_dev/kombu.db"
 [[mediagoblin.plugins.piwigo]]
 [[mediagoblin.plugins.basic_auth]]
 [[mediagoblin.plugins.openid]]
+[[mediagoblin.media_types.image]]
+[[mediagoblin.media_types.pdf]]
index c85f631847622667edbaedadaf8a39e1c361eee1..bba46db800c5ccb49811ad011644b4655b144313 100644 (file)
@@ -186,8 +186,8 @@ class TestOpenIDPlugin(object):
             openid_plugin_app.get('/auth/logout')
 
             # Get user and detach from session
-            test_user = mg_globals.database.User.find_one({
-                'username': u'chris'})
+            test_user = mg_globals.database.User.query.filter_by(
+                username=u'chris').first()
             Session.expunge(test_user)
 
             # Log back in
@@ -314,8 +314,8 @@ class TestOpenIDPlugin(object):
             assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
 
             # OpenID Added?
-            new_openid = mg_globals.database.OpenIDUserURL.find_one(
-                {'openid_url': u'http://add.myopenid.com'})
+            new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
+                openid_url=u'http://add.myopenid.com').first()
             assert new_openid
 
         _test_add()
@@ -365,8 +365,8 @@ class TestOpenIDPlugin(object):
             assert 'mediagoblin/edit/edit_account.html' in template.TEMPLATE_TEST_CONTEXT
 
             # OpenID deleted?
-            new_openid = mg_globals.database.OpenIDUserURL.find_one(
-                {'openid_url': u'http://add.myopenid.com'})
+            new_openid = mg_globals.database.OpenIDUserURL.query.filter_by(
+                openid_url=u'http://add.myopenid.com').first()
             assert not new_openid
 
         _test_delete(self, test_user)
index 162b2d195f09eb762124507b380950ca294b76d1..ac9410637bab31a8ceaa6a3b752fcd15763eb57b 100644 (file)
@@ -26,7 +26,7 @@ from mediagoblin.tests.tools import fixture_add_user
 from mediagoblin import mg_globals
 from mediagoblin.db.models import MediaEntry
 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 .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
@@ -77,7 +77,7 @@ class TestSubmission:
         return {'upload_files': [('file', filename)]}
 
     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))
 
     def test_missing_fields(self):
@@ -122,7 +122,7 @@ class TestSubmission:
         assert 'mediagoblin/user_pages/user.html' in context
 
     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:
             assert media.count() == count
             if count == 0:
@@ -219,7 +219,7 @@ class TestSubmission:
         media = self.check_media(request, {'title': u'Balanced Goblin'}, 1)
 
         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
 
 
@@ -240,8 +240,8 @@ class TestSubmission:
 
         request = context['request']
 
-        media = request.db.MediaEntry.find_one({
-            u'title': u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE'})
+        media = request.db.MediaEntry.query.filter_by(
+            title=u'UNIQUE_TITLE_PLS_DONT_CREATE_OTHER_MEDIA_WITH_THIS_TITLE').first()
 
         assert media.media_type == 'mediagoblin.media_types.image'
 
@@ -252,7 +252,7 @@ class TestSubmission:
         response, context = self.do_post({'title': title}, do_follow=True,
                                          **self.upload_data(filename))
         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.fail_error == u'mediagoblin.processing:BadMediaFail'
 
index 2584c62f89a08e9f0d7ba7b2b8ce12e667909e27..98361adc18eddf940882e1d06356171a561c9547 100644 (file)
@@ -164,7 +164,7 @@ def assert_db_meets_expected(db, expected):
     for collection_name, collection_data in expected.iteritems():
         collection = db[collection_name]
         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 == expected_document  # make sure it matches
 
index fdc32523c8acdcb46ba7166d48d6fa0918510825..d79afb66428102ffccac535f4b1740d2aedc4a4e 100644 (file)
@@ -21,6 +21,8 @@ import crypto
 
 _log = logging.getLogger(__name__)
 
+MAX_AGE = 30 * 24 * 60 * 60
+
 class Session(dict):
     def __init__(self, *args, **kwargs):
         self.send_new_cookie = False
@@ -64,5 +66,10 @@ class SessionManager(object):
         elif not session:
             response.delete_cookie(self.cookie_name)
         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),
-                httponly=True)
+                max_age=max_age, httponly=True)
index 83a524ec4421ec980e56ac24b56f75076e97c73d..596d4c20b6111c1496f49ec3b576edffe7e889d0 100644 (file)
@@ -142,7 +142,7 @@ def media_home(request, media, page, **kwargs):
 
     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(
         request,