def collection_get(self): """ GET method for items collection, supports the following features: - item status filters - show more pagination """ last_item_id = int(self.request.GET.get('last', 0)) status_name = self.request.GET.get('status', None) # fetch user user_id = int(self.request.matchdict['user_id']) user = DBSession.query(User).filter_by(id=user_id).one() # filter status items = user.items if status_name: logger.info("filtering by status: %s" % status_name) status = DBSession.query(ItemStatus).filter_by( name=status_name.upper()).one() items = items.filter_by(status=status) # apply last item filtering if it exists if last_item_id: logger.info("filtering by last item id: %s" % last_item_id) items = items.filter(Item.id < last_item_id) # apply ordering items = items.order_by(Item.id.desc()).limit(DEFAULT_LIMIT) return [item.to_dict() for item in items]
def dashboard(request): draft, ongoing, archived = DBSession.query(ItemStatus).order_by( ItemStatus.id.asc()).all() # load draft items draft_items = DBSession.query(Item).filter_by(status=draft).order_by( Item.id.desc()).limit(PANEL_DEFAULT_PAGING) draft_items_json = _items_to_json(draft_items) # load ongoing items ongoing_items = DBSession.query(Item).filter_by(status=ongoing).order_by( Item.id.desc()).limit(PANEL_DEFAULT_PAGING) ongoing_items_json = _items_to_json(ongoing_items) # load archived items archived_items = DBSession.query(Item).filter_by(status=archived).order_by( Item.id.desc()).limit(PANEL_DEFAULT_PAGING) archived_items_json = _items_to_json(archived_items) return { 'draft_items': draft_items_json, 'ongoing_items': ongoing_items_json, 'archived_items': archived_items_json, 'body_class': 'plain-content' }
def test_items_delete(self): """ Test deleting an item. """ # first create an item self._create_item_status() payload = { "name": "Macbook Air", "type": "TRADE", "quantity": "1", "price": "", "description": "Lightweight lappy.", "reason": "", "is_draft": "y", "uuid": str(uuid.uuid4()) } request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry response = items(request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(Item).count(), 1) # try retrieving the newly added item item = DBSession.query(Item).first() # now send a delete request request.method = 'DELETE' request.matchdict = {'id': item.id} request.body = None items(request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(Item).count(), 0)
def test_items_delete(self): """ Test deleting an item. """ # first create an item self._create_item_status() payload = {"name": "Macbook Air", "type": "TRADE", "quantity": "1", "price": "", "description": "Lightweight lappy.", "reason": "", "is_draft": "y", "uuid": str(uuid.uuid4())} request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry response = items(request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(Item).count(), 1) # try retrieving the newly added item item = DBSession.query(Item).first() # now send a delete request request.method = 'DELETE' request.matchdict = {'id': item.id} request.body = None items(request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(Item).count(), 0)
def validate_status(self, request): status = request.GET.get('status', None) if status: try: DBSession.query(ItemStatus).filter_by( name=status.upper()).one() except NoResultFound: request.errors.add('url', 'status', _(u'Invalid status'))
def validate_user(self, request): try: user_id = int(request.matchdict['user_id']) try: DBSession.query(User).filter_by(id=user_id).one() except NoResultFound: request.errors.add('url', 'user_id', _(u"User doesn't exist")) except ValueError: request.errors.add('url', 'user_id', _(u'Invalid User ID'))
def get(self): """ GET method for fetching single item. """ action = self.request.GET.get('action', None) item_id = int(self.request.matchdict['item_id']) item = DBSession.query(Item).filter_by(id=item_id).one() if action and action == 'clone': logger.info("cloning item: %s" % str(item_id)) draft_status = DBSession.query(ItemStatus).filter_by( name='DRAFTS').one() cloned_item = Item(user=item.user, name='%s - copy' % item.name, type=item.type, quantity=item.quantity, description=item.description, status=draft_status, price=item.price, reason=item.reason) cloned_item.tags = item.tags DBSession.add(cloned_item) DBSession.commit() # clone images static_path = pkgr.resource_filename('tradeorsale', 'static') source = os.path.join(static_path, 'items/images/%s' % item_id) destination = os.path.join(static_path, 'items/images/%s' % cloned_item.id) try: for imgfile in os.listdir(source): shutil.copy(os.path.join(source, imgfile), destination) for image in item.images.filter_by(parent=None).all(): segments = image.path.split('/') segments[3] = str(cloned_item.id) original_img = ItemImage(item=cloned_item, name=image.name, path='/'.join(segments)) for subimage in image.subimages.all(): segments = subimage.path.split('/') segments[3] = str(cloned_item.id) sub_img = ItemImage(item=cloned_item, name=subimage.name, path='/'.join(segments), size=subimage.size, parent=original_img) DBSession.add(sub_img) DBSession.add(original_img) except OSError as e: logger.error("error while cloning images: %s" % str(e)) DBSession.commit() return cloned_item.to_dict() return item.to_dict()
def validate_item(self, request): try: user_id = int(request.matchdict['user_id']) item_id = int(request.matchdict['item_id']) try: DBSession.query(Item).filter_by(id=item_id, user_id=user_id).one() except NoResultFound: request.errors.add('url', 'item_id', _(u"Item doesn't exist")) except ValueError: request.errors.add('url', 'item_id', _(u'Invalid Item ID'))
def test_items_put(self): """ Test updating an item. """ self._create_item_status() payload = { "name": "Macbook Air", "type": "TRADE", "quantity": "1", "price": "", "description": "Lightweight lappy.", "reason": "", "is_draft": "y", "uuid": str(uuid.uuid4()) } request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry # make the request items(request) # try retrieving the newly added item item = DBSession.query(Item).first() self.failUnless(item) payload = { "name": "Macbook Pro", "type": "SALE", "quantity": "5", "price": "200.00", "description": "Lightweight lappy.", "reason": "", "is_draft": "n", "id": item.id } request.matchdict = {'id': item.id} request.method = 'PUT' request.body = json.dumps(payload) # make the request again response = items(request) self.assertEqual(response.status_code, 200) # reload item item = DBSession.query(Item).filter_by(id=item.id).first() self.assertEqual(item.name, payload['name']) self.assertEqual(item.type, payload['type']) self.assertEqual(item.quantity, int(payload['quantity'])) self.assertEqual(str(item.price), payload['price']) self.assertEqual(item.status_id, self.draft_status.id)
def validate_image(self, request): try: item_id = int(request.matchdict['item_id']) image_id = int(request.matchdict['image_id']) try: DBSession.query(ItemImage).filter_by(id=image_id, item_id=item_id).one() except NoResultFound: request.errors.add('url', 'image_id', _(u"Image doesn't exist")) except ValueError: request.errors.add('url', 'image_id', _(u'Invalid Image ID'))
def test_upload_item_images_post_id(self): """ Test posting images for an item via id. """ self._create_item_status() item = Item(name='iPhone', type='TRADE', quantity=1, description='A smart phone', status=self.draft_status, reason='just because') DBSession.add(item) DBSession.commit() uuid_filename = str(uuid.uuid4()) mock_image = MockFileImage('image1.png') # write to disk the dummy image so the view can resize it original = '%s.png' % uuid_filename static_path = pkgr.resource_filename('tradeorsale', 'static') image_path = os.path.join(static_path, os.path.join('items/images', str(item.id)), original) with open(image_path, 'wb') as handle: handle.write(mock_image.file.read()) self.failUnless(os.path.exists(image_path)) # build request mock_image.file.seek(0) payload = {"item_id": item.id, "image": mock_image} request = testing.DummyRequest(post=payload) request.registry = self.config.registry response = upload_item_images(request) self.assertEqual(response.status_code, 200) # test that there are 3 images: original, small and medium self.assertEqual(DBSession.query(ItemImage).filter_by(item_id=item.id).count(), 3)
def _remove_existing_items(self): """ Helper method to remove existing items. """ for item in DBSession.query(Item).all(): DBSession.delete(item) DBSession.commit()
def add_renderer_globals(event): request = event.get('request') if request is None: request = get_current_request() globs = {'h': helpers} if request is not None: globs['_'] = request.translate globs['localizer'] = request.localizer try: globs['session'] = request.session except ConfigurationError: pass def url(*args, **kwargs): """ route_url shorthand """ return request.route_url(*args, **kwargs) tag_names = [tag.to_dict() for tag in DBSession.query(ItemTag).all()] globs['url'] = url globs['tag_names'] = json.dumps(tag_names) globs['post_item_form'] = ItemForm() event.update(globs)
def add_renderer_globals(event): request = event.get('request') if request is None: request = get_current_request() globs = {'h': helpers} if request is not None: globs['_'] = request.translate globs['localizer'] = request.localizer try: globs['session'] = request.session except ConfigurationError: pass def url(*args, **kwargs): """ route_url shorthand """ return request.route_url(*args, **kwargs) tag_names = [tag.to_dict() for tag in DBSession.query(ItemTag).all()] globs['url'] = url globs['tag_names'] = json.dumps(tag_names) globs['post_item_form'] = ItemForm() event.update(globs)
def delete(self): item_id = int(self.request.matchdict['item_id']) item = DBSession.query(Item).filter_by(id=item_id).one() logger.info("deleting item: %s" % item_id) item.is_deleted = True DBSession.add(item) DBSession.commit() return {'status': 'success', 'message': _(u'Item deletion successful')}
def delete(self): image_id = int(self.request.matchdict['image_id']) item_image = DBSession.query(ItemImage).filter_by(id=image_id).one() DBSession.delete(item_image) DBSession.commit() return { 'status': 'success', 'message': _(u'Image deletion successful') }
def test_items_post_failed(self): """ Test that when POSTing malformed payload, it'll raise HTTPBadRequest. """ payload = {"name": "", "type": "", "quantity": "", "price": "", "description": "", "reason": "", "is_draft": "", "uuid": ""} request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry self.assertRaises(HTTPBadRequest, items, request) self.assertEqual(DBSession.query(Item).count(), 0)
def test_items_put(self): """ Test updating an item. """ self._create_item_status() payload = {"name": "Macbook Air", "type": "TRADE", "quantity": "1", "price": "", "description": "Lightweight lappy.", "reason": "", "is_draft": "y", "uuid": str(uuid.uuid4())} request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry # make the request items(request) # try retrieving the newly added item item = DBSession.query(Item).first() self.failUnless(item) payload = {"name": "Macbook Pro", "type": "SALE", "quantity": "5", "price": "200.00", "description": "Lightweight lappy.", "reason": "", "is_draft": "n", "id": item.id} request.matchdict = {'id': item.id} request.method = 'PUT' request.body = json.dumps(payload) # make the request again response = items(request) self.assertEqual(response.status_code, 200) # reload item item = DBSession.query(Item).filter_by(id=item.id).first() self.assertEqual(item.name, payload['name']) self.assertEqual(item.type, payload['type']) self.assertEqual(item.quantity, int(payload['quantity'])) self.assertEqual(str(item.price), payload['price']) self.assertEqual(item.status_id, self.draft_status.id)
def dashboard(request): draft, ongoing, archived = DBSession.query( ItemStatus).order_by(ItemStatus.id.asc()).all() # load draft items draft_items = DBSession.query(Item).filter_by( status=draft).order_by(Item.id.desc()).limit(PANEL_DEFAULT_PAGING) draft_items_json = _items_to_json(draft_items) # load ongoing items ongoing_items = DBSession.query(Item).filter_by( status=ongoing).order_by(Item.id.desc()).limit(PANEL_DEFAULT_PAGING) ongoing_items_json = _items_to_json(ongoing_items) # load archived items archived_items = DBSession.query(Item).filter_by( status=archived).order_by(Item.id.desc()).limit(PANEL_DEFAULT_PAGING) archived_items_json = _items_to_json(archived_items) return {'draft_items': draft_items_json, 'ongoing_items': ongoing_items_json, 'archived_items': archived_items_json, 'body_class': 'plain-content'}
def test_items_post(self): """ Test creation of new item by POSTing. """ payload = {"name": "Macbook Air", "type": "TRADE", "quantity": "1", "price": "", "description": "Lightweight lappy.", "reason": "", "is_draft": "y", "uuid": str(uuid.uuid4())} request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry response = items(request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(Item).count(), 1)
def collection_post(self): payload = MultiDict(self.request.json_body) # fetch user # TODO: assign currently logged-in user's id user = DBSession.query(User).filter_by(id=1).one() # fetch status status_name = 'DRAFTS' if payload.get('is_draft', False) else 'ONGOING' status = DBSession.query(ItemStatus).filter_by(name=status_name).one() qty = int(payload.get('quantity', 1)) price = payload['price'] if payload.get( 'price', None) and payload['price'] else None new_item = Item(user=user, name=payload['name'], type=payload['type'], trade_with=payload.get('trade_with', None), status=status, price=price, quantity=qty, description=payload['description'], reason=payload['reason']) # load assigned tags and extend new item's tags if payload.get('tags', None): tag_ids = [ tag['id'] for tag in payload['tags'] if tag.get('id', None) ] tags = DBSession.query(ItemTag).filter( ItemTag.id.in_(tag_ids)).all() new_item.tags.extend(tags) DBSession.add(new_item) DBSession.commit() return new_item.to_dict()
def test_items_put_failed(self): """ Test that updating non-existent item fails. """ payload = {"name": "Macbook Pro", "type": "SALE", "quantity": "5", "price": "200.00", "description": "Lightweight lappy.", "reason": "", "is_draft": "n", "id": 1} request = Request({}, method='PUT', body=json.dumps(payload)) request.registry = self.config.registry request.matchdict = {'id': 1} request.method = 'PUT' self.assertRaises(HTTPBadRequest, items, request) self.assertEqual(DBSession.query(Item).count(), 0)
def test_upload_item_images_post_uuid(self): """ Test posting images for an item via uuid. """ self._create_item_status() item = Item(name='iPhone', type='TRADE', quantity=1, description='A smart phone', status=self.draft_status, reason='just because') DBSession.add(item) DBSession.commit() item_uuid = str(uuid.uuid4()) mock_image = MockFileImage('image1.png') # write to disk the dummy image so the view can resize it original = '%s.png' % item_uuid static_path = pkgr.resource_filename('tradeorsale', 'static') image_path = os.path.join(static_path, os.path.join('items/images', str(item.id)), original) with open(image_path, 'wb') as handle: handle.write(mock_image.file.read()) self.failUnless(os.path.exists(image_path)) # build request mock_image.file.seek(0) payload = {"uuid": item_uuid, "image": mock_image} request = testing.DummyRequest(post=payload) request.registry = self.config.registry # set a dummy uuid to regis self.redis.hset('item_uuid_to_id', item_uuid, item.id) self.redis.expire(item_uuid, 3600) response = upload_item_images(request) self.assertEqual(response.status_code, 200) # test that there are 3 images: original, small and medium self.assertEqual( DBSession.query(ItemImage).filter_by(item_id=item.id).count(), 3)
def test_items_post_failed(self): """ Test that when POSTing malformed payload, it'll raise HTTPBadRequest. """ payload = { "name": "", "type": "", "quantity": "", "price": "", "description": "", "reason": "", "is_draft": "", "uuid": "" } request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry self.assertRaises(HTTPBadRequest, items, request) self.assertEqual(DBSession.query(Item).count(), 0)
def test_item_image_delete(self): """ Test that image is deleted when DELETE request is sent. """ self._create_item_status() item = Item(name='iPhone', type='TRADE', quantity=1, description='A smart phone', status=self.draft_status, reason='just because') DBSession.add(item) DBSession.commit() # write to disk the dummy image mock_image = MockFileImage('original.jpg') static_path = pkgr.resource_filename('tradeorsale', 'static') item_images_path = os.path.join( static_path, os.path.join('items/images', str(item.id))) image_path = os.path.join(item_images_path, mock_image.filename) with open(image_path, 'wb') as handle: handle.write(mock_image.file.read()) self.failUnless(os.path.exists(image_path)) # save the image in db item_image = ItemImage( item.id, mock_image.filename, os.path.join('/%s' % item_images_path, mock_image.filename)) DBSession.add(item_image) DBSession.commit() # send DELETE request request = Request({}, method='DELETE') request.matchdict = {'id': item.id} request.registry = self.config.registry # check that record was deleted response = item_images(None, request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(ItemImage).count(), 0) self.failUnless(not os.path.exists(image_path))
def test_items_post(self): """ Test creation of new item by POSTing. """ payload = { "name": "Macbook Air", "type": "TRADE", "quantity": "1", "price": "", "description": "Lightweight lappy.", "reason": "", "is_draft": "y", "uuid": str(uuid.uuid4()) } request = Request({}, method='POST', body=json.dumps(payload)) request.registry = self.config.registry response = items(request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(Item).count(), 1)
def test_items_put_failed(self): """ Test that updating non-existent item fails. """ payload = { "name": "Macbook Pro", "type": "SALE", "quantity": "5", "price": "200.00", "description": "Lightweight lappy.", "reason": "", "is_draft": "n", "id": 1 } request = Request({}, method='PUT', body=json.dumps(payload)) request.registry = self.config.registry request.matchdict = {'id': 1} request.method = 'PUT' self.assertRaises(HTTPBadRequest, items, request) self.assertEqual(DBSession.query(Item).count(), 0)
def test_item_image_delete(self): """ Test that image is deleted when DELETE request is sent. """ self._create_item_status() item = Item(name='iPhone', type='TRADE', quantity=1, description='A smart phone', status=self.draft_status, reason='just because') DBSession.add(item) DBSession.commit() # write to disk the dummy image mock_image = MockFileImage('original.jpg') static_path = pkgr.resource_filename('tradeorsale', 'static') item_images_path = os.path.join(static_path, os.path.join('items/images', str(item.id))) image_path = os.path.join(item_images_path, mock_image.filename) with open(image_path, 'wb') as handle: handle.write(mock_image.file.read()) self.failUnless(os.path.exists(image_path)) # save the image in db item_image = ItemImage(item.id, mock_image.filename, os.path.join('/%s' % item_images_path, mock_image.filename)) DBSession.add(item_image) DBSession.commit() # send DELETE request request = Request({}, method='DELETE') request.matchdict = {'id': item.id} request.registry = self.config.registry # check that record was deleted response = item_images(None, request) self.assertEqual(response.status_code, 200) self.assertEqual(DBSession.query(ItemImage).count(), 0) self.failUnless(not os.path.exists(image_path))
def collection_post(self): item_id = int(self.request.matchdict['item_id']) item = DBSession.query(Item).filter_by(id=item_id).one() ext = os.path.splitext( self.request.POST['image'].filename)[1] or '.jpg' filename_uuid = uuid.uuid4() filename = '%s%s' % (filename_uuid, ext) # figure out path to the newly uploaded image static_path = pkgr.resource_filename('tradeorsale', 'static') item_images_path = os.path.join('items/images', str(item_id)) item_images_abspath = os.path.join(static_path, item_images_path) image_path = os.path.join(item_images_abspath, filename) # copy file chunk by chunk with open(image_path, 'wb') as handle: while True: data = self.request.POST['image'].file.read(2 << 16) # 128kb if not data: break handle.write(data) logger.info("storing item image to db: item-id(%i) size(original)" % item_id) item_image = ItemImage(item, filename, os.path.join('/%s' % item_images_path, filename)) # / + items/... # build resized images image_sizes = {} for size, dimension in THUMBNAIL_SIZES.items(): resized_filename = '%s_%s%s' % (filename_uuid, size, ext) resized_image_path = os.path.join(item_images_abspath, resized_filename) # resize image logger.info("resizing image to %s" % str(THUMBNAIL_SIZES[size])) try: img = Image.open(image_path) except IOError as e: logger.error("unable to open image: %s" % str(e)) self.request.errors.add('body', 'image', _(u'Unable to read image')) # if we're resizing to medium size, make height relative to width if size == 'medium': basewidth = THUMBNAIL_SIZES[size][0] width_percentage = (basewidth / float(img.size[0])) height_size = int( (float(img.size[1]) * float(width_percentage))) resized_img = img.resize((basewidth, height_size), Image.ANTIALIAS) else: resized_img = ImageOps.fit(img, THUMBNAIL_SIZES[size], Image.ANTIALIAS) resized_img.save(resized_image_path, quality=90, optimize=True) # save resized image to db logger.info("storing item image to db: item-id(%i) size(%s)" % (item_id, size)) item_subimage = ItemImage( item, resized_filename, os.path.join('/%s' % item_images_path, resized_filename), size) item_image.subimages.append(item_subimage) # save original image to db DBSession.add(item_image) DBSession.commit() # return different images sizes image_sizes = { 'id': item_image.id, 'original': assets_url(self.request, item_image.path) } for size in THUMBNAIL_SIZES.keys(): image_sizes[size] = assets_url(self.request, item_image.get_resized_image(size)) return {'item_id': item_id, 'sizes': image_sizes}
def put(self): item_id = int(self.request.matchdict['item_id']) payload = MultiDict(self.request.json_body) item = DBSession.query(Item).filter_by(id=item_id).one() transaction_date = None print payload # fetch status if payload.get('is_draft', False): status_name = 'DRAFTS' elif payload.get('status', None) and payload['status'] == 'archived': status_name = 'ARCHIVED' transaction_date = datetime.now() else: status_name = 'ONGOING' status = DBSession.query(ItemStatus).filter_by(name=status_name).one() # fetch new tags new_tags = [] ids_to_add = [ int(tag['id']) for tag in payload.get('tags', []) if tag.get('id', None) ] if ids_to_add: new_tags.extend( DBSession.query(ItemTag).filter( ItemTag.id.in_(ids_to_add)).all()) item.tags = new_tags # replace existing tags new_qty = int(payload.get('quantity', 1)) price = payload['price'] if payload['price'] else None item.name = payload['name'] item.type = payload['type'] item.trade_with = payload.get('trade_with', None) item.status = status item.price = price item.description = payload['description'] item.reason = payload.get('reason', None) item.transaction_date = transaction_date # adjust original quantity if new_qty > item.quantity: additional_quantity = new_qty - item.quantity item.original_quantity += additional_quantity elif new_qty < item.quantity: additional_quantity = item.quantity - new_qty item.original_quantity -= additional_quantity item.quantity = new_qty updating_fields = ('updating item: %s', 'name: %s', 'type: %s', 'status: %s', 'price: %s', 'quantity: %s', 'description: %s', 'reason: %s', 'tags: %s', 'transaction date: %s\n') logger.info('\n'.join(updating_fields) % (item_id, item.name, item.type, item.status, item.price, item.quantity, item.description, item.reason, item.tags, item.transaction_date)) DBSession.commit() return item.to_dict()