Example #1
0
    def test_caption__defaults_to_title(self):
        session = Client().session()
        image = Image(title='the title', filename='')
        session.add(image)
        image.add_tags(['cat', 'awesome'])

        eq_(image.caption(), 'the title')
Example #2
0
def add(request_format):
    tag_names = request.form['tags'].split(' ')
    url = request.form['url']

    if url:
        print 'fetching from remote url'
        truck = ImageTruck.new_from_url(url)
    elif request.files['file']:
        image = request.files['file']
        truck = ImageTruck.new_from_stream(image.stream, image.mimetype)
    else:
        abort(400)
    metadata = ImageMetadata.image_metadata(truck.contents)
    print 'potentially reorienting'
    truck.contents = ReorientImage.reorient_image(truck.contents)
    print 'uploading to s3'
    truck.upload()
    session = Client().session()
    image = Image(filename=truck.calculate_filename(),
                  source_url=url,
                  description=request.form.get('description'),
                  title=request.form.get('title'),
                  **metadata)
    album_id = request.form['album']
    if album_id:
        image.album_id = album_id
    session.add(image)
    image.add_tags(tag_names)

    ResizeImage.make_resizes(image, truck)

    if request_format == 'html':
        return redirect(url_for('show_image', image_id=image.image_id))
    elif request_format == 'json':
        return {'url': truck.url()}
Example #3
0
    def test_find_by_filename__is_case_insensitive(self):
        session = Client().session()
        session.add(Image(filename='deadbeef', source_url='example.com/foo'))
        session.flush()

        image = Image.find_by_filename('DEADBEEF')
        eq_(image.source_url, 'example.com/foo')
    def file_type_test(self,
                       bucket_method,
                       test_file_name,
                       content_type,
                       resized_size):
        bucket = Mock()
        bucket_method.return_value = bucket
        new_key = Mock()
        bucket.new_key.return_value = new_key
        test_file = os.path.join(os.path.dirname(__file__), test_file_name)
        image_handler = ImageHandler.open(test_file)
        with open(test_file, 'r') as fh:
            truck = ImageTruck.new_from_stream(fh, content_type)
        session = Client().session()
        image = ImageTable(filename='badcafe')
        session.add(image)
        session.flush()

        ResizeImage._resize_image(image, image_handler, truck, 'thumbnail')

        new_key.set_metadata.assert_called_with('Content-Type', content_type)
        resized_contents = new_key.set_contents_from_string.call_args[0][0]

        image_handler = ImageHandler.open(StringIO.StringIO(resized_contents))
        eq_(image_handler.size, resized_size)
Example #5
0
    def test_upload_an_image_with_json_format(self, ImageTruck, delay):
        truck = Mock()
        ImageTruck.new_from_url.return_value = truck
        truck.filename = 'CA741C'
        truck.url.return_value = 'cloudfrunt.nut/CA741C'
        truck.contents = b''
        truck.content_type = "image/gif"

        task_id = str(uuid.uuid4())
        delay.return_value = task_id

        response = self.app.post('/add.json', data={
            'album': '',
            'url': 'imgur.com/cool_cat.gif'})
        eq_(response.status_code, 200, response.data)

        session = Client().session()
        image = session.query(Image).one()
        body = json.loads(response.data)

        eq_(body,
            [{
                'url': 'cloudfrunt.nut/CA741C',
                'image_id': image.image_id,
                'task_id': task_id,
            }])
        contents = session.query(ImageContents).one()
        eq_(contents.image_id, image.image_id)
        delay.assert_called_with([],
                                 process_image,
                                 contents.image_contents_id)
Example #6
0
    def test_add_tag_to_an_untagged_image(self):
        session = Client().session()
        pic = Image(filename="tagless", title="Untagged Picture")
        session.add(pic)
        session.flush()

        self.visit_url('/image/{0}'.format(pic.image_id))

        tag_button = self.browser.find_by_id('tag-button')
        assert tag_button, "Couldn't find a button for listing tags!"
        tag_button.click()

        tag_list = self.browser.find_by_css('ul.view-tags')
        assert not tag_list.visible, "Popped up an empty tag dropdown!"

        self.browser.click_link_by_text('Edit')
        add_tag = self.browser.find_by_css('a.add-tag')
        add_tag.click()
        tag_input = self.browser.find_by_id('tag')[0]
        tag_input.fill('untagged\n')

        self.browser.click_link_by_text('Stop Editing')
        tag_button.click()
        tags = self.browser.find_by_css('li.tag')
        assert all([t.visible for t in tags]), "Tag listing was not visible!"
        eq_([t.text for t in tags], ['untagged'])
Example #7
0
    def _resize_image(cls, image, image_handler, truck, size):
        session = Client().session()

        (width, height) = image_handler.size
        (new_width, new_height) = cls._new_dimensions(width,
                                                      height,
                                                      RESIZES[size])

        print 'resizing to %s' % size
        resized = image_handler.resize((new_width, new_height),
                                       ImageHandler.ANTIALIAS)
        (_, contents_file) = tempfile.mkstemp()
        try:
            resized.save(contents_file, image_handler.format)
            with open(contents_file, 'r') as contents:
                print 'uploading resized image'
                truck.upload_resize(contents.read(), size)
        finally:
            os.unlink(contents_file)

        resize = ImageResize(image_id=image.image_id,
                             width=new_width,
                             height=new_height,
                             suffix=size)
        session.add(resize)
        session.flush()
Example #8
0
    def test_add_tag_to_an_untagged_image(self):
        session = Client().session()
        pic = Image(filename="tagless", title="Untagged Picture")
        session.add(pic)
        session.flush()

        self.visit_url('/image/{0}'.format(pic.image_id))

        tag_button = self.browser.find_by_id('tag-button')
        assert tag_button, "Couldn't find a button for listing tags!"
        assert tag_button.has_class("disabled"), \
            "Tag button enabled without tags!"

        self.browser.click_link_by_text('Edit')
        add_tag = self.browser.find_by_css('a.add-tag')
        add_tag.click()
        tag_input = self.browser.find_by_id('tag')[0]
        tag_input.type('untagged')
        tag_input.type(Keys.ENTER)

        self.browser.click_link_by_text('Stop Editing')
        tag_button.click()
        tags = self.browser.find_by_css('li.tag')
        assert all([t.visible for t in tags]), "Tag listing was not visible!"
        eq_([t.text for t in tags], ['untagged'])
Example #9
0
def get_item_batch(tag_names, table_name, attributes_to_get):
    if not tag_names:
        raise StopIteration

    tag_names = list(set(tag_names))

    unprocessed_keys = tag_names[MAX_ITEMS_TO_REQUEST:]
    tag_names = tag_names[:MAX_ITEMS_TO_REQUEST]

    dynamo = Client().get_dynamodb()
    table = Client().table(table_name)
    batch_list = BatchList(dynamo)
    batch_list.add_batch(table, tag_names,
            attributes_to_get=attributes_to_get + [HASH_KEY])
    response = dynamo.batch_get_item(batch_list)
    items = response['Responses'][table.name]['Items']
    if response['UnprocessedKeys'] \
            and table.name in response['UnprocessedKeys']:
        for key in response['UnprocessedKeys'][table.name]['Keys']:
            unprocessed_keys.append(key['HashKeyElement'])

    for item in items:
        yield item
    for item in get_item_batch(unprocessed_keys, table_name, attributes_to_get):
        yield item
Example #10
0
    def test_change_album(self):
        session = Client().session()
        image = Image(filename='deadbeef')
        session.add(image)
        migrant = Album(name='migrant')
        pink_friday = Album(name="Pink Friday")
        session.add(migrant)
        session.add(pink_friday)
        session.flush()

        self.visit_url('/image/%d' % image.image_id)
        assert self.browser.is_text_present('image has no album')
        assert self.browser.is_text_present('set album')

        set_album = self.browser.find_by_css('#set-album').first
        set_album.click()
        self.browser.select('album', pink_friday.album_id)
        assert self.browser.is_text_present(
            "image appears in the album 'Pink Friday'"),\
            "Album info wasn't present"

        del image
        image = session.query(Image).one()
        eq_(image.album_id, pink_friday.album_id)

        self.visit_url('/image/%d' % image.image_id)
        assert self.browser.is_text_present(
            "image appears in the album 'Pink Friday'"),\
            "Album info wasn't right after reload"
Example #11
0
    def test_upload_an_image_twice(self,
                                   ImageTruck,
                                   ImageMetadata,
                                   ResizeImage):
        truck = Mock()
        ImageTruck.new_from_stream.return_value = truck
        truck.calculate_filename.return_value = 'CA7'
        truck.calculate_filename.return_value = 'CA7'
        truck.url.return_value = 'ess three'
        ImageMetadata.image_metadata.return_value = {}

        response = self.app.post('/add', data={
            'tags': 'pet',
            'url': '',
            'album': '',
            'file': (StringIO(str('booya')), 'img.jpg')})
        eq_(response.status_code, 302)
        response = self.app.post('/add', data={
            'tags': 'pet',
            'url': '',
            'album': '',
            'file': (StringIO(str('booya')), 'img.jpg')})
        eq_(response.status_code, 302)

        session = Client().session()
        image = session.query(Image).one()
        image_tags = session.query(ImageTag.image_id).all()
        eq_(image_tags, [(image.image_id,)])
Example #12
0
    def test_upload_an_image(self, ImageTruck, ResizeImage, ImageMetadata):
        truck = Mock()
        ImageTruck.new_from_stream.return_value = truck
        truck.calculate_filename.return_value = 'CA7'
        truck.url.return_value = 'ess three'
        ImageMetadata.image_metadata.return_value = {
            'camera': 'Samsung NX210',
            'photographed_at': '2013-05-09 12:00:00',
            'focal_length': 30,
            'aperture': '1/1.8',
            'shutter_speed': 5,
            'iso': '400'}

        response = self.app.post('/add', data={
            'album': '',
            'tags': 'pet cool',
            'url': '',
            'title': 'My cat being awesome',
            'description': 'my cat is awesome. You can see how awesome.',
            'file': (StringIO(str('booya')), 'img.jpg')})

        session = Client().session()
        image = session.query(Image).one()

        eq_(image.filename, 'CA7')
        eq_(image.source_url, '')
        eq_(image.title, 'My cat being awesome')
        eq_(image.description, 'my cat is awesome. You can see how awesome.')

        ResizeImage.make_resizes.assert_called_with(image, truck)

        eq_(response.status_code, 302, response.data)
        eq_(response.headers['Location'],
            'http://localhost/image/%d' % image.image_id)
Example #13
0
    def test_caption__falls_back_to_tags(self):
        session = Client().session()
        image = Image(title='', filename='')
        session.add(image)
        image.add_tags(['cat', 'awesome'])

        eq_(image.caption(), 'awesome cat')
Example #14
0
def coordinated_commit(queued_tasks):
    session = Client().session()
    try:
        session.commit()
    except sqlalchemy.exc.OperationalError as sqlError:
        # If we've sent tasks to redis but have lost the database, those tasks
        # probably point to invalid data. They'll likely fail anyway when the
        # worker can't get the database, and even if they don't, whatever
        # operation they relate to has been lost.

        exc_info = sys.exc_info()
        try:
            for task in queued_tasks:
                task.revoke()
        except (redis.exceptions.ConnectionError,
                redis.exceptions.TimeoutError) as redisError:
            # If we've lost the database, redis connection errors seem likely.
            # Try to report the whole failure.
            raise SkyIsFallingError(sqlError, redisError), None, exc_info[2]

        raise sqlError, None, exc_info[2]
    except (sqlalchemy.exc.DatabaseError,
            sqlalchemy.exc.StatementError) as sqlError:
        exc_info = sys.exc_info()
        try:
            # If we've sent tasks to redis, they probably point to invalid
            # data. Even if they don't, whatever operation they relate to was
            # invalid in some way or another, so this needs to be a
            # coordinated rollback.
            coordinated_rollback(queued_tasks)
            raise sqlError, None, exc_info[2]
        except (redis.exceptions.ConnectionError,
                redis.exceptions.TimeoutError) as redisError:
            raise SkyIsFallingError(sqlError, redisError), None, exc_info[2]
Example #15
0
def show_add(request_format):
    session = Client().session()
    albums = session.query(Album).all()
    if request_format == 'html':
        return render_template('add.html.jinja', user=g.user, albums=albums)
    elif request_format == 'json':
        return {'albums': albums}
Example #16
0
    def file_type_test(self,
                       bucket_method,
                       test_file,
                       content_type,
                       resized_size):
        bucket = Mock()
        bucket_method.return_value = bucket
        new_key = Mock()
        bucket.new_key.return_value = new_key
        image_handler = ImageHandler(filename=test_file)
        truck = ImageTruck.new_from_file(test_file)
        session = Client().session()
        image = ImageTable(filename='badcafe')
        session.add(image)
        session.flush()
        after_upload = Mock()

        ResizeImage._resize_image(image,
                                  image_handler,
                                  truck,
                                  'thumbnail',
                                  after_upload)

        new_key.set_metadata.assert_called_with('Content-Type', content_type)
        resized_contents = new_key.set_contents_from_string.call_args[0][0]

        image_handler = ImageHandler(blob=resized_contents)
        eq_(image_handler.size, resized_size)

        after_upload.assert_called_once_with('thumbnail')
Example #17
0
    def run(self, image_id, suffix=None):
        session = Client().session()
        now = time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())
        try:
            image = session.query(Image).\
                filter((Image.created_at - timedelta(hours=1)) < now).\
                filter(Image.image_id == image_id).\
                one()
        except NoResultFound:
            session.rollback()
            logger.error('No unexpired result found for image_id {0}. '
                         'Skipping.'.format(image_id))
            return

        filename = image.filename
        print repr(suffix)
        if suffix is not None:
            filename = '{0}_{1}'.format(filename, suffix)

        config = Client().config()
        try:
            distro_id = config['aws.cloudfront_distribution_id']
            Client().get_cloudfront().create_invalidation_request(
                distro_id, [filename])
        except KeyError:
            pass
        except CloudFrontServerError as e:
            if e.error_code == 'TooManyInvalidationsInProgress':
                self.retry(exc=e)
            else:
                raise
Example #18
0
def show_add(request_format):
    session = Client().session()
    albums = session.query(Album).all()
    if request_format == "html":
        return render_template("add.html.jinja", albums=albums)
    elif request_format == "json":
        return {"albums": albums}
Example #19
0
    def test_toomanyinvalidation_errors_cause_retry(self, MockClient):
        error = CloudFrontServerError(400, 'Bad Request')
        error.error_code = 'TooManyInvalidationsInProgress'

        cloudfront = Mock()
        cloudfront.create_invalidation_request.side_effect = error

        config = Client().config()
        client = Mock()
        client.config.return_value = config
        client.get_cloudfront.return_value = cloudfront
        MockClient.return_value = client

        session = Client().session()
        transaction_id = TaskTransaction.new_id()
        image = Image(filename='abad1dea')
        image.created_at = '2001-01-01 00:00:00'
        session.add(image)
        session.flush()

        invalidate = NeverCalledDirectlyInvalidate()
        invalidate.retry = Mock()
        invalidate(transaction_id, image.image_id)

        invalidate.retry.assert_called_with(exc=error)
Example #20
0
    def test_upload_an_image_twice(self, ImageTruck, delay):
        truck = Mock()
        ImageTruck.new_from_stream.return_value = truck
        truck.filename = 'CA7'
        truck.url.return_value = 'ess three'
        truck.contents = b''
        truck.content_type = "image/jpeg"

        response = self.app.post('/add', data={
            'url': '',
            'file': (StringIO(str('booya')), 'img.jpg')})
        eq_(response.status_code, 302)
        response = self.app.post('/add', data={
            'url': '',
            'file': (StringIO(str('booya')), 'img.jpg')})
        eq_(response.status_code, 302)

        session = Client().session()
        image = session.query(Image).one()
        contentses = session.query(ImageContents).all()
        for contents in contentses:
            eq_(contents.image_id, image.image_id)
        contents_calls = [call([], process_image, x.image_contents_id)
                          for x in contentses]
        delay.assert_has_calls(contents_calls)
Example #21
0
    def test_find_by_filename(self):
        session = Client().session()
        session.add(Image(filename='deadbeef', source_url='example.com/foo'))
        session.flush()

        image = Image.find_by_filename('deadbeef')
        eq_(image.source_url, 'example.com/foo')
Example #22
0
    def test_add_an_album(self):
        response = self.app.post('/new_album', data={'name': 'my pics'})
        eq_(response.status_code, 302, response.data)
        eq_(response.headers['Location'], 'http://localhost/add')

        session = Client().session()
        albums = session.query(Album.name).all()
        eq_(albums, [('my pics',)])
Example #23
0
 def test_on_view_album(self):
     session = Client().session()
     album = Album(name="fotozzzz")
     session.add(album)
     session.flush()
     self.visit_url('/album/{0}'.format(album.album_id))
     assert self.browser.is_text_present('Log out'), \
         "Page didn't act like logged in"
Example #24
0
 def test_on_view_image(self):
     session = Client().session()
     image = Image(filename='bab1eface', title='face of a baby')
     session.add(image)
     session.flush()
     self.visit_url('/image/{0}'.format(image.image_id))
     assert self.browser.is_text_present('Log out'), \
         "Page didn't act like logged in"
Example #25
0
    def test_creating_with_a_new_source_url_updates_existing_record(self):
        session = Client().session()
        session.add(Image(filename='badcafe', source_url='example.com'))
        session.flush()
        session.add(Image(filename='badcafe', source_url='examp.le'))
        session.flush()

        source_url = session.query(Image.source_url).first()
        eq_(source_url, ('examp.le',))
Example #26
0
 def wrapper(self, transaction_id, *args, **kwargs):
     session = Client().session()
     transactions_found = session.query(TaskTransaction).\
         filter(TaskTransaction.transaction_id == transaction_id).\
         delete()
     if transactions_found == 0:
         raise self.retry()
     else:
         return task(self, *args, **kwargs)
Example #27
0
    def test_upload_several_images_in_one_go(self, ImageTruck, delay):
        (truck1, truck2, truck3) = (Mock(), Mock(), Mock())

        truck1.filename = 'BAD1DEA'
        truck1.url.return_value = 'cloudfrunt.nut/BAD1DEA'
        truck1.contents = b'boom'
        truck1.content_type = "image/jpeg"

        truck2.filename = 'CAFEBABE'
        truck2.url.return_value = 'cloudfrunt.nut/CAFEBABE'
        truck2.contents = b'shaka'
        truck2.content_type = "image/jpeg"

        truck3.filename = 'DADD1E'
        truck3.url.return_value = 'cloudfrunt.nut/DADD1E'
        truck3.contents = b'laka'
        truck3.content_type = "image/jpeg"

        ImageTruck.new_from_stream.side_effect = [truck1, truck2, truck3]

        id1 = str(uuid.uuid4())
        id2 = str(uuid.uuid4())
        id3 = str(uuid.uuid4())
        delay.side_effect = [id1, id2, id3]

        response = self.app.post('/add.json', data={
            'album': '',
            'url': '',
            'file[]': [
                (StringIO(str('boom')), 'image_1.jpg'),
                (StringIO(str('shaka')), 'image_2.jpg'),
                (StringIO(str('laka')), 'image_3.jpg'),
            ]})
        eq_(response.status_code, 200, response.data)

        session = Client().session()
        images = session.query(Image).all()
        body = json.loads(response.data)

        eq_(body, [
            {
                'url': 'cloudfrunt.nut/BAD1DEA',
                'image_id': images[0].image_id,
                'task_id': id1,
            },
            {
                'url': 'cloudfrunt.nut/CAFEBABE',
                'image_id': images[1].image_id,
                'task_id': id2,
            },
            {
                'url': 'cloudfrunt.nut/DADD1E',
                'image_id': images[2].image_id,
                'task_id': id3,
            },
        ])
Example #28
0
    def test_created_at_is_set_at_creation_time(self, mock_time):
        now = time.strptime("2011-05-09 13:01:01", "%Y-%m-%d %H:%M:%S")
        mock_time.strftime = time.strftime
        mock_time.gmtime.return_value = now
        session = Client().session()
        album = Album(name="my pix")
        session.add(album)
        session.flush()

        eq_(album.created_at, "2011-05-09 13:01:01")
Example #29
0
 def get_filenames(self):
     from catsnap.table.image import Image
     from catsnap.table.image_tag import ImageTag
     session = Client().session()
     filenames = session.query(Image.filename).\
             join(ImageTag).\
             filter(ImageTag.image_id == Image.image_id).\
             filter(ImageTag.tag_id == self.tag_id)
     for filename in filenames:
         yield filename[0]
Example #30
0
 def remove_tag(self, tag_name):
     from catsnap.table.image_tag import ImageTag
     from catsnap.table.tag import Tag
     session = Client().session()
     image_tag = session.query(ImageTag).\
             join(Tag, Tag.tag_id == ImageTag.tag_id).\
             filter(Tag.name == tag_name).\
             filter(ImageTag.image_id == self.image_id).\
             one()
     session.delete(image_tag)