async def search(self, locks=None, acquired_by=None, fields=None, sort=None, page=None, limit=None): query = {} self._filter_re(query, 'id', locks) self._filter_re(query, 'acquired_by', acquired_by) try: cursor = self._coll.find(filter=query, projection=self._projection(fields)) cursor.sort(self._sort(sort)) cursor.skip(self._pagination_skip(page, limit)) cursor.limit(self._pagination_limit(limit)) result = list() for item in await cursor.to_list(self._pagination_limit(limit)): if 'acquired_since' in item: item['acquired_since'] = item['acquired_since'].replace( tzinfo=datetime.timezone.utc).isoformat() result.append(self._format(item)) return self._format(result, multi=True) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def delete(self, _id): try: result = await self._coll.delete_one(filter={'id': _id}) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) if result.deleted_count is 0: raise ResourceNotFound(_id) return
async def delete_mark(self, _id): update = {'$set': {'deleting': True}} try: await self._coll.update_one( filter={'id': _id}, update=update, ) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def create(self, _id, payload): payload['id'] = _id payload['acquired_since'] = datetime.datetime.utcnow() try: await self._coll.insert_one(payload) except pymongo.errors.DuplicateKeyError: raise DuplicateResource(_id) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) return await self.get(_id)
async def create(self, _id, payload): payload['password'] = await self._password(payload['password']) payload['deleting'] = False payload['id'] = _id try: await self._coll.insert_one(payload) except pymongo.errors.DuplicateKeyError: raise DuplicateResource(_id) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) return await self.get(_id)
async def check_credential(self, credentials): try: result = await self._coll.find_one( filter={'id': self._str_uuid_2_bin(credentials['id'])}, ) if not result: raise CredentialError if not pbkdf2_sha512.verify(credentials['secret'], result['secret']): raise CredentialError return self._format({'user': result['owner']}) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def get_all(self, owner): try: cursor = self._coll.find(filter={'owner': owner}, projection=self._projection()) result = list() for item in await cursor.to_list(1000): item['id'] = str(item['id']) item['created'] = str(item['created']) result.append(self._format(item)) return self._format(result, multi=True) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def get(self, _id, fields=None): try: result = await self._coll.find_one( filter={ 'id': _id, 'deleting': False }, projection=self._projection(fields)) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) if result is None: raise ResourceNotFound(_id) return self._format(result)
async def get(self, _id, fields=None): try: result = await self._coll.find_one( filter={ 'id': _id, }, projection=self._projection(fields)) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) if result is None: raise ResourceNotFound(_id) if 'acquired_since' in result: result['acquired_since'] = result['acquired_since'].replace( tzinfo=datetime.timezone.utc).isoformat() return self._format(result)
async def check_credentials(self, credentials): try: password = await self._coll.find_one(filter={ 'id': credentials['user'], 'deleting': False }, projection={'password': 1}) if not password: raise AuthenticationError if not pbkdf2_sha512.verify(credentials['password'], password['password']): raise AuthenticationError return credentials['user'] except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def get(self, _id, owner): try: result = await self._coll.find_one(filter={ 'id': self._str_uuid_2_bin(_id), 'owner': owner }, projection=self._projection()) if result is None: raise ResourceNotFound(_id) result['id'] = _id if 'created' in result: result['created'] = str(result['created']) return self._format(result) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def update(self, _id, payload): if 'password' in payload: payload['password'] = await self._password(payload['password']) update = {'$set': {}} for k, v in payload.items(): update['$set'][k] = v try: result = await self._coll.find_one_and_update( filter={ 'id': _id, 'deleting': False }, update=update, projection=self._projection(), return_document=pymongo.ReturnDocument.AFTER) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) if result is None: raise ResourceNotFound(_id) return self._format(result)
async def search(self, _id=None, fields=None, sort=None, page=None, limit=None): query = {'deleting': False} self._filter_re(query, 'id', _id) try: cursor = self._coll.find(filter=query, projection=self._projection(fields)) cursor.sort(self._sort(sort)) cursor.skip(self._pagination_skip(page, limit)) cursor.limit(self._pagination_limit(limit)) result = list() for item in await cursor.to_list(self._pagination_limit(limit)): result.append(self._format(item)) return self._format(result, multi=True) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)
async def create(self, owner, payload): _id = uuid.uuid4() secret = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits + '_-.') for _ in range(128)) created = datetime.datetime.utcnow() payload['id'] = Binary(_id.bytes, STANDARD) payload['secret'] = self._create_secret(str(secret)) payload['created'] = created payload['owner'] = owner try: await self._coll.insert_one(payload) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) result = { 'id': str(_id), 'created': str(created), 'description': payload['description'], 'secret': str(secret) } return self._format(result)
async def update(self, _id, owner, payload): update = {'$set': {}} for k, v in payload.items(): update['$set'][k] = v try: result = await self._coll.find_one_and_update( filter={ 'id': self._str_uuid_2_bin(_id), 'owner': owner }, update=update, projection=self._projection(), return_document=pymongo.ReturnDocument.AFTER) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) if result is None: raise ResourceNotFound(_id) if 'created' in result: result['created'] = str(result['created']) result['id'] = _id return self._format(result)
async def delete(self, _id, payload): try: if 'force' in payload: result = await self._coll.delete_one(filter={ 'id': _id, }) else: query = { 'id': _id, 'acquired_by': payload['acquired_by'], } if 'secret' in payload: query['secret'] = payload['secret'] else: query['secret'] = None result = await self._coll.delete_one(filter=query) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err) if result.deleted_count is 0: raise ResourceNotFound(_id) return
async def error_catcher(request, handler): log = logging.getLogger('application') _request_id = request['X-Request-ID'] try: try: log.debug("{0} entering module {1} function {2}".format( _request_id, handler.__module__, handler.__name__)) return await handler(request) except (jsonschema.exceptions.ValidationError, json.decoder.JSONDecodeError) as err: log.error('{0} received invalid JSON body {1}'.format( _request_id, err)) raise InvalidBody(err) except pymongo.errors.ConnectionFailure as err: log.error('{0} error communicating with MongoDB: {1}'.format( _request_id, err)) raise MongoConnError(err) finally: log.debug("{0} leaving module {1} function {2}".format( _request_id, handler.__module__, handler.__name__)) except BaseError as err: return json_response(data=err.err_rsp, status=err.status)
async def delete_all_from_owner(self, owner): try: await self._coll.delete_many(filter={"owner": owner}) except pymongo.errors.ConnectionFailure as err: raise MongoConnError(err)