def get(self, request): """List all Category instance registered in the system""" # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Category filter categories = [] if not parser.objects or not parser.objects[0].categories: categories = self.backend.registry.all() else: for category in parser.objects[0].categories: try: category = self.backend.registry.lookup_id(str(category)) except Category.DoesNotExist: return hrc.NOT_FOUND('%s: Category not found' % category) else: categories.append(category) dao = DataObject(translator=self.translator, categories=categories) dao.render_flags['category_discovery'] = True # Render response renderer.render(dao) return HttpResponse(renderer.headers, renderer.body)
def get(self, request): """List all Category instance registered in the system""" # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Category filter categories = [] if not parser.objects or not parser.objects[0].categories: categories = self.backend.registry.all() else: for category in parser.objects[0].categories: try: category = self.backend.registry.lookup_id(str(category)) except Category.DoesNotExist: return hrc.NOT_FOUND("%s: Category not found" % category) else: categories.append(category) dao = DataObject(translator=self.translator, categories=categories) dao.render_flags["category_discovery"] = True # Render response renderer.render(dao) return HttpResponse(renderer.headers, renderer.body)
def get(self, request, path): """Retrieve a resource instance.""" try: location, entity_id = path.rsplit("/", 1) except ValueError: location = None entity_id = path if location: location_category = self.backend.registry.lookup_location(location) else: location_category = None try: parser, renderer = self._request_init(request) entity = self._get_entity(entity_id, user=request.user) except HttpRequestError as e: return e.response if ( location_category and location_category != entity.occi_get_kind() and location_category in entity.occi_get_mixins() ): return hrc.NOT_FOUND() dao = DataObject(translator=self.translator) dao.load_from_entity(entity) renderer.render(dao) return HttpResponse(renderer.headers, renderer.body)
def get(self, request, path): """Retrieve a resource instance.""" try: location, entity_id = path.rsplit('/', 1) except ValueError: location = None entity_id = path if location: location_category = self.backend.registry.lookup_location(location) else: location_category = None try: parser, renderer = self._request_init(request) entity = self._get_entity(entity_id, user=request.user) except HttpRequestError as e: return e.response if (location_category and location_category != entity.occi_get_kind() and location_category in entity.occi_get_mixins()): return hrc.NOT_FOUND() dao = DataObject(translator=self.translator) dao.load_from_entity(entity) renderer.render(dao) return HttpResponse(renderer.headers, renderer.body)
def get(self, request, path): """Get the resource instances in the specified `Kind` collection""" # Lookup location path categories = self.backend.registry.lookup_recursive(path or '') # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Retrieve resource instances from backend entities = [] try: for category in categories: if isinstance(category, Kind): entities.extend(self._filter_entities(categories=[category], dao_filter=parser.objects, user=request.user)) except HttpRequestError as e: return e.response # Render response objects = [] for entity in entities: dao = DataObject(translator=self.translator) dao.load_from_entity(entity) objects.append(dao) renderer.render(objects) return HttpResponse(renderer.headers, renderer.body)
def get(self, request): """List all Category instance registered in the system""" # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response dao = DataObject(translator=self.translator, categories=self.backend.registry.all()) dao.render_flags['category_discovery'] = True # Render response renderer.render(dao) return HttpResponse(renderer.headers, renderer.body)
def parse(self, headers=None, body=None): super(TextURIListParser, self).parse(headers, body) body = body or '' for loc in body.replace('\r', '').split('\n'): loc = loc.strip() if loc: self.objects.append(DataObject(location=loc))
def get(self, request, path): """Get the resource instances in the specified collection""" # Lookup location path categories = self.backend.registry.lookup_recursive(path or '') # If path is not a Kind/Mixin location filter out everything but Kind # categories if len(categories) > 1: t = [] for category in categories: if isinstance(category, Kind): t.append(category) categories = t # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Retrieve resource instances from backend entities = [] try: for category in categories: entities.extend( self._filter_entities(categories=[category], dao_filter=parser.objects, user=request.user)) except HttpRequestError as e: return e.response # Render response objects = [] for entity in entities: dao = DataObject(translator=self.translator) dao.load_from_entity(entity) objects.append(dao) renderer.render(objects) return HttpResponse(renderer.headers, renderer.body)
def parse(self, headers=None, body=None): categories = [] links = [] attributes = [] locations = [] # Walk list of HTTP header name-value pairs for name, value in headers or (): name = name.lower() if name == 'accept': self._parse_accept_header(value) elif name == 'category': categories.extend(self._parse_category_header(value)) elif name == 'link': # FIXME - not allowing Link create/update using POST/PUT yet pass elif name == 'x-occi-attribute': attribute_headers = HttpAttributeHeaders() attribute_headers.parse(value) attributes.extend(attribute_headers.all()) elif name == 'x-occi-location': location_headers = HttpHeadersBase() location_headers.parse(value) locations.extend(location_headers.all()) # Only possible to represent one "full" data object with HTTP Headers. # Multiple data objects can only be represented with a location. locations = locations or [None] self.objects.append(DataObject( categories=categories, links=links, attributes=attributes, location=locations[0])) for loc in locations[1:]: self.objects.append(DataObject(location=loc))
def _post_update(self, request, entity_id): """Update an existing resource instance.""" # Parse request try: parser, renderer = self._request_init(request) entity = self._get_entity(entity_id, user=request.user) except HttpRequestError as e: return e.response # Only a single data object allowed if not parser.objects: return hrc.BAD_REQUEST('No resource instance specified') elif len(parser.objects) > 1: return hrc.BAD_REQUEST('More than one resource instance specified') dao = parser.objects[0] dao.translator = self.translator # Update entity object from request data try: dao.save_to_entity(entity=entity, category_registry=self.backend.registry) except DataObject.Invalid as e: return hrc.BAD_REQUEST(e) # Save the updated entity object try: id_list = self._save_entities([entity], user=request.user) except HttpRequestError as e: return e.response # Response is a list of locations dao_list = [] for entity_id in id_list: dao_list.append( DataObject(location=self.translator.from_native(entity_id))) # Render response renderer.render(dao_list) # Set Location header to the first ID renderer.headers.append( ('Location', self.translator.from_native(id_list[0]))) return HttpResponse(renderer.headers, renderer.body)
def _update_collection(self, request, location_category, replace=False): # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Any data-objects submitted? if not parser.objects: return hrc.BAD_REQUEST("No resource instance(s) specified") # Entities to update and delete entities_updated = {} entities_deleted = {} # Only possible to replace a pure Kind/Mixin location if replace: assert location_category # When replacing the whole collection we need to: # - Remove the all entities of Kind not part of the update. # - Remove the Mixin from all entities not part of the update. try: if isinstance(location_category, Kind): for entity in self._filter_entities(categories=[location_category], user=request.user): entities_deleted[entity_id] = True elif isinstance(location_category, Mixin): for entity in self._filter_entities(categories=[location_category], user=request.user): try: entity.occi_remove_mixin(location_category) except Entity.UnknownCategory: pass else: entities_updated[entity.id] = entity except HttpRequestError as e: return e.response # Convert request objects to entity instances try: for dao in parser.objects: # Add location category to entity dao if location_category: dao.categories.append(location_category) dao.translator = self.translator # Get Entity ID from request entity_id = dao.get_entity_id() # COMPAT: OCCI HTTP Rendering 1.1 does not threat PUT # /mixin_loc/ as a resource create/replace operation. # Use non-replace mode as workaround. _do_replace = replace if replace and parser.specification() in ("occi-http-1.1"): _do_replace = False # Attempt to load existing Entity if entity_id and not _do_replace: try: entity = entities_updated[entity_id] except KeyError: entity = self._get_entity(entity_id, user=request.user) else: entity = None # Create/update entity object # FIXME: If replacing the entity we leave all links untouched. # This is according to spec but is it convenient? entity = dao.save_to_entity( entity=entity, save_links=(not replace), category_registry=self.backend.registry ) entities_updated[entity.id] = entity entities_deleted.pop(entity.id, None) # Add Link objects to list of modified entities if hasattr(entity, "links"): for link in entity.links: entities_updated[link.id] = link except DataObject.Invalid as e: return hrc.BAD_REQUEST(e) except HttpRequestError as e: return e.response # Save (and delete) all affected entities using a single backend operation try: entities = self._save_entities( entities_updated.values(), delete_entity_ids=entities_deleted.keys(), user=request.user ) except HttpRequestError as e: return e.response # Response is a list of created/updated entities dao_list = [] for entity in entities: dao = DataObject(translator=self.translator) dao.load_from_entity(entity) dao_list.append(dao) # Render response if len(dao_list) == 1: renderer.render(dao_list[0]) else: renderer.render(dao_list) # Set Location header to the first ID renderer.headers.append(("Location", dao_list[0].location)) return HttpResponse(renderer.headers, renderer.body)
def _update_collection(self, request, location_category, replace=False): # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Any data-objects submitted? if not parser.objects: return hrc.BAD_REQUEST('No resource instance(s) specified') # Entities to update and delete entities_updated = {} entities_deleted = {} # Only possible to replace a pure Kind/Mixin location if replace: assert (location_category) # When replacing the whole collection we need to: # - Remove the all entities of Kind not part of the update. # - Remove the Mixin from all entities not part of the update. try: if isinstance(location_category, Kind): for entity in self._filter_entities( categories=[location_category], user=request.user): entities_deleted[entity_id] = True elif isinstance(location_category, Mixin): for entity in self._filter_entities( categories=[location_category], user=request.user): try: entity.occi_remove_mixin(location_category) except Entity.UnknownCategory: pass else: entities_updated[entity.id] = entity except HttpRequestError as e: return e.response # Convert request objects to entity instances try: for dao in parser.objects: # Add location category to entity dao if location_category: dao.categories.append(location_category) dao.translator = self.translator # Get Entity ID from request entity_id = dao.get_entity_id() # COMPAT: OCCI HTTP Rendering 1.1 does not threat PUT # /mixin_loc/ as a resource create/replace operation. # Use non-replace mode as workaround. _do_replace = replace if replace and parser.specification() in ('occi-http-1.1'): _do_replace = False # Attempt to load existing Entity if entity_id and not _do_replace: try: entity = entities_updated[entity_id] except KeyError: entity = self._get_entity(entity_id, user=request.user) else: entity = None # Create/update entity object # FIXME: If replacing the entity we leave all links untouched. # This is according to spec but is it convenient? entity = dao.save_to_entity( entity=entity, save_links=(not replace), category_registry=self.backend.registry) entities_updated[entity.id] = entity entities_deleted.pop(entity.id, None) # Add Link objects to list of modified entities if hasattr(entity, 'links'): for link in entity.links: entities_updated[link.id] = link except DataObject.Invalid as e: return hrc.BAD_REQUEST(e) except HttpRequestError as e: return e.response # Save (and delete) all affected entities using a single backend operation try: entities = self._save_entities( entities_updated.values(), delete_entity_ids=entities_deleted.keys(), user=request.user) except HttpRequestError as e: return e.response # Response is a list of created/updated entities dao_list = [] for entity in entities: dao = DataObject(translator=self.translator) dao.load_from_entity(entity) dao_list.append(dao) # Render response if len(dao_list) == 1: renderer.render(dao_list[0]) else: renderer.render(dao_list) # Set Location header to the first ID renderer.headers.append(('Location', dao_list[0].location)) return HttpResponse(renderer.headers, renderer.body)
def post(self, request, path): """Create or update resource instance(s) OR execute an action on the specified collection. """ # Lookup location path location_category = self.backend.registry.lookup_location(path) # Action request? if request.query_args: if not location_category: return hrc.BAD_REQUEST('%s: not a Kind nor Mixin location' % path) return self._collection_action(request, location_category) # Parse request try: parser, renderer = self._request_init(request) except HttpRequestError as e: return e.response # Any data-objects submitted? if not parser.objects: return hrc.BAD_REQUEST('No resource instance(s) specified') # Convert request objects to entity instances entities = [] try: for dao in parser.objects: # Add location category to entity dao if location_category: dao.categories.append(location_category) dao.translator = self.translator # Entity ID specified in request? entity_id = None if dao.attributes: for attr, value in dao.attributes: if attr == 'occi.core.id': entity_id = value elif dao.location: entity = self.translator.to_native(dao.location) if entity: entity_id = entity.id # Attempt to load existing Entity if entity_id: entity = self._get_entity(entity_id, user=request.user) else: entity = None # Create/update entity object entity = dao.save_to_entity(entity=entity, save_links=True, category_registry=self.backend.registry) entities.append(entity) # Add Link objects to list of modified entities if hasattr(entity, 'links'): for link in entity.links: entities.append(link) except DataObject.Invalid as e: return hrc.BAD_REQUEST(e) except HttpRequestError as e: return e.response # Save all entities using a single backend operation try: entities = self._save_entities(entities, user=request.user) except HttpRequestError as e: return e.response # Response is a list of created/updated entities dao_list = [] for entity in entities: dao = DataObject(translator=self.translator) dao.load_from_entity(entity) dao_list.append(dao) # Render response if len(dao_list) == 1: renderer.render(dao_list[0]) else: renderer.render(dao_list) # Set Location header to the first ID renderer.headers.append(('Location', dao_list[0].location)) return HttpResponse(renderer.headers, renderer.body)