def set_item(self, request):
        """Sets a single WBO object."""
        storage = self._get_storage(request)
        if storage.use_quota:
            left = self._check_quota(request)
        else:
            left = 0.

        user_id = request.user['userid']
        collection_name = request.sync_info['collection']
        item_id = request.sync_info['item']

        if self._was_modified(request, user_id, collection_name):
            raise HTTPPreconditionFailed(collection_name)

        try:
            data = json.loads(request.body)
        except ValueError:
            raise HTTPJsonBadRequest(WEAVE_MALFORMED_JSON)

        try:
            wbo = WBO(data)
        except ValueError:
            raise HTTPJsonBadRequest(WEAVE_INVALID_WBO)

        consistent, msg = wbo.validate()
        if not consistent:
            raise HTTPJsonBadRequest(WEAVE_INVALID_WBO)

        if self._has_modifiers(wbo):
            wbo['modified'] = request.server_time

        try:
            res = storage.set_item(user_id, collection_name, item_id,
                                   storage_time=request.server_time, **wbo)
        except StorageConflictError:
            raise HTTPJsonBadRequest(WEAVE_INVALID_WRITE)
        response = json_response(res)
        if storage.use_quota and left <= _ONE_MEG:
            response.headers['X-Weave-Quota-Remaining'] = str(left)
        return response
示例#2
0
    def get_item(self, user_id, collection_name, item_id, fields=None):
        """returns one item"""
        wbo = self._get_wbo_table(user_id)
        collection_id = self._get_collection_id(user_id, collection_name)
        if fields is None:
            fields = [wbo]
        else:
            fields = [getattr(wbo.c, field) for field in fields]
        where = self._get_query('ITEM_ID_COL_USER', user_id)
        query = select(fields, where)
        res = self._do_query_fetchone(query,
                                      user_id=user_id,
                                      item_id=item_id,
                                      collection_id=collection_id,
                                      ttl=_int_now())
        if res is None:
            return None

        return WBO(res, {'modified': bigint2time})
示例#3
0
    def get_items(self,
                  user_id,
                  collection_name,
                  fields=None,
                  filters=None,
                  limit=None,
                  offset=None,
                  sort=None):
        """returns items from a collection

        "filter" is a dict used to add conditions to the db query.
        Its keys are the field names on which the condition operates.
        Its values are the values the field should have.
        It can be a single value, or a list. For the latter the in()
        operator is used. For single values, the operator has to be provided.
        """
        wbo = self._get_wbo_table(user_id)
        collection_id = self._get_collection_id(user_id, collection_name)
        if fields is None:
            fields = [wbo]
        else:
            fields = [getattr(wbo.c, field) for field in fields]

        # preparing the where statement
        where = [wbo.c.username == user_id, wbo.c.collection == collection_id]

        if filters is not None:
            for field, value in filters.items():
                field = getattr(wbo.c, field)

                operator, value = value
                if field.name == 'modified':
                    value = _roundedbigint(value)

                if isinstance(value, (list, tuple)):
                    where.append(field.in_(value))
                else:
                    if operator == '=':
                        where.append(field == value)
                    elif operator == '<':
                        where.append(field < value)
                    elif operator == '>':
                        where.append(field > value)

        if filters is None or 'ttl' not in filters:
            where.append(wbo.c.ttl > _int_now())

        where = and_(*where)
        query = select(fields, where)

        if sort is not None:
            if sort == 'oldest':
                query = query.order_by(wbo.c.modified.asc())
            elif sort == 'newest':
                query = query.order_by(wbo.c.modified.desc())
            else:
                query = query.order_by(wbo.c.sortindex.desc())

        if limit is not None and int(limit) > 0:
            query = query.limit(int(limit))

        if offset is not None and int(offset) > 0:
            query = query.offset(int(offset))

        res = self._do_query_fetchall(query)
        converters = {'modified': bigint2time}
        return [WBO(line, converters) for line in res]
示例#4
0
    def test_validation(self):
        data = {'parentid': 'bigid' * 30}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)

        data = {'parentid': 'id', 'sortindex': 9999999999}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)

        data = {'parentid': 'id', 'sortindex': '9999.1'}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)
        self.assertTrue(wbo['sortindex'], 9999)

        data = {'parentid': 'id', 'sortindex': 'ok'}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)

        data = {'parentid':  33, 'sortindex': '12'}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)
        self.assertEquals(wbo['parentid'], '33')
        self.assertEquals(wbo['sortindex'], 12)

        for bad_ttl in ('bouh', -1, 31537000):
            data = {'parentid':  33, 'ttl': bad_ttl}
            wbo = WBO(data)
            result, failure = wbo.validate()
            self.assertFalse(result)

        data = {'parentid':  33, 'ttl': 3600}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)

        data = {'payload':  "X" * 30000}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)

        data = {'payload':  "X" * 300000}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)
示例#5
0
    def test_validation(self):
        data = {'parentid': 'bigid' * 30}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)

        data = {'parentid': 'id', 'sortindex': 9999999999}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)

        data = {'parentid': 'id', 'sortindex': '9999.1'}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)
        self.assertTrue(wbo['sortindex'], 9999)

        data = {'parentid': 'id', 'sortindex': 'ok'}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)

        data = {'parentid': 33, 'sortindex': '12'}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)
        self.assertEquals(wbo['parentid'], '33')
        self.assertEquals(wbo['sortindex'], 12)

        for bad_ttl in ('bouh', -1, 31537000):
            data = {'parentid': 33, 'ttl': bad_ttl}
            wbo = WBO(data)
            result, failure = wbo.validate()
            self.assertFalse(result)

        data = {'parentid': 33, 'ttl': 3600}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)

        data = {'payload': "X" * 30000}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertTrue(result)

        data = {'payload': "X" * 300000}
        wbo = WBO(data)
        result, failure = wbo.validate()
        self.assertFalse(result)
示例#6
0
 def test_basic(self):
     wbo = WBO()
     wbo = WBO({'boooo': ''})
     self.assertTrue('boooo' not in wbo)
    def set_collection(self, request):
        """Sets a batch of WBO objects into a collection."""

        user_id = request.user['userid']
        collection_name = request.sync_info['collection']

        if self._was_modified(request, user_id, collection_name):
            raise HTTPPreconditionFailed(collection_name)

        try:
            wbos = json.loads(request.body)
        except ValueError:
            raise HTTPJsonBadRequest(WEAVE_MALFORMED_JSON)

        if not isinstance(wbos, (tuple, list)):
            # thats a batch of one
            try:
                id_ = str(wbos['id'])
            except (KeyError, TypeError):
                raise HTTPJsonBadRequest(WEAVE_INVALID_WBO)
            if '/' in id_:
                raise HTTPJsonBadRequest(WEAVE_INVALID_WBO)

            request.sync_info['item'] = id_
            return self.set_item(request)

        res = {'success': [], 'failed': {}}

        # Sanity-check each of the WBOs.
        # Limit the batch based on both count and payload size.
        kept_wbos = []
        total_bytes = 0
        for count, wbo in enumerate(wbos):
            try:
                wbo = WBO(wbo)
            except ValueError:
                res['failed'][''] = ['invalid wbo']
                continue

            if 'id' not in wbo:
                res['failed'][''] = ['invalid id']
                continue

            consistent, msg = wbo.validate()
            item_id = wbo['id']
            if not consistent:
                res['failed'][item_id] = [msg]
                continue

            if count >= self.batch_max_count:
                res['failed'][item_id] = ['retry wbo']
                continue
            if 'payload' in wbo:
                total_bytes += len(wbo['payload'])
            if total_bytes >= self.batch_max_bytes:
                res['failed'][item_id] = ['retry bytes']
                continue

            if self._has_modifiers(wbo):
                wbo['modified'] = request.server_time

            kept_wbos.append(wbo)

        storage = self._get_storage(request)
        if storage.use_quota:
            left = self._check_quota(request)
        else:
            left = 0.

        storage_time = request.server_time

        for wbos in batch(kept_wbos, size=self.batch_size):
            wbos = list(wbos)   # to avoid exhaustion
            try:
                storage.set_items(user_id, collection_name,
                                  wbos, storage_time=storage_time)

            except Exception, e:   # we want to swallow the 503 in that case
                # something went wrong
                self.logger.error('Could not set items')
                self.logger.error(str(e))
                for wbo in wbos:
                    res['failed'][wbo['id']] = "db error"
            else:
                res['success'].extend([wbo['id'] for wbo in wbos])