示例#1
0
 def _remove_existing_items(self):
     """
     Helper method to remove existing items.
     """
     for item in DBSession.query(Item).all():
         DBSession.delete(item)
     DBSession.commit()
示例#2
0
    def test_upload_item_images_post_uuid_failed(self):
        """
        Test posting images for an item via uuid with invalid image fails.
        """
        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()

        class DumbMockImage(object):
            file = StringIO('image')
            filename = 'image1.jpg'

        item_uuid = str(uuid.uuid4())
        mock_image = DumbMockImage()

        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)

        self.assertRaises(HTTPBadRequest, upload_item_images, request)
示例#3
0
    def test_upload_item_images_post_uuid_failed(self):
        """
        Test posting images for an item via uuid with invalid image fails.
        """
        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()

        class DumbMockImage(object):
            file = StringIO('image')
            filename = 'image1.jpg'

        item_uuid = str(uuid.uuid4())
        mock_image = DumbMockImage()

        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)

        self.assertRaises(HTTPBadRequest, upload_item_images, request)
示例#4
0
    def test_dashboard_view_drafts_nonempty(self):
        """
        Test that dashboard view returns non-empty list
        draft items when there are draft items.
        """
        self._create_item_status()
        DBSession.add(
            Item(name='iPhone',
                 type='TRADE',
                 description='A smart phone.',
                 status=self.draft_status,
                 quantity=1))
        DBSession.add(
            Item(name='Macbook Pro',
                 type='SALE',
                 description='An apple product.',
                 price=30500,
                 status=self.ongoing_status,
                 quantity=5))
        DBSession.commit()

        request = testing.DummyRequest()
        response = dashboard(request)
        draft_items = json.loads(response['draft_items'])

        self.assertEqual(len(draft_items), 1)
        self.assertNotEqual(draft_items, [])
示例#5
0
    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)
示例#6
0
 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')}
示例#7
0
 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')
     }
示例#8
0
    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()
示例#9
0
 def _create_item_status(self):
     """
     Helper method to create item statuses.
     """
     self.draft_status = ItemStatus('DRAFTS')
     self.ongoing_status = ItemStatus('ONGOING')
     self.archived_status = ItemStatus('ARCHIVED')
     DBSession.add(self.draft_status)
     DBSession.add(self.ongoing_status)
     DBSession.add(self.archived_status)
     DBSession.commit()
示例#10
0
    def test_dashboard_view_drafts_nonempty(self):
        """
        Test that dashboard view returns non-empty list
        draft items when there are draft items.
        """
        self._create_item_status()
        DBSession.add(Item(name='iPhone', type='TRADE',
            description='A smart phone.', status=self.draft_status, quantity=1))
        DBSession.add(Item(name='Macbook Pro', type='SALE',
            description='An apple product.', price=30500,
            status=self.ongoing_status, quantity=5))
        DBSession.commit()

        request = testing.DummyRequest()
        response = dashboard(request)
        draft_items = json.loads(response['draft_items'])

        self.assertEqual(len(draft_items), 1)
        self.assertNotEqual(draft_items, [])
示例#11
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)
示例#12
0
    def test_create_image_path(self):
        """
        Test that creating an item creates image path.
        """
        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()

        # check that the images path has been created
        images_path = pkgr.resource_filename('tradeorsale', 'static')
        item_images_abspath = os.path.join(
            images_path, os.path.join('items/images', str(item.id)))
        self.failUnless(os.path.exists(item_images_abspath))
示例#13
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))
示例#14
0
    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()
示例#15
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))
示例#16
0
    def test_delete_image(self):
        """
        Test that deleting an image deletes it from disk.
        """
        # create item first
        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()

        # delete image and check that it doesn't exist
        DBSession.delete(item_image)
        DBSession.commit()
        self.failUnless(not os.path.exists(image_path))
示例#17
0
    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()
示例#18
0
    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}