async def themecss(context, request): registry = await get_registry() settings = registry.for_interface(ICustomTheme) resp = Response(status=200) resp.content_type = "text/css" disposition = 'filename="style.css"' resp.headers["CONTENT-DISPOSITION"] = disposition resp.content_length = len(settings["css"]) await resp.prepare(request) await resp.write(settings["css"].encode(), eof=True) return resp
async def default_delete(context, request): data = await request.json() behavior = data.get('behavior', None) factory = get_cached_factory(context.type_name) behavior_class = resolve_dotted_name(behavior) if behavior_class is not None: if behavior_class in factory.behaviors: return Response(status=201) if behavior not in context.__behaviors__: return Response(status=201) context.remove_behavior(behavior) return {}
async def delete_behavior(context, behavior): factory = get_cached_factory(context.type_name) behavior_class = resolve_dotted_name(behavior) if behavior_class is not None: if behavior_class in factory.behaviors: return Response(content={ 'reason': 'Behaviors defined on this type must be present and cannot be dynamically removed' }, status=412) if behavior not in context.__behaviors__: return Response(content={'reason': 'Not in behaviors'}, status=412) context.remove_behavior(behavior) return {}
async def delete_behavior(context, behavior): factory = get_cached_factory(context.type_name) behavior_class = resolve_dotted_name(behavior) if behavior_class is not None: if behavior_class in factory.behaviors: return Response(content={ 'reason': 'Not not remove this type of behavior' }, status=412) if behavior not in context.__behaviors__: return Response(content={ 'reason': 'Not in behaviors' }, status=412) context.remove_behavior(behavior) return {}
async def default_patch(context, request): data = await request.json() behavior = data.get('behavior', None) try: behavior_class = resolve_dotted_name(behavior) except ModuleNotFoundError: behavior_class = None if behavior_class is None: return Response(status=404) factory = get_cached_factory(context.type_name) if behavior_class in factory.behaviors: return Response(status=201) if behavior in context.__behaviors__: return Response(status=201) context.add_behavior(behavior) return {}
async def __call__(self): data = await self.request.json() if '@type' not in data or data['@type'] not in app_settings[ 'container_types']: raise HTTPNotFound( content={ 'message': 'can not create this type %s' % data['@type'] }) if 'id' not in data: raise HTTPPreconditionFailed(content={'message': 'We need an id'}) if not data.get('title'): data['title'] = data['id'] if 'description' not in data: data['description'] = '' value = await self.context.async_contains(data['id']) if value: # Already exist raise HTTPConflict( content={'message': 'Container with id already exists'}) install_addons = data.pop('@addons', None) or [] for addon in install_addons: # validate addon list if addon not in app_settings['available_addons']: return ErrorResponse( 'RequiredParam', "Property '@addons' must refer to a valid addon", status=412, reason=error_reasons.INVALID_ID) owner_id = get_authenticated_user_id(self.request) container = await create_container(self.context, data.pop('id'), container_type=data.pop('@type'), owner_id=owner_id, **data) self.request._container_id = container.__name__ self.request.container = container annotations_container = get_adapter(container, IAnnotations) self.request.container_settings = await annotations_container.async_get( REGISTRY_DATA_KEY) for addon in install_addons: await addons.install(container, addon) resp = { '@type': container.type_name, 'id': container.id, 'title': data['title'] } headers = {'Location': posixpath.join(self.request.path, container.id)} return Response(content=resp, headers=headers)
async def __call__(self): """ data input : { 'interface': 'INTERFACE' }""" if not hasattr(self.request, 'container_settings'): return ErrorResponse('BadRequest', _("Not in a container request"), status=412) data = await self.request.json() interface = data.get('interface', None) initial_values = data.get('initial_values', {}) if interface is None: return ErrorResponse('InvalidRequest', 'Non existent Interface', status=412) registry = self.request.container_settings iObject = import_class(interface) registry.register_interface(iObject) config = registry.for_interface(iObject) # Initialize values # If its defined on the guillotina.schema default will not be overwritten # you will need to PATCH for key, field in get_fields(iObject).items(): if key in initial_values and getattr(config, key, _marker) == _marker: # We don't have a value config[key] = initial_values[key] return Response(status=201)
async def __call__(self): if app_settings.get("graphql", {}).get("enable_playground") is True: return Response( content=PLAYGROUND_HTML, headers={"content-type": "text/html"}, ) raise HTTPNotFound()
async def __call__(self): """ data input : { 'interface': 'INTERFACE' }""" registry = await get_registry() if registry is None: return ErrorResponse("BadRequest", _("Not in a container request"), status=412) data = await self.request.json() interface = data.get("interface", None) initial_values = data.get("initial_values", {}) if interface is None: return ErrorResponse("InvalidRequest", "Non existent Interface", status=412) iObject = import_class(interface) registry.register_interface(iObject) config = registry.for_interface(iObject) # Initialize values # If its defined on the guillotina.schema default will not be overwritten # you will need to PATCH for key, field in get_fields(iObject).items(): if key in initial_values and getattr(config, key, _marker) == _marker: # We don't have a value config[key] = initial_values[key] await notify( RegistryEditedEvent(self.context, registry, {interface: initial_values})) return Response(status=201)
async def tus_options(self, *args, **kwargs): resp = Response(headers={ 'Tus-Resumable': '1.0.0', 'Tus-Version': '1.0.0', 'Tus-Extension': 'creation-defer-length' }) return resp
async def __call__(self): data = await self.request.json() if "@type" not in data or data["@type"] not in app_settings[ "container_types"]: raise HTTPNotFound( content={ "message": "can not create this type %s" % data["@type"] }) if "id" not in data: raise HTTPPreconditionFailed(content={"message": "We need an id"}) if not data.get("title"): data["title"] = data["id"] if "description" not in data: data["description"] = "" value = await self.context.async_contains(data["id"]) if value: # Already exist raise HTTPConflict( content={"message": "Container with id already exists"}) install_addons = data.pop("@addons", None) or [] for addon in install_addons: # validate addon list if addon not in app_settings["available_addons"]: return ErrorResponse( "RequiredParam", "Property '@addons' must refer to a valid addon", status=412, reason=error_reasons.INVALID_ID, ) owner_id = get_authenticated_user_id() container = await create_container(self.context, data.pop("id"), container_type=data.pop("@type"), owner_id=owner_id, **data) task_vars.container.set(container) annotations_container = get_adapter(container, IAnnotations) task_vars.registry.set( await annotations_container.async_get(REGISTRY_DATA_KEY)) for addon in install_addons: await addons.install(container, addon) resp = { "@type": container.type_name, "id": container.id, "title": data["title"] } headers = {"Location": posixpath.join(self.request.path, container.id)} return Response(content=resp, headers=headers)
async def add_comment(context, request): payload = await request.json() bhr = ICMSBehavior(context) if not bhr.allow_discussion: raise HTTPUnauthorized(content={"text": "Not available option"}) await bhr.load() if bhr.comments is None: bhr.comments = {} user_id = get_authenticated_user_id() comment_uuid = uuid.uuid4().hex bhr.comments[comment_uuid] = { "@parent": None, "author_name": None, "author_username": user_id, "creation_date": datetime.now().isoformat(), "in_reply_to": None, "is_deletable": True, "is_editable": True, "modification_date": datetime.now().isoformat(), "text": { "data": payload.get("text", ""), "mime-type": "text/plain" }, "user_notification": None, } bhr.register() url = getMultiAdapter((context, request), IAbsoluteURL)() headers = {"Location": url + "/@comments/" + comment_uuid} return Response(status=204, headers=headers)
async def delete_comment(context, request): comment_id = request.matchdict["comment_id"] bhr = ICMSBehavior(context) if not bhr.allow_discussion: raise HTTPUnauthorized(content={"text": "Not available option"}) await bhr.load() if comment_id not in bhr.comments: raise ErrorResponse("InvalidComment", "This comment does not exist", status=412) user_id = get_authenticated_user_id() comment = bhr.comments[comment_id] # TODO: We need ? policy = get_security_policy() if user_id != comment["author_username"] or not policy.check_permission( "guillotina.DeleteAllComments", context): raise HTTPUnauthorized( content={"text": "Not the author or permission"}) list_to_delete = [comment_id] delete_from_list(bhr.comments, list_to_delete) for comment in list_to_delete: del bhr.comments[comment] bhr.register() return Response(status=204)
async def modify_comment(context, request): payload = await request.json() comment_id = request.matchdict["comment_id"] bhr = ICMSBehavior(context) if not bhr.allow_discussion: raise HTTPUnauthorized(content={"text": "Not available option"}) await bhr.load() if comment_id not in bhr.comments: raise ErrorResponse("InvalidComment", "This comment does not exist", status=412) user_id = get_authenticated_user_id() comment = bhr.comments[comment_id] # TODO: We need ? if user_id != comment["author_username"]: raise HTTPUnauthorized(content={"text": "Not the author"}) comment["text"]["data"] = payload.get("text", "") comment["modification_date"] = datetime.now().isoformat() bhr.register() url = getMultiAdapter((context, request), IAbsoluteURL)() headers = {"Location": url + "/@comments/" + comment_id} return Response(status=204, headers=headers)
async def __call__(self): data = await self.get_data() behaviors = data.get("@behaviors", None) for behavior in behaviors or (): try: self.context.add_behavior(behavior) except (TypeError, ComponentLookupError): return HTTPPreconditionFailed( content={"message": f"{behavior} is not a valid behavior", "behavior": behavior} ) deserializer = query_multi_adapter((self.context, self.request), IResourceDeserializeFromJson) if deserializer is None: raise ErrorResponse( "DeserializationError", "Cannot deserialize type {}".format(self.context.type_name), status=412, reason=error_reasons.DESERIALIZATION_FAILED, ) await notify(BeforeObjectModifiedEvent(self.context, payload=data)) await deserializer(data) await notify(ObjectModifiedEvent(self.context, payload=data)) return Response(status=204)
async def __call__(self): data = await self.request.json() if '@type' not in data or data['@type'] not in app_settings[ 'container_types']: raise HTTPNotFound( content={ 'message': 'can not create this type %s' % data['@type'] }) if 'id' not in data: raise HTTPPreconditionFailed(content={'message': 'We need an id'}) if not data.get('title'): data['title'] = data['id'] if 'description' not in data: data['description'] = '' value = await self.context.async_contains(data['id']) if value: # Already exist raise HTTPConflict( content={'message': 'Container with id already exists'}) container = await create_content(data['@type'], id=data['id'], title=data['title'], description=data['description']) # Special case we don't want the parent pointer container.__name__ = data['id'] await self.context.async_set(data['id'], container) await container.install() self.request._container_id = container.__name__ self.request.container = container user = get_authenticated_user_id(self.request) # Local Roles assign owner as the creator user roleperm = IPrincipalRoleManager(container) roleperm.assign_role_to_principal('guillotina.Owner', user) await notify( ObjectAddedEvent(container, self.context, container.__name__, payload=data)) resp = { '@type': data['@type'], 'id': data['id'], 'title': data['title'] } headers = {'Location': posixpath.join(self.request.path, data['id'])} return Response(content=resp, headers=headers)
async def tus_options(self, *args, **kwargs): resp = Response( headers={ "Tus-Resumable": "1.0.0", "Tus-Version": "1.0.0", "Tus-Extension": "creation-defer-length", }) return resp
async def default_patch(context, request): data = await request.json() behavior = data.get("behavior", None) try: behavior_class = resolve_dotted_name(behavior) except ModuleNotFoundError: behavior_class = None if behavior_class is None: return Response(content={"reason": "Could not find behavior"}, status=404) factory = get_cached_factory(context.type_name) if behavior_class in factory.behaviors: return Response(content={"reason": "Already in behaviors"}, status=412) if behavior in context.__behaviors__: return Response(content={"reason": "Already in behaviors"}, status=412) context.add_behavior(behavior) return {}
async def test_raise_response(container_requester): async with container_requester as requester: with mock.patch("guillotina.asgi.Guillotina.request_handler") as handle_mock: # noqa f = asyncio.Future() f.set_result(None) handle_mock.return_value = f handle_mock.side_effect = Response(status=200) _, status = await requester("GET", "/db") assert status == 200
async def __call__(self): """Apply CORS on the OPTIONS view.""" headers = await self.preflight() resp = await self.render() if IResponse.providedBy(resp): headers.update(resp.headers) resp.headers = headers return resp return Response(content=resp, headers=headers)
async def run_editor(context, request): editor_view = await get_object_by_path('/abfab/editor/editor.svelte') return Response(content=wrap_component(request, editor_view, './@edit-data', 'text'), status=200, headers={ 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp', })
async def serve_file(self, fi): filepath = str(fi.file_path.absolute()) filename = fi.file_path.name with open(filepath, "rb") as f: resp = Response(status=200) resp.content_type, _ = mimetypes.guess_type(filename) disposition = 'filename="{}"'.format(filename) if "text" not in (resp.content_type or ""): disposition = "attachment; " + disposition resp.headers["CONTENT-DISPOSITION"] = disposition data = f.read() resp.content_length = len(data) await resp.prepare(self.request) await resp.write(data, eof=True) return resp
async def tus_patch(self, *args, **kwargs): await self.dm.load() to_upload = None if "CONTENT-LENGTH" in self.request.headers: # header is optional, we'll be okay with unknown lengths... to_upload = int(self.request.headers["CONTENT-LENGTH"]) if "UPLOAD-LENGTH" in self.request.headers: if self.dm.get("deferred_length"): size = int(self.request.headers["UPLOAD-LENGTH"]) await self.dm.update(size=size) if "UPLOAD-OFFSET" in self.request.headers: offset = int(self.request.headers["UPLOAD-OFFSET"]) else: raise HTTPPreconditionFailed( content={"reason": "No upload-offset header"}) ob_offset = self.dm.get("offset") if offset != ob_offset: raise HTTPConflict( content={ "reason": f"Current upload offset({offset}) does not match " f"object offset {ob_offset}" }) read_bytes = await self.file_storage_manager.append( self.dm, self._iterate_request_data(), offset) if to_upload and read_bytes != to_upload: # pragma: no cover # check length matches if provided raise HTTPPreconditionFailed( content={ "reason": "Upload size does not match what was provided" }) await self.dm.update(offset=offset + read_bytes) headers = { "Upload-Offset": str(self.dm.get_offset()), "Tus-Resumable": "1.0.0", "Access-Control-Expose-Headers": ",".join(["Upload-Offset", "Tus-Resumable", "Tus-Upload-Finished"]), } if self.dm.get("size") is not None and self.dm.get_offset( ) >= self.dm.get("size"): await self.file_storage_manager.finish(self.dm) await self.dm.finish() headers["Tus-Upload-Finished"] = "1" else: await self.dm.save() return Response(headers=headers)
async def tus_patch(self, *args, **kwargs): await self.dm.load() to_upload = None if 'CONTENT-LENGTH' in self.request.headers: # header is optional, we'll be okay with unknown lengths... to_upload = int(self.request.headers['CONTENT-LENGTH']) if 'UPLOAD-LENGTH' in self.request.headers: if self.dm.get('deferred_length'): size = int(self.request.headers['UPLOAD-LENGTH']) await self.dm.update(size=size) if 'UPLOAD-OFFSET' in self.request.headers: offset = int(self.request.headers['UPLOAD-OFFSET']) else: raise HTTPPreconditionFailed( content={'reason': 'No upload-offset header'}) ob_offset = self.dm.get('offset') if offset != ob_offset: raise HTTPConflict( content={ 'reason': f'Current upload offset({offset}) does not match ' f'object offset {ob_offset}' }) read_bytes = await self.file_storage_manager.append( self.dm, self._iterate_request_data(), offset) if to_upload and read_bytes != to_upload: # check length matches if provided raise HTTPPreconditionFailed( content={ 'reason': 'Upload size does not match what was provided' }) await self.dm.update(offset=offset + read_bytes) headers = { 'Upload-Offset': str(self.dm.get_offset()), 'Tus-Resumable': '1.0.0', 'Access-Control-Expose-Headers': ','.join(['Upload-Offset', 'Tus-Resumable', 'Tus-Upload-Finished']) } if self.dm.get('size') is not None and self.dm.get_offset( ) >= self.dm.get('size'): await self.file_storage_manager.finish(self.dm) await self.dm.finish() headers['Tus-Upload-Finished'] = '1' else: await self.dm.save() return Response(headers=headers)
async def tus_head(self, *args, **kwargs): await self.dm.load() head_response = { 'Upload-Offset': str(self.dm.get_offset()), 'Tus-Resumable': '1.0.0', 'Access-Control-Expose-Headers': 'Upload-Offset,Tus-Resumable' } if self.dm.get('size'): head_response['Upload-Length'] = str(self.dm.get('size')) return Response(headers=head_response)
async def tus_head(self, *args, **kwargs): await self.dm.load() head_response = { "Upload-Offset": str(self.dm.get_offset()), "Tus-Resumable": "1.0.0", "Access-Control-Expose-Headers": "Upload-Offset,Tus-Resumable,Upload-Length", } if self.dm.get("size"): head_response["Upload-Length"] = str(self.dm.get("size")) else: head_response["Upload-Length"] = "0" return Response(headers=head_response)
async def handler(self, request): """Main handler function""" request._view_error = False await notify(BeforeRenderViewEvent(request, self.view)) request.record("viewrender") try: # We try to avoid collisions on the same instance of # guillotina view_result = await self.view() if app_settings["check_writable_request"](request): await commit(warn=False) else: await abort() except (ConflictError, TIDConflictError): await abort() # bubble this error up raise except response.Response as exc: await abort() view_result = exc request._view_error = True except Exception: await abort() raise request.record("viewrendered") resp = view_result if resp is None: resp = Response(status=200) if not IResponse.providedBy(resp) or not resp.prepared: resp = await apply_rendering(self.view, self.request, resp) request.record("renderer") resp = await apply_cors(request, resp) if not request._view_error: task = request.execute_futures() else: task = request.execute_futures("failure") if task is not None: await self.wait(request, resp, task) self.debug(request, resp) request.record("finish") del self.view del self.resource request.clear_futures() return resp
async def __call__(self): if self.key is _marker: # No option to write the root of registry return ErrorResponse("InvalidRequest", "Needs the registry key", status=412) data = await self.request.json() if "value" in data: value = data["value"] else: value = data assert "." in self.key, "Registry key must be dotted.iface.name.fieldname" # noqa iface_name, name = self.key.rsplit(".", 1) iface = resolve_dotted_name(iface_name) assert iface is not None, "Must provide valid registry interface" # noqa try: field = iface[name] except KeyError: return ErrorResponse("DeserializationError", "Invalid field name {}".format(str(name)), status=412) try: new_value = get_adapter((field), IJSONToValue, args=[value, self.context]) except ComponentLookupError: return ErrorResponse("DeserializationError", "Cannot deserialize type {}".format( str(self.field)), status=412) try: registry = await get_registry() registry[self.key] = new_value except (DeserializationError, ValueDeserializationError) as e: return ErrorResponse("DeserializationError", str(e), exc=e, status=412) await notify( RegistryEditedEvent(self.context, registry, {iface_name: { name: value }})) return Response(status=204)
async def __call__(self): registry = await get_registry() settings = registry.for_interface(IImagingSettings) scale_name = self.request.matchdict["scale"] allowed_sizes = settings["allowed_sizes"] if scale_name not in allowed_sizes: raise HTTPNotFound( content={"reason": f"{scale_name} is not supported"}) file = self.field.get(self.field.context or self.context) if file is None: raise HTTPNotFound( content={ "message": "File or custom filename required to download" }) adapter = get_multi_adapter((self.context, self.request, self.field), IFileManager) data = b"" async for chunk in adapter.iter_data(): data += chunk width, _, height = allowed_sizes[scale_name].partition(":") result, format_, size = scaleImage( data, int(width), int(height), quality=settings["quality"], direction="thumbnail", ) cors_renderer = app_settings["cors_renderer"](self.request) headers = await cors_renderer.get_headers() headers.update({ "CONTENT-DISPOSITION": 'attachment; filename="{}"'.format(file.filename) }) download_resp = Response( status=200, headers=headers, content_type=f"image/{format_}", content_length=len(result), ) await download_resp.prepare(self.request) await download_resp.write(result) await download_resp.write(eof=True) return download_resp
async def __call__(self, value) -> Response: """ Value can be: - Guillotina response object - serializable value """ if IResponse.providedBy(value): resp = cast(Response, value) if resp.content is not None: resp.set_body(self.get_body(resp.content), self.content_type) return resp return Response(body=self.get_body(value) or b"", status=200, content_type=self.content_type)