X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;ds=sidebyside;f=mediagoblin%2Fdb%2Fmixin.py;h=1f2e7ec30262d762deab08704059cc15b02bd6f2;hb=bb12fb807e59cbe124c32c0b4fa2a74e0b81aade;hp=98414d729f8f29c6339c77b2c3adfeaac974c815;hpb=b0118957ff3304226f3500b4f5cfaecc41e9ee48;p=mediagoblin.git diff --git a/mediagoblin/db/mixin.py b/mediagoblin/db/mixin.py index 98414d72..1f2e7ec3 100644 --- a/mediagoblin/db/mixin.py +++ b/mediagoblin/db/mixin.py @@ -27,35 +27,43 @@ These functions now live here and get "mixed in" into the real objects. """ -from uuid import uuid4 +import uuid +import re +from datetime import datetime from werkzeug.utils import cached_property from mediagoblin import mg_globals -from mediagoblin.auth import lib as auth_lib -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 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) - @property def bio_html(self): return cleaned_markdown_conversion(self.bio) + def url_for_self(self, urlgen, **kwargs): + """Generate a URL for this User's home page.""" + return urlgen('mediagoblin.user_pages.user_home', + user=self.username, **kwargs) + -class MediaEntryMixin(object): +class GenerateSlugMixin(object): + """ + Mixin to add a generate_slug method to objects. + + Depends on: + - self.slug + - self.title + - self.check_slug_used(new_slug) + """ def generate_slug(self): """ - Generate a unique slug for this MediaEntry. + Generate a unique slug for this object. This one does not *force* slugs, but usually it will probably result in a niceish one. @@ -76,19 +84,15 @@ class MediaEntryMixin(object): generated bits until it's unique. That'll be a little bit of junk, but at least it has the basis of a nice slug. """ - # import this here due to a cyclic import issue - # (db.models -> db.mixin -> db.util -> db.models) - from mediagoblin.db.util import check_media_slug_used - #Is already a slug assigned? Check if it is valid if self.slug: self.slug = slugify(self.slug) - + # otherwise, try to use the title. elif self.title: # assign slug based on title self.slug = slugify(self.title) - + # We don't want any empty string slugs if self.slug == u"": self.slug = None @@ -98,24 +102,33 @@ class MediaEntryMixin(object): # so just return... we're not going to force one. if not self.slug: return # giving up! - + # Otherwise, let's see if this is unique. - if check_media_slug_used(self.uploader, self.slug, self.id): + if self.check_slug_used(self.slug): # It looks like it's being used... lame. - + # Can we just append the object's id to the end? if self.id: slug_with_id = u"%s-%s" % (self.slug, self.id) - if not check_media_slug_used(self.uploader, - slug_with_id, self.id): + if not self.check_slug_used(slug_with_id): self.slug = slug_with_id return # success! - + # okay, still no success; # let's whack junk on there till it's unique. - self.slug += '-' - while check_media_slug_used(self.uploader, self.slug, self.id): - self.slug += uuid4().hex[:4] + self.slug += '-' + uuid.uuid4().hex[:4] + # keep going if necessary! + while self.check_slug_used(self.slug): + self.slug += uuid.uuid4().hex[:4] + + +class MediaEntryMixin(GenerateSlugMixin): + def check_slug_used(self, slug): + # import this here due to a cyclic import issue + # (db.models -> db.mixin -> db.util -> db.models) + from mediagoblin.db.util import check_media_slug_used + + return check_media_slug_used(self.uploader, slug, self.id) @property def description_html(self): @@ -125,32 +138,38 @@ class MediaEntryMixin(object): """ return cleaned_markdown_conversion(self.description) - def get_display_media(self, media_map, - fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER): - """ - Find the best media for display. + def get_display_media(self): + """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 + We try checking self.media_manager.fetching_order if it exists to + pull down the order. Returns: - (media_size, media_path) + (media_size, media_path) + or, if not found, None. + """ - media_sizes = media_map.keys() + fetch_order = self.media_manager.media_fetch_order + + # No fetching order found? well, give up! + if not fetch_order: + return None + + media_sizes = self.media_files.keys() - for media_size in common.DISPLAY_IMAGE_FETCHING_ORDER: + for media_size in fetch_order: if media_size in media_sizes: - return media_map[media_size] + return media_size, self.media_files[media_size] def main_mediafile(self): pass @property def slug_or_id(self): - return (self.slug or self.id) - + if self.slug: + return self.slug + else: + return u'id:%s' % self.id def url_for_self(self, urlgen, **extra_args): """ @@ -183,20 +202,31 @@ class MediaEntryMixin(object): thumb_url = mg_globals.app.staticdirector(manager[u'default_thumb']) return thumb_url + @property + def original_url(self): + """ Returns the URL for the original image + will return self.thumb_url if original url doesn't exist""" + if u"original" not in self.media_files: + return self.thumb_url + + return mg_globals.app.public_store.file_url( + self.media_files[u"original"] + ) + @cached_property def media_manager(self): """Returns the MEDIA_MANAGER of the media's media_type 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 + 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): """ @@ -210,15 +240,60 @@ class MediaEntryMixin(object): return licenses.get_license_by_url(self.license or "") def exif_display_iter(self): - from mediagoblin.tools.exif import USEFUL_TAGS + if not self.media_data: + return + exif_all = self.media_data.get("exif_all") + + for key in exif_all: + label = re.sub('(.)([A-Z][a-z]+)', r'\1 \2', key) + yield label.replace('EXIF', '').replace('Image', ''), exif_all[key] + def exif_display_data_short(self): + """Display a very short practical version of exif info""" if not self.media_data: return + exif_all = self.media_data.get("exif_all") - for key in USEFUL_TAGS: - if key in exif_all: - yield key, exif_all[key] + exif_short = {} + + if 'Image DateTimeOriginal' in exif_all: + # format date taken + takendate = datetime.strptime( + exif_all['Image DateTimeOriginal']['printable'], + '%Y:%m:%d %H:%M:%S').date() + taken = takendate.strftime('%B %d %Y') + + exif_short.update({'Date Taken': taken}) + + aperture = None + if 'EXIF FNumber' in exif_all: + fnum = str(exif_all['EXIF FNumber']['printable']).split('/') + + # calculate aperture + if len(fnum) == 2: + aperture = "f/%.1f" % (float(fnum[0])/float(fnum[1])) + elif fnum[0] != 'None': + aperture = "f/%s" % (fnum[0]) + + if aperture: + exif_short.update({'Aperture': aperture}) + + short_keys = [ + ('Camera', 'Image Model', None), + ('Exposure', 'EXIF ExposureTime', lambda x: '%s sec' % x), + ('ISO Speed', 'EXIF ISOSpeedRatings', None), + ('Focal Length', 'EXIF FocalLength', lambda x: '%s mm' % x)] + + for label, key, fmt_func in short_keys: + try: + val = fmt_func(exif_all[key]['printable']) if fmt_func \ + else exif_all[key]['printable'] + exif_short.update({label: val}) + except KeyError: + pass + + return exif_short class MediaCommentMixin(object): @@ -230,23 +305,28 @@ class MediaCommentMixin(object): """ return cleaned_markdown_conversion(self.content) + def __unicode__(self): + return u'<{klass} #{id} {author} "{comment}">'.format( + klass=self.__class__.__name__, + id=self.id, + author=self.get_author, + comment=self.content) -class CollectionMixin(object): - def generate_slug(self): + def __repr__(self): + return '<{klass} #{id} {author} "{comment}">'.format( + klass=self.__class__.__name__, + id=self.id, + author=self.get_author, + comment=self.content) + + +class CollectionMixin(GenerateSlugMixin): + def check_slug_used(self, slug): # import this here due to a cyclic import issue # (db.models -> db.mixin -> db.util -> db.models) from mediagoblin.db.util import check_collection_slug_used - self.slug = slugify(self.title) - - duplicate = check_collection_slug_used(mg_globals.database, - self.creator, self.slug, self.id) - - if duplicate: - if self.id is not None: - self.slug = u"%s-%s" % (self.id, self.slug) - else: - self.slug = None + return check_collection_slug_used(self.creator, slug, self.id) @property def description_html(self):