--- /dev/null
+# 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/>.
+
+"""
+This module contains some Mixin classes for the db objects.
+
+A bunch of functions on the db objects are really more like
+"utility functions": They could live outside the classes
+and be called "by hand" passing the appropiate reference.
+They usually only use the public API of the object and
+rarely use database related stuff.
+
+These functions now live here and get "mixed in" into the
+real objects.
+"""
+
+from mediagoblin.auth import lib as auth_lib
+from mediagoblin.tools import common
+
+
+class UserMixin(object):
+ def check_login(self, password):
+ """
+ See if a user can login with this password
+ """
+ return auth_lib.bcrypt_check_password(
+ password, self.pw_hash)
+
+
+class MediaEntryMixin(object):
+ def get_display_media(self, media_map,
+ fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER):
+ """
+ Find the best media for display.
+
+ Args:
+ - media_map: a dict like
+ {u'image_size': [u'dir1', u'dir2', u'image.jpg']}
+ - fetch_order: the order we should try fetching images in
+
+ Returns:
+ (media_size, media_path)
+ """
+ media_sizes = media_map.keys()
+
+ for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER:
+ if media_size in media_sizes:
+ return media_map[media_size]
+
+ def main_mediafile(self):
+ pass
+
+ def url_for_self(self, urlgen):
+ """
+ Generate an appropriate url for ourselves
+
+ Use a slug if we have one, else use our '_id'.
+ """
+ uploader = self.get_uploader
+
+ if self.get('slug'):
+ return urlgen(
+ 'mediagoblin.user_pages.media_home',
+ user=uploader.username,
+ media=self.slug)
+ else:
+ return urlgen(
+ 'mediagoblin.user_pages.media_home',
+ user=uploader.username,
+ media=unicode(self._id))
+
+ def get_fail_exception(self):
+ """
+ Get the exception that's appropriate for this error
+ """
+ if self['fail_error']:
+ return common.import_component(self['fail_error'])
from mongokit import Document
-from mediagoblin.auth import lib as auth_lib
from mediagoblin import mg_globals
from mediagoblin.db.mongo import migrations
from mediagoblin.db.mongo.util import ASCENDING, DESCENDING, ObjectId
from mediagoblin.tools.pagination import Pagination
-from mediagoblin.tools import url, common
+from mediagoblin.tools import url
+from mediagoblin.db.mixin import UserMixin, MediaEntryMixin
###################
# Custom validators
########
-class User(Document):
+class User(Document, UserMixin):
"""
A user of MediaGoblin.
'status': u'needs_email_verification',
'is_admin': False}
- def check_login(self, password):
- """
- See if a user can login with this password
- """
- return auth_lib.bcrypt_check_password(
- password, self.pw_hash)
-
-class MediaEntry(Document):
+class MediaEntry(Document, MediaEntryMixin):
"""
Record of a piece of media.
return self.db.MediaComment.find({
'media_entry': self._id}).sort('created', order)
- def get_display_media(self, media_map,
- fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER):
- """
- Find the best media for display.
-
- Args:
- - media_map: a dict like
- {u'image_size': [u'dir1', u'dir2', u'image.jpg']}
- - fetch_order: the order we should try fetching images in
-
- Returns:
- (media_size, media_path)
- """
- media_sizes = media_map.keys()
-
- for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER:
- if media_size in media_sizes:
- return media_map[media_size]
-
- def main_mediafile(self):
- pass
-
def generate_slug(self):
self.slug = url.slugify(self.title)
def get_uploader(self):
return self.db.User.find_one({'_id': self.uploader})
- def get_fail_exception(self):
- """
- Get the exception that's appropriate for this error
- """
- if self['fail_error']:
- return common.import_component(self['fail_error'])
-
class MediaComment(Document):
"""
from sqlalchemy.orm import relationship
from mediagoblin.db.sql.base import GMGTableBase
+from mediagoblin.db.mixin import UserMixin, MediaEntryMixin
Base = declarative_base(cls=GMGTableBase)
setattr(instance, self.fieldname, val)
-class User(Base):
+class User(Base, UserMixin):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
_id = SimpleFieldAlias("id")
-class MediaEntry(Base):
+class MediaEntry(Base, MediaEntryMixin):
__tablename__ = "media_entries"
id = Column(Integer, primary_key=True)
# 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 pkg_resources
-import urlparse
-
####################################
# Staticdirect infrastructure.
# Borrowed largely from cc.engine
####################################
import pkg_resources
-import urlparse
+import logging
+
+_log = logging.getLogger(__name__)
class StaticDirect(object):
if filepath in self.cache:
return self.cache[filepath]
+ if not pkg_resources.resource_exists('mediagoblin',
+ 'static' + filepath):
+ _log.info("StaticDirect resource %r not found locally",
+ filepath)
static_direction = self.cache[filepath] = self.get(filepath)
return static_direction
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>{% block title %}{{ app_config['html_title'] }}{% endblock %}</title>
<link rel="stylesheet" type="text/css"
- href="{{ request.staticdirect('/css/reset.css') }}"/>
+ href="{{ request.staticdirect('/css/extlib/reset.css') }}"/>
<link rel="stylesheet" type="text/css"
href="{{ request.staticdirect('/css/base.css') }}"/>
- <link rel="stylesheet" type="text/css"
- href="{{ request.staticdirect('/css/video-js.css') }}"/>
<link rel="shortcut icon"
href="{{ request.staticdirect('/images/goblin.ico') }}" />
<script src="{{ request.staticdirect('/js/extlib/jquery.js') }}"></script>
</ul>
{% endif %}
{% if app_config['allow_attachments']
+ and request.user
and (media.uploader == request.user._id
or request.user.is_admin) %}
<p>
# tag parsing
tags_max_length = 50
+# So we can start to test attachments:
+allow_attachments = True
+
# Celery shouldn't be set up by the application as it's setup via
# mediagoblin.init.celery.from_celery
celery_setup_elsewhere = true
self.test_user = test_user
+ self.login()
+
+ def login(self):
self.test_app.post(
'/auth/login/', {
'username': u'chris',
'password': 'toast'})
+ def logout(self):
+ self.test_app.get('/auth/logout/')
+
def test_missing_fields(self):
# Test blank form
# ---------------
assert template.TEMPLATE_TEST_CONTEXT.has_key(
'mediagoblin/user_pages/user.html')
+ # Make sure the media view is at least reachable, logged in...
+ self.test_app.get('/u/chris/m/normal-upload-1/')
+ # ... and logged out too.
+ self.logout()
+ self.test_app.get('/u/chris/m/normal-upload-1/')
+ # Log back in for the remaining tests.
+ self.login()
+
# Test PNG
# --------
template.clear_test_template_context()
filter-with = beaker
config = %(here)s/mediagoblin_local.ini %(here)s/mediagoblin.ini
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-7.7s [%(name)s] %(message)s
+
[app:publicstore_serve]
use = egg:Paste#static
document_root = %(here)s/user_dev/media/public/