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()}
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')
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)
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')
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, })
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)) ]
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))]
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'
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())
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())
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'
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, [])
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'])
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 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'])
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'])
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')
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)
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()), [])
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!"
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())
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'])
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!"
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)
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)
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))
def test_caption__falls_back_to_filename(self): session = Client().session() image = Image(title='', filename='the filename') eq_(image.caption(), 'the filename')
def test_caption__falls_back_to_filename(self): image = Image(title='', filename='the filename') eq_(image.caption(), 'the filename')
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'])
def test_neighbors_is_nones_when_the_image_has_no_album(self): image = Image(filename='faceface') eq_((None, None), image.neighbors())