コード例 #1
0
ファイル: image.py プロジェクト: pythonchelle/catsnap
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()}
コード例 #2
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    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')
コード例 #3
0
ファイル: test_invalidate.py プロジェクト: ErinCall/catsnap
    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)
コード例 #4
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    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')
コード例 #5
0
    def test_get_image_info_as_json(self):
        session = Client().session()
        album = Album(name='cow shots')
        session.add(album)
        session.flush()
        image = Image(filename='deadbeef',
                      description='one time I saw a dead cow',
                      title='dead beef',
                      album_id=album.album_id)

        session.add(image)
        image.add_tags(['cow', 'dead'])
        session.flush()

        response = self.app.get('/image/%d.json' % image.image_id)
        eq_(json.loads(response.data), {
            'description': 'one time I saw a dead cow',
            'title': 'dead beef',
            'album_id': album.album_id,
            'tags': [ 'cow', 'dead', ],
            'source_url': 'https://s3.amazonaws.com/snapcats/deadbeef',
            'camera': None,
            'photographed_at': None,
            'focal_length': None,
            'aperture': None,
            'shutter_speed': None,
            'iso': None,
            })
コード例 #6
0
ファイル: image.py プロジェクト: ErinCall/catsnap
def add(request_format):
    url = request.form.get("url")

    if url:
        try:
            trucks = [ImageTruck.new_from_url(url)]
        except RequestException:
            abort(request_format, 400, "That url is no good.")
        except TryHTTPError:
            abort(
                request_format,
                400,
                "Catsnap couldn't establish an HTTPS connection to that "
                "image. An HTTP connection may succeed (this is a problem "
                "on Catsnap's end, not something you did wrong).",
            )
    elif request.files.get("file[]"):
        trucks = [ImageTruck.new_from_stream(data.stream) for data in request.files.getlist("file[]")]
    elif request.files.get("file"):
        data = request.files["file"]
        trucks = [ImageTruck.new_from_stream(data.stream)]
    else:
        abort(request_format, 400, "Please submit either a file or a url.")

    # These loops are sorta awkwardly phrased to avoid lots of round-tripping
    # to the database. I hope you don't consider the optimization premature.
    session = Client().session()
    images = []
    for truck in trucks:
        image = Image(filename=truck.filename, source_url=url)
        album_id = request.form.get("album_id")
        if album_id:
            image.album_id = int(album_id)
        session.add(image)
        images.append(image)

    session.flush()
    contentses = []
    for i in xrange(0, len(images)):
        (truck, image) = trucks[i], images[i]
        contents = ImageContents(image_id=image.image_id, contents=truck.contents, content_type=truck.content_type)
        session.add(contents)
        contentses.append(contents)
    session.flush()

    task_ids = []
    # Hey, this is a loop around a round-trip to redis. Although the Python
    # Redis library offers a way to send multiple requests in one thwack,
    # Celery doesn't appear to offer a way to use it. Nothing to be done.
    for contents in contentses:
        task_ids.append(delay(g.queued_tasks, process_image, contents.image_contents_id))

    if request_format == "html":
        return redirect(url_for("show_image", image_id=image.image_id))
    elif request_format == "json":
        return [
            {"url": trucks[i].url(), "image_id": images[i].image_id, "task_id": task_ids[i]}
            for i in xrange(0, len(trucks))
        ]
コード例 #7
0
ファイル: image.py プロジェクト: ErinCall/catsnap
def add(request_format):
    url = request.form.get('url')

    if url:
        try:
            trucks = [ImageTruck.new_from_url(url)]
        except RequestException:
            abort(request_format, 400, "That url is no good.")
    elif request.files.get('file[]'):
        trucks = [ImageTruck.new_from_stream(data.stream)
                  for data in request.files.getlist('file[]')]
    elif request.files.get('file'):
        data = request.files['file']
        trucks = [ImageTruck.new_from_stream(data.stream)]
    else:
        abort(request_format, 400, "Please submit either a file or a url.")

    # These loops are sorta awkwardly phrased to avoid lots of round-tripping
    # to the database. I hope you don't consider the optimization premature.
    session = Client().session()
    images = []
    for truck in trucks:
        image = Image(filename=truck.filename, source_url=url)
        album_id = request.form.get('album_id')
        if album_id:
            image.album_id = int(album_id)
        session.add(image)
        images.append(image)

    session.flush()
    contentses = []
    for i in xrange(0, len(images)):
        (truck, image) = trucks[i], images[i]
        contents = ImageContents(image_id=image.image_id,
                                 contents=truck.contents,
                                 content_type=truck.content_type)
        session.add(contents)
        contentses.append(contents)
    session.flush()

    task_ids = []
    # Hey, this is a loop around a round-trip to redis. Although the Python
    # Redis library offers a way to send multiple requests in one thwack,
    # Celery doesn't appear to offer a way to use it. Nothing to be done.
    for contents in contentses:
        task_ids.append(delay(g.queued_tasks,
                              process_image,
                              contents.image_contents_id))

    if request_format == 'html':
        return redirect(url_for('show_image', image_id=image.image_id))
    elif request_format == 'json':
        return [{
                'url': trucks[i].url(),
                'image_id': images[i].image_id,
                'task_id': task_ids[i],
            } for i in xrange(0, len(trucks))]
コード例 #8
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_add_tags_creates_tag_row_if_necessary(self):
        session = Client().session()
        image = Image(filename='baba15')
        session.add(image)
        image.add_tags(['booya'])

        tag = session.query(Tag).\
                filter(Tag.name=='booya').\
                first()

        assert tag, 'no tag was created'
コード例 #9
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_neighbors_is_none_and_one_when_there_is_a_greater_neighbor(self):
        session = Client().session()
        album = Album(name='Light me up')
        session.add(album)
        session.flush()

        image = Image(filename='f1acc1d', album_id=album.album_id)
        session.add(image)
        next = Image(filename='1ace', album_id=album.album_id)
        session.add(next)
        session.flush()

        eq_((None, next), image.neighbors())
コード例 #10
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_neighbors_is_one_and_none_when_the_image_has_a_lesser_neighbor(self):
        session = Client().session()
        album = Album(name='Light me up')
        session.add(album)
        session.flush()

        prev = Image(filename='1ace', album_id=album.album_id)
        session.add(prev)
        image = Image(filename='f1acc1d', album_id=album.album_id)
        session.add(image)
        session.flush()

        eq_((prev, None), image.neighbors())
コード例 #11
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_add_tags_adds_image_tag_rows(self):
        session = Client().session()
        tag = Tag(name='booya')
        session.add(tag)
        image = Image(filename='baba15')
        session.add(image)
        image.add_tags(['booya'])

        image_tag = session.query(ImageTag).\
                filter(ImageTag.image_id == image.image_id).\
                filter(ImageTag.tag_id == tag.tag_id).\
                first()

        assert image_tag, 'no image/tag mapping was created'
コード例 #12
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_remove_tag(self):
        session = Client().session()
        tag = Tag(name='booya')
        image = Image(filename='bab1e5')
        session.add(tag)
        session.add(image)
        session.flush()
        image_tag = ImageTag(image_id=image.image_id, tag_id=tag.tag_id)
        session.add(image_tag)
        session.flush()

        image.remove_tag('booya')

        image_tags = session.query(ImageTag).all()
        eq_(image_tags, [])
コード例 #13
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_get_tags(self):
        session = Client().session()
        image = Image(filename='cafebabe')
        mustache = Tag(name='mustache')
        gif = Tag(name='gif')
        session.add(image)
        session.add(mustache)
        session.add(gif)
        session.flush()
        session.add(ImageTag(tag_id=mustache.tag_id, image_id=image.image_id))
        session.add(ImageTag(tag_id=gif.tag_id, image_id=image.image_id))
        session.flush()

        tags = image.get_tags()
        eq_(list(tags), ['mustache', 'gif'])
コード例 #14
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    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')
コード例 #15
0
ファイル: test_invalidate.py プロジェクト: ErinCall/catsnap
    def test_invalidate_an_image__with_a_resize_suffix(self):
        cloudfront = Mock()
        Client().get_cloudfront = Mock()
        Client().get_cloudfront.return_value = cloudfront

        transaction_id = TaskTransaction.new_id()
        image = Image(filename='f131d')
        image.created_at = '2001-05-09 13:00:00'
        session = Client().session()
        session.add(image)
        session.flush()

        Invalidate().run(transaction_id, image.image_id, suffix="teensy")

        cloudfront.create_invalidation_request.assert_called_with(
            'FETCHISNTGOINGTOHAPPEN', ['f131d_teensy'])
コード例 #16
0
ファイル: test_invalidate.py プロジェクト: ErinCall/catsnap
    def test_invalidate_an_image(self):
        cloudfront = Mock()
        Client().get_cloudfront = Mock()
        Client().get_cloudfront.return_value = cloudfront

        transaction_id = TaskTransaction.new_id()
        image = Image(filename='c1a115')
        image.created_at = '2001-05-09 13:00:00'
        session = Client().session()
        session.add(image)
        session.flush()

        Invalidate().run(transaction_id, image.image_id)

        cloudfront.create_invalidation_request.assert_called_with(
            'JEEZAMANDA', ['c1a115'])
コード例 #17
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    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')
コード例 #18
0
ファイル: test_invalidate.py プロジェクト: ErinCall/catsnap
    def test_invalidation_of_new_images_is_a_noop(self, mock_time, MockClient):
        now = time.strptime('2011-05-09 15:01:01', '%Y-%m-%d %H:%M:%S')
        mock_time.strftime = time.strftime
        mock_time.gmtime.return_value = now

        get_cloudfront = Mock()
        get_cloudfront.side_effect = AssertionError('should not have called me!')
        Client().get_cloudfront = get_cloudfront

        transaction_id = TaskTransaction.new_id()
        image = Image(filename='c1a115')
        # created 1 hour before "now"
        image.created_at = '2011-05-09 13:00:00'
        session = Client().session()
        session.add(image)
        session.flush()

        Invalidate().run(transaction_id, image.image_id)
コード例 #19
0
    def test_hitting_escape_aborts_editing_without_saving(self):
        session = Client().session()
        pic = Image(filename="acebabe")
        session.add(pic)
        session.flush()

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

        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('babe')
        tag_input.fill(Keys.ESCAPE)

        add_tag = self.browser.find_by_css('a.add-tag')
        assert add_tag.visible, "Editing didn't abort!"

        eq_(list(pic.get_tags()), [])
コード例 #20
0
ファイル: test_image_view.py プロジェクト: ErinCall/catsnap
    def test_remove_last_tag(self):
        session = Client().session()
        pic = Image(filename="tagged", title="Untagged Picture")
        session.add(pic)
        session.flush()

        pic.add_tags(['one'])
        session.flush()

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

        self.browser.click_link_by_text('Edit')
        remove_tag = self.browser.find_by_css('a.remove-tag')
        remove_tag.click()

        self.browser.click_link_by_text('Stop Editing')
        tag_button = self.browser.find_by_id('tag-button')
        assert tag_button.has_class("disabled"), \
            "Tag button enabled without tags!"
コード例 #21
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_neighbors_skips_over_images_from_other_albums(self):
        session = Client().session()
        hobbiton = Album(name='Hobbiton')
        session.add(hobbiton)
        hardbottle = Album(name='Hardbottle')
        session.add(hardbottle)
        session.flush()

        samwise = Image(filename='5411111115e', album_id=hobbiton.album_id)
        session.add(samwise)
        bilbo = Image(filename='b11b0', album_id=hobbiton.album_id)
        session.add(bilbo)
        lobelia = Image(filename='10be11a', album_id=hardbottle.album_id)
        session.add(lobelia)
        frodo = Image(filename='f0d0', album_id=hobbiton.album_id)
        session.add(frodo)
        session.flush()

        eq_((samwise, frodo), bilbo.neighbors())
コード例 #22
0
    def test_tabbing_out_of_tab_input_opens_and_focuses_a_new_one(self):
        session = Client().session()
        pic = Image(filename="acebabe")
        session.add(pic)
        session.flush()

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

        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('babe\t')
        tag_removes = self.browser.find_by_css('a.remove-tag')
        eq_([t.text for t in tag_removes], ['babe'])

        focused_input = self.browser.find_by_css('input:focus').first
        eq_(focused_input['id'], 'tag')

        eq_(list(pic.get_tags()), ['babe'])
コード例 #23
0
    def test_remove_last_tag(self):
        session = Client().session()
        pic = Image(filename="tagged", title="Untagged Picture")
        session.add(pic)
        session.flush()

        pic.add_tags(['one'])
        session.flush()

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

        self.browser.click_link_by_text('Edit')
        remove_tag = self.browser.find_by_css('a.remove-tag')
        remove_tag.click()

        self.browser.click_link_by_text('Stop Editing')
        tag_button = self.browser.find_by_id('tag-button')
        tag_button.click()
        tag_list = self.browser.find_by_css('ul.view-tags')
        assert not tag_list.visible, "Popped up an empty tag dropdown!"
コード例 #24
0
ファイル: test_invalidate.py プロジェクト: ErinCall/catsnap
    def test_unknown_cloudfront_errors_reraise(self, MockClient):
        error = CloudFrontServerError(400, 'Bad Request')
        error.error_code = 'CloudFrontHatesYouToday'

        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

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

        Invalidate()(transaction_id, image.image_id)
コード例 #25
0
ファイル: tag.py プロジェクト: pythonchelle/catsnap
    def get_image_data(cls, tag_names):
        from catsnap.table.image import Image
        from catsnap.table.image_tag import ImageTag
        session = Client().session()
        image_data = session.query(func.max(Image.filename),
                                   Image.image_id,
                                   func.max(Image.title),
                                   func.array_agg(Tag.name)).\
                join(ImageTag).\
                filter(ImageTag.image_id == Image.image_id).\
                filter(ImageTag.tag_id == Tag.tag_id).\
                filter(Image.image_id.in_(
                    session.query(ImageTag.image_id).\
                            join(Tag).\
                            filter(ImageTag.tag_id == Tag.tag_id).\
                            filter(Tag.name.in_(tag_names)))).\
                group_by(Image.image_id).\
                order_by(Image.filename)

        for image_struct in image_data:
            caption = Image.make_caption(title=image_struct[2],
                filename=image_struct[0],
                tags=image_struct[3])
            yield (image_struct[0], image_struct[1], caption)
コード例 #26
0
ファイル: test_album.py プロジェクト: ErinCall/catsnap
    def test_images_for_album_id_sorts_by_photographed_then_added_date(self):
        session = Client().session()
        album = Album(name="my pix")
        session.add(album)
        session.flush()

        han = Image(photographed_at="2012-05-13 03:00:00", album_id=album.album_id, filename="han")
        han.created_at = "2014-11-22 13:15:00"
        greedo = Image(photographed_at="2014-12-28 15:24:00", album_id=album.album_id, filename="greedo")
        greedo.created_at = "2014-08-01 08:00:00"
        artoo = Image(photographed_at=None, album_id=album.album_id, filename="R2D2")
        artoo.created_at = "1977-05-13 01:00:00"
        session.add(han)
        session.add(greedo)
        session.add(artoo)
        session.flush()

        # Sorting should be done by the date the image was shot, or the date
        # it was added if it has no photographed_at. Han shot first, so he
        # should show up before Greedo. Artoo never shot at all, so use his
        # created_at (which refers to the *record*, not the image) instead.
        images = Album.images_for_album_id(album.album_id)
        eq_(["R2D2", "han", "greedo"], map(lambda x: x.filename, images))
コード例 #27
0
ファイル: test_image.py プロジェクト: pythonchelle/catsnap
    def test_caption__falls_back_to_filename(self):
        session = Client().session()
        image = Image(title='', filename='the filename')

        eq_(image.caption(), 'the filename')
コード例 #28
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
    def test_caption__falls_back_to_filename(self):
        image = Image(title='', filename='the filename')

        eq_(image.caption(), 'the filename')
コード例 #29
0
    def test_edit_tags(self):
        session = Client().session()

        pic = Image(filename="silly", title="Silly Picture")
        session.add(pic)
        session.flush()

        pic.add_tags(['goofy', 'silly'])
        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()

        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], ['goofy', 'silly'])

        self.browser.click_link_by_text('Edit')

        assert all([not t.visible for t in tags]), "Tag listing didn't disappear!"

        tag_removes = self.browser.find_by_css('a.remove-tag')
        eq_([t.text for t in tag_removes], ['goofy', 'silly'])
        assert all([t.visible for t in tag_removes]), "Remove tag controls weren't visible!"

        add_tag = self.browser.find_by_css('a.add-tag')
        eq_(add_tag.text, 'Add tag')
        assert add_tag.visible, "Add tag control wasn't visible!"

        tag_removes[0].click()

        eq_(list(pic.get_tags()), ['silly'])
        tag_removes = self.browser.find_by_css('a.remove-tag')
        eq_([t.text for t in tag_removes], ['silly'])

        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], ['silly'])
        self.browser.click_link_by_text('Edit')

        add_tag.click()
        focused_input = self.browser.find_by_css('input:focus').first
        tag_input = self.browser.find_by_id('tag').first
        eq_(focused_input['id'], 'tag', "Add-tag input wasn't automatically focused!")
        tag_input.fill('funny\n')

        tag_removes = self.browser.find_by_css('a.remove-tag')
        eq_([t.text for t in tag_removes], ['silly', 'funny'])

        eq_(list(pic.get_tags()), ['silly', 'funny'])

        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], ['silly', 'funny'])
        self.browser.click_link_by_text('Edit')


        tag_removes[1].click()
        eq_(list(pic.get_tags()), ['silly'])
コード例 #30
0
ファイル: test_image.py プロジェクト: ErinCall/catsnap
 def test_neighbors_is_nones_when_the_image_has_no_album(self):
     image = Image(filename='faceface')
     eq_((None, None), image.neighbors())