def delete_deprecated_image_shapes(self): """ Delete any image shapes that are no longer defined. """ shapes = Media.get_shape_names() deprecated_shapes = [] base_path = Media.get_shape_base_path() try: folders = os.listdir(base_path) except OSError: folders = [] for folder in folders: if not folder.startswith('.') and folder != 'original' and folder not in shapes: path = os.path.join(base_path, folder) if os.path.isdir(path): shutil.rmtree(path) if folder not in deprecated_shapes: deprecated_shapes.append(folder) if len(deprecated_shapes) > 0: print '%d deprecated image shape(s) deleted (%s).' % ( len(deprecated_shapes), ', '.join(deprecated_shapes) )
def test_add_media_to_gallery_should_create_media_gallery(self): cms = get_cms() p = self.create_page('Page') m = Media() m.save() self.assertEqual(len(MediaGallery.objects.filter(target_id=p.pk)), 0) cms.add_media_to_gallery(p, m) self.assertEqual(len(MediaGallery.objects.filter(target_id=p.pk)), 1)
def get_deploy_context(): from cubane.media.models import Media image_sizes = {} image_sizes['xxx_large'] = 2400 image_sizes['xx_large'] = 1600 for image in settings.IMAGE_SIZES: name = image.replace('-', '_') image_sizes[name] = settings.IMAGE_SIZES[image] disable_device_ratio = 'true' if settings.DISABLE_DEVICE_RATIO else 'false' shapes = Media.get_shape_list() image_art_direction = Media.get_art_direction() # generate list of choke-points image_size_list = [ image_sizes.get('xxx_large'), image_sizes.get('xx_large'), image_sizes.get('x_large'), image_sizes.get('large'), image_sizes.get('medium'), image_sizes.get('small'), image_sizes.get('x_small'), image_sizes.get('xx_small'), image_sizes.get('xxx_small') ] # names of image shapes image_size_names = [ 'xxx-large', 'xx-large', 'x-large', 'large', 'medium', 'small', 'x-small', 'xx-small', 'xxx-small' ] # list of aspect ratios poer shape aspect_ratio_by_shape = dict([(shape.get('name'), shape.get('ratio_percent')) for shape in shapes]) return { 'image_sizes': image_sizes, 'disable_device_ratio': disable_device_ratio, 'shapes': shapes, 'MEDIA_URL': settings.MEDIA_URL, 'MEDIA_API_URL': settings.MEDIA_API_URL, 'image_art_direction': image_art_direction, 'image_art_direction_json': to_json(image_art_direction), 'image_size_list_json': to_json(image_size_list), 'image_size_names_json': to_json(image_size_names), 'aspect_ratio_by_shape': to_json(aspect_ratio_by_shape) }
def _render_image(self, lightbox=False, media_id=1, markup_media_id=1): page = Page() page.set_slot_content('content', self._image_markup(lightbox, markup_media_id)) return self._render( "{% load cms_tags %}{% slot 'content' %}", { 'page': page, 'images': { media_id: Media(id=media_id, caption='Test', width=64, height=64) } })
def test_gallery_property_should_return_attached_media_in_seq(self): self.page.title = 'Test' self.page.save() content_type = ContentType.objects.get_for_model(self.page.__class__) names = ['c', 'b', 'a'] for seq, name in enumerate(names, start=1): m = Media(caption=name) m.save() mg = MediaGallery() mg.media = m mg.content_type = content_type mg.target_id = self.page.pk mg.seq = seq mg.save() self.assertEqual(names, [m.caption for m in self.page.gallery]) [mg.delete() for mg in MediaGallery.objects.all()] [m.delete() for m in Media.objects.all()] self.page.delete()
def test_should_fallback_to_original_shape_if_specified_shape_does_not_exist( self): page = Page() page.set_slot_content('content', self._image_markup()) html = self._render( "{% load cms_tags %}{% slot 'content' 0 'shape-does-not-exist' %}", { 'page': page, 'images': { 1: Media(id=1, caption='Test', width=64, height=64) } }) self.assertMarkup(html, 'noscript', {'data-shape': 'original'})
def test_content_by_slot_with_image_rewrite(self): self.page.set_slot_content('content', '<img data-cubane-media-id="1"/>') images = {1: Media(id=1, caption='Test')} html = self.page.content_by_slot(images).get('content') self.assertIn('class="lazy-load-shape-original"', html) self.assertIn('style="padding-bottom:100.0%;"', html) self.assertIn('data-shape="original"', html) self.assertIn('data-path="/0/1/"', html) self.assertIn('data-blank="0"', html) self.assertIn('data-sizes="xx-small"', html) self.assertIn( '<img src="http://www.testapp.cubane.innershed.com/media/shapes/original/xx-small/0/1/" alt="Test" title="Test">', html)
def _assert_media_filter(self, widths, image_size, expected_widths): media = [] for w in widths: m = Media(width=w) m.save() media.append(m) self.assertEqual(expected_widths, [ m.width for m in Media.filter_by(Media.objects.all(), image_size) ]) for m in media: m.delete()
def test_delete_media_asset_should_remove_physical_files(self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.jpg'), 'Test') files = [ self.m.original_path, ] for size in self.m.get_available_image_sizes(): files.append( self.m.get_image_path(size, settings.DEFAULT_IMAGE_SHAPE)) for shape in Media.get_shape_names(): files.append(self.m.get_image_path(size, shape)) for f in files: self.assertTrue(os.path.isfile(f), f) self.m.delete() for f in files: self.assertFalse(os.path.isfile(f), f)
def create_media_object(self, caption, filename, folder=None): """ Create a new media item object within the media library based on the given meta data. This will simply create the meta data but will not upload or store any actual image/document data and it is assumed that this happens outside of the image media object creation. """ # generate caption based on filename if provided if not caption and filename: caption = get_caption_from_filename(filename) media = Media() media.caption = caption media.filename = filename if folder: media.parent = folder media.save() return media
def create_blank_external_media(self, url, filename=None, caption=None, folder=None): """ Create a new (blank) media item with the given external url and optionally the given parent folder. """ media = Media() media.is_blank = True media.external_url = url # generate filename based on given url url_parts = urlparse.urlparse(url) path = url_parts.path # filename if filename: media.filename = filename else: media.filename = os.path.basename(path) # generate caption from filename if caption: media.caption = caption else: media.caption = get_caption_from_filename(media.filename) # folder if folder: media.folder = folder media.save() # notify task runner that there is something to do TaskRunner.notify() return media
def handle(self, *args, **options): """ Run command. """ # determine images to work with process_documents = False if options.get('documents'): # documents only images = Media.objects.filter( is_image=False, has_preview=True ) process_documents = True elif options.get('images'): # images only images = Media.objects.filter( is_image=True ) else: # images and docuements images = Media.objects.filter( Q(is_image=True) | Q(has_preview=True) ) process_documents = True # specific pk? if options.get('pk'): images = images.filter(pk=options.get('pk')) # continuation if options.get('continue'): continue_filename = options.get('continue') else: continue_filename = None # specific shape? shape = options.get('shape') if shape: shapes = Media.get_shapes().keys() if shape not in shapes: print 'ERROR: Invalid shape name \'%s\'. Available shapes: %s.' % ( shape, ', '.join(['\'%s\'' % s for s in shapes]) ) return # re-evaluate PDF files for media in Media.objects.filter(is_image=False, has_preview=False): if get_ext(media.filename) == 'pdf': media.has_preview = True media.save() # delete deprecated image shapes and sizes self.delete_deprecated_image_sizes() self.delete_deprecated_image_shapes() # determine count of images to process... n = images.count() # process images print 'Processing images...Please Wait...' process_item = continue_filename is None for i, image in enumerate(images, start=1): # continuation? if continue_filename: if image.filename == continue_filename: process_item = True # generate image versions and re-generate meta data if process_item: image.upload(shape=shape) # verbose output print '%-70s [%d%%]' % ( image.filename, int(float(i) / float(n) * 100.0) ) print '%d images processed.' % n
def setUp(self): self.m = Media()
class CMSMediaModelsMediaTestCase(CubaneTestCase): def setUp(self): self.m = Media() def tearDown(self): if self.m.pk: self.m.delete() def test_save_should_generate_uid_if_not_present(self): self.m.save() self.assertIsNotNone(self.m.uid) def test_save_should_ignore_uid_if_present(self): self.m.uid = 'uuid' self.m.save() self.assertEqual('uuid', self.m.uid) def test_save_should_rename_filename_on_disk_if_caption_changed(self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.jpg'), 'Test') self.assertEqual(self.m.caption, 'Test') self.assertEqual(self.m.filename, 'test.jpg') self.assertEqual('test.jpg', os.path.basename(self.m.original_path)) self.assertTrue(os.path.isfile(self.m.original_path)) self.m.caption = 'Hello World' self.m.save() self.assertEqual('Hello World', self.m.caption) self.assertEqual('hello-world.jpg', self.m.filename) self.assertEqual('hello-world.jpg', os.path.basename(self.m.original_path)) self.assertTrue(os.path.isfile(self.m.original_path)) def test_save_should_rename_filename_to_unnamed_on_disk_if_caption_changed_to_empty_string( self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.jpg'), 'Test') self.assertEqual(self.m.caption, 'Test') self.assertEqual(self.m.filename, 'test.jpg') self.m.caption = '' self.m.save() self.assertEqual('', self.m.caption) self.assertEqual('unnamed.jpg', self.m.filename) self.assertEqual('unnamed.jpg', os.path.basename(self.m.original_path)) self.assertTrue(os.path.isfile(self.m.original_path)) def test_save_should_duplicate_file_if_asset_was_duplicated(self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.jpg'), 'Test') # prepare for duplication org = Media.objects.get(pk=self.m.pk) self.m.on_duplicated() self.assertEqual(self.m.pk, self.m._prior_pk) self.assertTrue(self.m._being_duplicated) self.assertIsNone(self.m.uid) self.m.pk = None # save() should create duplicate self.m.caption = 'Hello World' self.m.save() self.assertNotEqual(self.m.pk, org.pk) self.assertNotEqual(self.m.uid, org.uid) self.assertNotEqual(self.m.original_path, org.original_path) self.assertTrue(os.path.isfile(self.m.original_path)) self.assertTrue(os.path.isfile(org.original_path)) # was also renamed due to caption change self.assertEqual('Hello World', self.m.caption) self.assertEqual('hello-world.jpg', self.m.filename) self.assertEqual('hello-world.jpg', os.path.basename(self.m.original_path)) org.delete() def test_get_json_fieldnames_should_return_fieldnames_for_json_encoding( self): self.assertEqual([ 'id', 'caption', 'filename', 'width', 'height', 'is_image', 'url' ], self.m.get_json_fieldnames()) def test_get_form_should_return_default_form(self): self.assertTrue(issubclass(self.m.get_form(), MediaForm)) def test_get_filter_form_should_return_default_form(self): self.assertTrue(issubclass(self.m.get_filter_form(), MediaFilterForm)) def test_filter_by_should_understand_filtering_by_image_size(self): self._assert_media_filter([256, 512, 1024], {'image_size': '200-600'}, [256, 512]) def test_filter_by_image_size_should_ignore_missing_arg(self): self._assert_media_filter([256, 512, 1024], {}, [256, 512, 1024]) def test_filter_by_image_size_should_ignore_incorrect_arg_format(self): self._assert_media_filter([256, 512, 1024], {'image_size': '200'}, [256, 512, 1024]) def test_filter_by_image_size_should_ignore_parsing_error_min_value(self): self._assert_media_filter([256, 512, 1024], {'image_size': 'xxx-200'}, [256, 512, 1024]) def test_filter_by_image_size_should_ignore_parsing_error_max_value(self): self._assert_media_filter([256, 512, 1024], {'image_size': '200-xxx'}, [256, 512, 1024]) @override_settings(IMAGE_SHAPES={'test': '200:200', 'original': '300:200'}) def test_get_shapes_should_ignore_reserved_name_original(self): self._assert_get_shapes({'test': 1.0}) @override_settings(IMAGE_SHAPES={'test': '200:200', 'error': '300'}) def test_get_shapes_should_raise_exception_on_formatting_errors(self): with self.assertRaisesRegexp(ValueError, 'Incorrect shape declaration'): self._assert_get_shapes({'test': 1.0}) @override_settings(IMAGE_SHAPES={'test': '200:200', 'error': '0:300'}) def test_get_shapes_should_raise_exception_on_zero_width(self): with self.assertRaisesRegexp(ValueError, 'Incorrect shape declaration'): self._assert_get_shapes({'test': 1.0}) @override_settings(IMAGE_SHAPES={'test': '200:200', 'error': '300:0'}) def test_get_shapes_should_raise_exception_on_zero_height(self): with self.assertRaisesRegexp(ValueError, 'Incorrect shape declaration'): self._assert_get_shapes({'test': 1.0}) def test_orientation_should_return_landscape_for_landscape_images(self): self._assert_orientation(1024, 512, 'orientation', 'landscape') def test_orientation_should_return_landscape_for_squared_images(self): self._assert_orientation(512, 512, 'orientation', 'landscape') def test_orientation_should_return_portrait_for_portrait_images(self): self._assert_orientation(512, 1024, 'orientation', 'portrait') def test_backend_orientation_should_return_landscape_for_wider_images( self): self._assert_orientation(1024, 512, 'backend_orientation', 'landscape') def test_backend_orientation_should_return_landscape_for_exact_images( self): self._assert_orientation(1024, 1024.0 / Media.BACKEND_IMAGE_RATIO, 'backend_orientation', 'landscape') def test_backend_orientation_should_return_landscape_for_thinner_images( self): self._assert_orientation(512, 1024, 'backend_orientation', 'portrait') def test_backend_listing_orientation_should_return_landscape_for_wider_images( self): self._assert_orientation(1024, 512, 'backend_listing_orientation', 'landscape') def test_backend_listing_orientation_should_return_landscape_for_exact_images( self): self._assert_orientation(1024, 1024.0 / Media.BACKEND_LISTING_IMAGE_RATIO, 'backend_listing_orientation', 'landscape') def test_backend_listing_orientation_should_return_landscape_for_thinner_images( self): self._assert_orientation(512, 1024, 'backend_listing_orientation', 'portrait') def test_bucket_id_should_spread_pk_within_buckets_of_defined_size(self): buckets = {} for i in range(0, 3 * Media.BUCKET_SIZE): self.m.id = i bucket_id = self.m.bucket_id if bucket_id not in buckets: buckets[bucket_id] = 0 buckets[bucket_id] += 1 for bucket_id, n in buckets.items(): self.assertEqual(Media.BUCKET_SIZE, n) def test_original_path_should_combine_base_path_with_bucket_id_pk_and_filename( self): self.m.pk = 433 self.m.filename = 'test.jpg' self.assertTrue( self.m.original_path.endswith('/originals/0/433/test.jpg')) def test_original_url_should_combine_bucket_id_pk_and_filename_matching_physical_path( self): self.m.pk = 433 self.m.filename = 'test.jpg' self.assertEqual( 'http://www.testapp.cubane.innershed.com/media/originals/0/433/test.jpg', self.m.original_url) def test_aspect_ratio_should_return_wdith_over_height(self): self.m.width = 1024 self.m.height = 512 self.assertEqual(2, self.m.aspect_ratio) def test_aspect_ratio_should_return_1_if_height_is_zero(self): self.m.width = 1024 self.m.height = 0 self.assertEqual(1, self.m.aspect_ratio) def test_aspect_ratio_percent_should_represent_aspect_ratio_in_percent( self): self.m.width = 1024 self.m.height = 512 self.assertEqual(50, self.m.aspect_ratio_percent) def test_aspect_ratio_percent_should_return_100_percent_if_height_zero( self): self.m.width = 1024 self.m.height = 0 self.assertEqual(100, self.m.aspect_ratio_percent) def test_get_default_image_size(self): self.m.id = 1 self.m.width = 1000 self.m.height = 500 self.assertEqual((1280, 640), self.m.get_default_image_size()) def test_size_property_should_return_size_display_value(self): self.m.width = 1024 self.m.height = 1250 self.assertEqual('1,024 x 1,250', self.m.size) def test_xxsmall_url(self): self._assert_size_url('xxsmall', 'xx-small') def test_xsmall_url(self): self._assert_size_url('xsmall', 'x-small') def test_small_url(self): self._assert_size_url('small', 'small') def test_medium_url(self): self._assert_size_url('medium', 'medium') def test_large_url(self): self._assert_size_url('large', 'large') def test_xlarge_url(self): self._assert_size_url('xlarge', 'x-large') @override_settings(IMAGE_SIZES={'xx-large': 1600}) def test_xxlarge_url_url(self): self._assert_size_url('xxlarge', 'xx-large') @override_settings(IMAGE_SIZES={'xxx-large': 2400}) def test_xxxlarge_url(self): self._assert_size_url('xxxlarge', 'xxx-large') def test_url_property_should_return_default_url_for_regular_images(self): self.m.id = 1 self.m.width = 1000 self.m.height = 500 self.assertEqual(self.m.default_url, self.m.url) def test_url_property_should_return_original_url_for_svg_images(self): self.m.id = 1 self.m.width = 1000 self.m.height = 500 self.m.is_svg = True self.assertEqual(self.m.original_url, self.m.url) @override_settings(IMG_MAX_WIDTH=600) def test_resize_if_too_wide(self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.jpg'), 'Hobbiton') self.assertEqual(512, self.m.width) self.assertEqual(512, self.m.height) max_width = settings.IMG_MAX_WIDTH settings.IMG_MAX_WIDTH = 400 self.m.resize_if_too_wide() settings.IMG_MAX_WIDTH = max_width self.assertEqual(400, self.m.width) self.assertEqual(400, self.m.height) def test_resize_if_too_wide_should_ignore_non_image_file(self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.txt'), 'Test') self.m.resize_if_too_wide() self.assertEqual(0, self.m.width) self.assertEqual(0, self.m.height) self.assertFalse(self.m.is_image) def test_upload_png_image_without_transparency_should_store_image_as_jpg( self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.png'), 'Test') # verify it's a JPEG file img = open_image(self.m.original_path) self.assertEqual('test.jpg', self.m.filename) self.assertTrue(is_jpeg_image_object(img)) def test_upload_png_with_transparency_should_not_convert_image_to_jpg( self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test_with_transparency.png'), 'Test') # verify it's still a PNG file with transparency layer img = open_image(self.m.original_path) self.assertEqual('test.png', self.m.filename) self.assertTrue(is_png_image_object(img)) def test_delete_media_asset_should_remove_physical_files(self): cms = get_cms() self.m = cms.create_media_from_file( self.get_test_image_path('test.jpg'), 'Test') files = [ self.m.original_path, ] for size in self.m.get_available_image_sizes(): files.append( self.m.get_image_path(size, settings.DEFAULT_IMAGE_SHAPE)) for shape in Media.get_shape_names(): files.append(self.m.get_image_path(size, shape)) for f in files: self.assertTrue(os.path.isfile(f), f) self.m.delete() for f in files: self.assertFalse(os.path.isfile(f), f) def test_get_available_image_sizes_should_return_available_image_sizes( self): self.m.width = 512 self.m.height = 512 self.assertEqual( { 'small': 254, 'large': 738, 'xx-small': 75, 'medium': 336, 'x-small': 149 }, self.m.get_available_image_sizes()) def test_get_image_url_or_smaller(self): self.m.id = 1 self.m.width = 600 self.m.height = 600 self.assertEqual( 'http://www.testapp.cubane.innershed.com/media/shapes/original/large/0/1/', self.m.get_image_url_or_smaller('x-large')) @override_settings(IMAGE_SHAPES={'landscape': '400:200'}) def test_get_width(self): delattr(Media, '_shapes') self.m.width = 600 self.assertEqual(1280, self.m.get_width('x-large', 'landscape')) @override_settings(IMAGE_SHAPES={'landscape': '400:200'}) def test_get_height(self): delattr(Media, '_shapes') self.m.width = 600 self.assertEqual(640, self.m.get_height('x-large', 'landscape')) def test_set_filename_should_set_caption_if_not_set(self): self.m.set_filename('hello_world.jpg') self.assertEqual('hello-world.jpg', self.m.filename) self.assertEqual('Hello World', self.m.caption) def test_set_filename_should_not_exceed_os_max_filename_length(self): fn = 'x' * MAX_FILENAME_LENGTH + '.jpg' self.m.set_filename(fn) self.assertEqual('x' * (MAX_FILENAME_LENGTH - 4) + '.jpg', self.m.filename) self.assertTrue(len(self.m.filename) <= MAX_FILENAME_LENGTH) @override_settings(IMAGE_SHAPES={'landscape': '400:200'}) def test_to_dict(self): delattr(Media, '_shapes') self.m.id = 1 self.m.width = 600 self.m.height = 600 self.m.filename = 'test.jpg' self.m.caption = 'Test' self.m.is_image = True self.assertEqual( { 'url': 'http://www.testapp.cubane.innershed.com/media/shapes/original/large/0/1/test.jpg', 'original_url': u'http://www.testapp.cubane.innershed.com/media/originals/0/1/test.jpg', 'caption': 'Test', 'shapes': { 'original': { 'small': 'http://www.testapp.cubane.innershed.com/media/shapes/original/small/0/1/test.jpg', 'large': 'http://www.testapp.cubane.innershed.com/media/shapes/original/large/0/1/test.jpg', 'xx-small': 'http://www.testapp.cubane.innershed.com/media/shapes/original/xx-small/0/1/test.jpg', 'medium': 'http://www.testapp.cubane.innershed.com/media/shapes/original/medium/0/1/test.jpg', 'x-small': 'http://www.testapp.cubane.innershed.com/media/shapes/original/x-small/0/1/test.jpg' }, 'landscape': { 'small': 'http://www.testapp.cubane.innershed.com/media/shapes/landscape/small/0/1/test.jpg', 'large': 'http://www.testapp.cubane.innershed.com/media/shapes/landscape/large/0/1/test.jpg', 'xx-small': 'http://www.testapp.cubane.innershed.com/media/shapes/landscape/xx-small/0/1/test.jpg', 'medium': 'http://www.testapp.cubane.innershed.com/media/shapes/landscape/medium/0/1/test.jpg', 'x-small': 'http://www.testapp.cubane.innershed.com/media/shapes/landscape/x-small/0/1/test.jpg' } }, 'id': 1, 'hashid': None, 'is_svg': False, 'lastmod': None }, self.m.to_dict()) def _assert_media_filter(self, widths, image_size, expected_widths): media = [] for w in widths: m = Media(width=w) m.save() media.append(m) self.assertEqual(expected_widths, [ m.width for m in Media.filter_by(Media.objects.all(), image_size) ]) for m in media: m.delete() def _assert_get_shapes(self, expected_shapes): delattr(Media, '_shapes') shapes = Media.get_shapes() self.assertEqual(expected_shapes, shapes) def _assert_orientation(self, width, height, attr, expected_orientation): self.m.width = width self.m.height = height self.assertEqual(expected_orientation, getattr(self.m, attr)) def _assert_size_url(self, size, url_size): self.m.id = 1 self.m.width = 2400 self.m.height = 2400 self.assertEqual( 'http://www.testapp.cubane.innershed.com/media/shapes/original/%s/0/1/' % url_size, getattr(self.m, '%s_url' % size))
def _assert_get_shapes(self, expected_shapes): delattr(Media, '_shapes') shapes = Media.get_shapes() self.assertEqual(expected_shapes, shapes)