def make_aiohttp_application(): middlewares = [resolve_dotted_name(m) for m in app_settings.get('middlewares', [])] router_klass = app_settings.get('router', TraversalRouter) router = resolve_dotted_name(router_klass)() return GuillotinaAIOHTTPApplication( router=router, middlewares=middlewares, **app_settings.get('aiohttp_settings', {}))
def make_aiohttp_application(): middlewares = [resolve_dotted_name(m) for m in app_settings.get('middlewares', [])] router_klass = app_settings.get('router', TraversalRouter) router = resolve_dotted_name(router_klass)() return GuillotinaAIOHTTPApplication( router=router, middlewares=middlewares, **app_settings.get('aiohttp_settings', {}))
def load_service(_context, service): # prevent circular import from guillotina.security.utils import protect_view service_conf = service["config"] factory = resolve_dotted_name(service["klass"]) permission = service_conf.get("permission", app_settings.get("default_permission", None)) protect_view(factory, permission) method = service_conf.get("method", "GET") default_layer = resolve_dotted_name( app_settings.get("default_layer", IDefaultLayer)) layer = service_conf.get("layer", default_layer) name = service_conf.get("name", "") content = service_conf.get("context", Interface) logger.debug("Defining adapter for " # noqa "{0:s} {1:s} {2:s} to {3:s} name {4:s}".format( content.__identifier__, app_settings["http_methods"][method].__identifier__, layer.__identifier__, str(factory), name, )) if not getattr(factory, "__route__", None): factory.__route__ = routes.Route(name) else: factory.__route__.service_configuration = service_conf service_conf["route"] = [str(rp) for rp in factory.__route__.route_parts] component.adapter( _context, factory=(factory, ), provides=app_settings["http_methods"][method], for_=(content, layer), name=factory.__route__.view_name, ) api = app_settings["api_definition"] ct_name = content.__identifier__ if ct_name not in api: api[ct_name] = OrderedDict() ct_api = api[ct_name] if name: if "endpoints" not in ct_api: ct_api["endpoints"] = OrderedDict() if name not in ct_api["endpoints"]: ct_api["endpoints"][name] = OrderedDict() ct_api["endpoints"][name][method] = OrderedDict(service_conf) else: ct_api[method] = OrderedDict(service_conf)
def load_service(_context, service): # prevent circular import from guillotina.security.utils import protect_view service_conf = service['config'] factory = resolve_dotted_name(service['klass']) permission = service_conf.get( 'permission', app_settings.get('default_permission', None)) protect_view(factory, permission) method = service_conf.get('method', 'GET') default_layer = resolve_dotted_name( app_settings.get('default_layer', IDefaultLayer)) layer = service_conf.get('layer', default_layer) name = service_conf.get('name', '') content = service_conf.get('context', Interface) logger.debug('Defining adapter for ' # noqa '{0:s} {1:s} {2:s} to {3:s} name {4:s}'.format( content.__identifier__, app_settings['http_methods'][method].__identifier__, layer.__identifier__, str(factory), name)) if not getattr(factory, '__route__', None): factory.__route__ = routes.Route(name) else: factory.__route__.service_configuration = service_conf component.adapter( _context, factory=(factory,), provides=app_settings['http_methods'][method], for_=(content, layer), name=factory.__route__.view_name ) api = app_settings['api_definition'] ct_name = content.__identifier__ if ct_name not in api: api[ct_name] = OrderedDict() ct_api = api[ct_name] if name: if 'endpoints' not in ct_api: ct_api['endpoints'] = OrderedDict() if name not in ct_api['endpoints']: ct_api['endpoints'][name] = OrderedDict() ct_api['endpoints'][name][method] = OrderedDict(service_conf) else: ct_api[method] = OrderedDict(service_conf)
def load_service(_context, service): # prevent circular import from guillotina.security.utils import protect_view service_conf = service['config'] factory = resolve_dotted_name(service['klass']) permission = service_conf.get( 'permission', app_settings.get('default_permission', None)) protect_view(factory, permission) method = service_conf.get('method', 'GET') default_layer = resolve_dotted_name( app_settings.get('default_layer', IDefaultLayer)) layer = service_conf.get('layer', default_layer) name = service_conf.get('name', '') content = service_conf.get('context', Interface) logger.debug('Defining adapter for ' # noqa '{0:s} {1:s} {2:s} to {3:s} name {4:s}'.format( content.__identifier__, app_settings['http_methods'][method].__identifier__, layer.__identifier__, str(factory), name)) if not getattr(factory, '__route__', None): factory.__route__ = routes.Route(name) else: factory.__route__.service_configuration = service_conf component.adapter( _context, factory=(factory,), provides=app_settings['http_methods'][method], for_=(content, layer), name=factory.__route__.view_name ) api = app_settings['api_definition'] ct_name = content.__identifier__ if ct_name not in api: api[ct_name] = OrderedDict() ct_api = api[ct_name] if name: if 'endpoints' not in ct_api: ct_api['endpoints'] = OrderedDict() if name not in ct_api['endpoints']: ct_api['endpoints'][name] = OrderedDict() ct_api['endpoints'][name][method] = OrderedDict(service_conf) else: ct_api[method] = OrderedDict(service_conf)
def update_app_settings(settings): for key, value in settings.items(): if (isinstance(app_settings.get(key), dict) and isinstance(value, dict)): app_settings[key].update(value) else: app_settings[key] = value
async def __aenter__(self): self.requester = await self.get_requester() resp, status = await self.requester( "POST", "/db", data=json.dumps({ "@type": "Container", # to be able to register for tests "@addons": app_settings.get("__test_addons__") or [], "title": "Guillotina Container", "id": "guillotina", "description": "Description Guillotina Container", }), ) assert status == 200 for addon in self.install: await self.requester("POST", "/db/guillotina/@addons", data=json.dumps({"id": addon})) return self.requester
def update_app_settings(settings): for key, value in settings.items(): if (isinstance(app_settings.get(key), dict) and isinstance(value, dict)): app_settings[key].update(value) else: app_settings[key] = value
def make_app(config_file=None, settings=None, loop=None): from guillotina.asgi import AsgiApp router_klass = app_settings.get("router", traversal.TraversalRouter) app = AsgiApp(config_file, settings, loop, resolve_dotted_name(router_klass)()) return app
def get_conflict_summary(self, oid, txn, old_serial, writer): from guillotina.utils import get_current_request try: req = get_current_request() except RequestNotFound: req = None max_attempts = app_settings.get('conflict_retry_attempts', 3) attempts = getattr(req, '_retry_attempt', 0) return f'''Object ID: {oid}
async def addable_types(context, request): constrains = IConstrainTypes(context, None) types = constrains and constrains.get_allowed_types() if types is None: types = [ type_name for type_name in FACTORY_CACHE if constrains.is_globally_allowed(type_name) ] container_types = app_settings.get("container_types", []) types = [item for item in types if item not in container_types] return types
async def __aenter__(self): self.requester = await self.get_requester() resp, status = await self.requester('POST', '/db', data=json.dumps({ "@type": "Container", # to be able to register for tests "@addons": app_settings.get('__test_addons__') or [], "title": "Guillotina Container", "id": "guillotina", "description": "Description Guillotina Container" })) assert status == 200 return self.requester
async def __aenter__(self): self.requester = await self.get_requester() resp, status = await self.requester('POST', '/db', data=json.dumps({ "@type": "Container", # to be able to register for tests "@addons": app_settings.get('__test_addons__') or [], "title": "Guillotina Container", "id": "guillotina", "description": "Description Guillotina Container" })) assert status == 200 return self.requester
def __init__(self, context, request, field): self.context = context self.request = request self.field = field iface = resolve_dotted_name(app_settings["cloud_storage"]) alsoProvides(field, iface) self.file_storage_manager = get_multi_adapter((context, request, field), IFileStorageManager) self.dm = get_adapter( self.file_storage_manager, IUploadDataManager, name=app_settings.get("cloud_datamanager") or "db" )
def __init__(self, context, request, field): self.context = context self.request = request self.field = field iface = import_class(app_settings['cloud_storage']) alsoProvides(field, iface) self.file_storage_manager = get_multi_adapter( (context, request, field), IFileStorageManager) self.dm = get_adapter(self.file_storage_manager, IUploadDataManager, name=app_settings.get('cloud_datamanager') or 'db')
def generate_error_response(self, e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex if isinstance(e, asyncio.CancelledError): # pragma: no cover message = _("Cancelled execution of view") + " " + eid logger.warning(message, exc_info=e, eid=eid, request=request) else: message = _("Error on execution of view") + " " + eid logger.error(message, exc_info=e, eid=eid, request=request) data = { "message": message, "reason": error_reasons.UNKNOWN.name, "details": error_reasons.UNKNOWN.details, "eid": eid, } if app_settings.get("debug"): data["traceback"] = traceback.format_exc() return response.HTTPInternalServerError(content=data)
async def _handle(self, request, retries=0): aiotask_context.set('request', request) try: return await super()._handle(request) except (ConflictError, TIDConflictError) as e: if app_settings.get('conflict_retry_attempts', 3) > retries: label = 'DB Conflict detected' if isinstance(e, TIDConflictError): label = 'TID Conflict Error detected' tid = getattr(getattr(request, '_txn', None), '_tid', 'not issued') logger.debug( f'{label}, retrying request, tid: {tid}, retries: {retries + 1})', exc_info=True) request._retry_attempt = retries + 1 request.clear_futures() return await self._handle(request, retries + 1) logger.error( 'Exhausted retry attempts for conflict error on tid: {}'.format( getattr(getattr(request, '_txn', None), '_tid', 'not issued') )) return HTTPConflict()
async def _handle(self, request, retries=0): aiotask_context.set('request', request) try: return await super()._handle(request) except (ConflictError, TIDConflictError) as e: if app_settings.get('conflict_retry_attempts', 3) > retries: label = 'DB Conflict detected' if isinstance(e, TIDConflictError): label = 'TID Conflict Error detected' tid = getattr(getattr(request, '_txn', None), '_tid', 'not issued') logger.debug( f'{label}, retrying request, tid: {tid}, retries: {retries + 1})', exc_info=True) request._retry_attempt = retries + 1 request.clear_futures() return await self._handle(request, retries + 1) logger.error( 'Exhausted retry attempts for conflict error on tid: {}'.format( getattr(getattr(request, '_txn', None), '_tid', 'not issued') )) return HTTPConflict()
def generate_error_response(e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex http_response = query_adapter(e, IErrorResponseException, kwargs={ 'error': error, 'eid': eid }) if http_response is not None: return http_response message = _('Error on execution of view') + ' ' + eid logger.error(message, exc_info=e, eid=eid, request=request) data = { 'message': message, 'reason': error_reasons.UNKNOWN.name, 'details': error_reasons.UNKNOWN.details, 'eid': eid } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() return response.HTTPInternalServerError(content=data)
def generate_error_response(e, request, error, status=500): # We may need to check the roles of the users to show the real error eid = uuid.uuid4().hex http_response = query_adapter(e, IErrorResponseException, kwargs={ "error": error, "eid": eid }) if http_response is not None: return http_response message = _("Error on execution of view") + " " + eid logger.error(message, exc_info=e, eid=eid, request=request) data = { "message": message, "reason": error_reasons.UNKNOWN.name, "details": error_reasons.UNKNOWN.details, "eid": eid, } if app_settings.get("debug"): data["traceback"] = traceback.format_exc() return response.HTTPInternalServerError(content=data)
async def _handle(self, request, retries=0): task_vars.request.set(request) for var in ( "txn", "tm", "futures", "authenticated_user", "security_policies", "container", "registry", "db", ): # and make sure to reset various task vars... getattr(task_vars, var).set(None) try: return await super()._handle(request) except (ConflictError, TIDConflictError) as e: if app_settings.get("conflict_retry_attempts", 3) > retries: label = "DB Conflict detected" if isinstance(e, TIDConflictError): label = "TID Conflict Error detected" tid = getattr(getattr(request, "_txn", None), "_tid", "not issued") logger.debug( f"{label}, retrying request, tid: {tid}, retries: {retries + 1})", exc_info=True) request._retry_attempt = retries + 1 request.clear_futures() return await self._handle(request, retries + 1) logger.error( "Exhausted retry attempts for conflict error on tid: {}". format( getattr(getattr(request, "_txn", None), "_tid", "not issued"))) return HTTPConflict(body=json.dumps({"summary": str(e)}), content_type="application/json")
async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]: """Main function to resolve a request.""" if request.method not in app_settings['http_methods']: raise HTTPMethodNotAllowed( method=request.method, allowed_methods=[ k for k in app_settings['http_methods'].keys() ]) method = app_settings['http_methods'][request.method] try: resource, tail = await self.traverse(request) except ConflictError: # can also happen from connection errors so we bubble this... raise except Exception as _exc: logger.error('Unhandled exception occurred', exc_info=True) request.resource = request.tail = None request.exc = _exc data = { 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() raise HTTPBadRequest(content={'reason': data}) request.record('traversed') await notify(ObjectLoadedEvent(resource)) request.resource = resource request.tail = tail if request.resource is None: await notify(TraversalResourceMissEvent(request, tail)) raise HTTPNotFound(content={"reason": 'Resource not found'}) if tail and len(tail) > 0: # convert match lookups view_name = routes.path_to_view_name(tail) elif not tail: view_name = '' request.record('beforeauthentication') authenticated = await authenticate_request(request) # Add anonymous participation if authenticated is None: authenticated = AnonymousUser() set_authenticated_user(authenticated) request.record('authentication') policy = get_security_policy(authenticated) for language in get_acceptable_languages(request): translator = query_adapter((resource, request), ILanguage, name=language) if translator is not None: resource = translator.translate() break # container registry lookup try: view = query_multi_adapter((resource, request), method, name=view_name) except AttributeError: view = None if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) # Check security on context to AccessContent unless # is view allows explicit or its OPTIONS permission = get_utility(IPermission, name='guillotina.AccessContent') if not policy.check_permission(permission.id, resource): # Check if its a CORS call: if IOPTIONS != method: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.info( "No access content {content} with {auth}".format( content=resource, auth=authenticated.id), request=request) raise HTTPUnauthorized( content={ "reason": "You are not authorized to access content", "content": str(resource), "auth": authenticated.id }) if not view and len(tail) > 0: # we should have a view in this case because we are matching routes await notify(TraversalViewMissEvent(request, tail)) return None request.found_view = view request.view_name = view_name request.record('viewfound') ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if view_permission is None: # use default view permission view_permission = app_settings['default_permission'] if not policy.check_permission(view_permission, view): if IOPTIONS != method: raise HTTPUnauthorized( content={ "reason": "You are not authorized to view", "content": str(resource), "auth": authenticated.id }) try: view.__route__.matches(request, tail or []) except (KeyError, IndexError): await notify(TraversalRouteMissEvent(request, tail)) return None except AttributeError: pass if hasattr(view, 'prepare'): view = (await view.prepare()) or view request.record('authorization') return MatchInfo(resource, request, view)
async def make_app(config_file=None, settings=None, loop=None, server_app=None): ''' Make application from configuration :param config_file: path to configuration file to load :param settings: dictionary of settings :param loop: if not using with default event loop :param settings: provide your own aiohttp application ''' # reset app_settings startup_vars = {} for key in app_settings.keys(): if key[0] == '_': startup_vars[key] = app_settings[key] app_settings.clear() app_settings.update(startup_vars) app_settings.update(deepcopy(default_settings)) if loop is None: loop = asyncio.get_event_loop() # chainmap task factory is actually very important # default task factory uses inheritance in a way # that bubbles back down. So it's possible for a sub-task # to clear out the request of the parent task loop.set_task_factory(aiotask_context.chainmap_task_factory) if config_file is not None: with open(config_file, 'r') as config: settings = json.load(config) elif settings is None: raise Exception('Neither configuration or settings') # Create root Application root = ApplicationRoot(config_file, loop) provide_utility(root, IApplication, 'root') # Initialize global (threadlocal) ZCA configuration config = root.config = ConfigurationMachine() app_configurator = ApplicationConfigurator( settings.get('applications') or [], config, root, settings ) configure.scan('guillotina.renderers') configure.scan('guillotina.api') configure.scan('guillotina.content') configure.scan('guillotina.registry') configure.scan('guillotina.auth') configure.scan('guillotina.json') configure.scan('guillotina.behaviors') configure.scan('guillotina.languages') configure.scan('guillotina.permissions') configure.scan('guillotina.security.security_local') configure.scan('guillotina.security.policy') configure.scan('guillotina.auth.participation') configure.scan('guillotina.catalog.index') configure.scan('guillotina.catalog.catalog') configure.scan('guillotina.files') configure.scan('guillotina.annotations') configure.scan('guillotina.constraintypes') configure.scan('guillotina.subscribers') configure.scan('guillotina.db.strategies') configure.scan('guillotina.db.cache') configure.scan('guillotina.db.writer') configure.scan('guillotina.db.factory') configure.scan('guillotina.exc_resp') configure.scan('guillotina.fields') configure.scan('guillotina.migrations') # always load guillotina app_configurator.configure_application('guillotina') app_configurator.configure_all_applications() apply_concrete_behaviors() # update *after* plugins loaded update_app_settings(settings) if 'logging' in app_settings: try: logging.config.dictConfig(app_settings['logging']) except Exception: logger.error('Could not setup logging configuration', exc_info=True) # Make and initialize aiohttp app if server_app is None: server_app = make_aiohttp_application() root.app = server_app server_app.root = root server_app.config = config optimize_settings(app_settings) await notify(ApplicationConfiguredEvent(server_app, loop)) for key, dbconfig in list_or_dict_items(app_settings['databases']): factory = get_utility( IDatabaseConfigurationFactory, name=dbconfig['storage']) root[key] = await factory(key, dbconfig, loop) await notify(DatabaseInitializedEvent(root[key])) for key, file_path in list_or_dict_items(app_settings['static']): path = resolve_path(file_path).resolve() if not path.exists(): raise Exception('Invalid static directory {}'.format(file_path)) if path.is_dir(): root[key] = StaticDirectory(path) else: root[key] = StaticFile(path) for key, file_path in list_or_dict_items(app_settings['jsapps']): path = resolve_path(file_path).resolve() if not path.exists() or not path.is_dir(): raise Exception('Invalid jsapps directory {}'.format(file_path)) root[key] = JavaScriptApplication(path) root.set_root_user(app_settings['root_user']) if app_settings.get('jwk') and\ app_settings.get('jwk').get('k') and\ app_settings.get('jwk').get('kty'): key = jwk.JWK.from_json(json.dumps(app_settings.get('jwk'))) app_settings['jwk'] = key # {"k":"QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo","kty":"oct"} if not app_settings.get('debug') and app_settings['jwt'].get('secret'): # validate secret secret = app_settings['jwt']['secret'] if secret == 'secret': logger.warning( 'You are using a very insecure secret key in production mode. ' 'It is strongly advised that you provide a better value for ' '`jwt.secret` in your config.') elif not secure_passphrase(app_settings['jwt']['secret']): logger.warning( 'You are using a insecure secret key in production mode. ' 'It is recommended that you provide a more complex value for ' '`jwt.secret` in your config.') # Set router root server_app.router.set_root(root) server_app.on_cleanup.append(cleanup_app) for util in app_settings.get('utilities') or []: logger.warn('Adding : ' + util['provides']) root.add_async_utility(util['provides'], util, loop=loop) for key, util in app_settings['load_utilities'].items(): logger.info('Adding ' + key + ' : ' + util['provides']) root.add_async_utility(key, util, loop=loop) # Load cached Schemas load_cached_schema() await notify(ApplicationInitializedEvent(server_app, loop)) return server_app
def executor(self): if self._executor is None: self._executor = ThreadPoolExecutor( max_workers=app_settings.get("thread_pool_workers", 32)) return self._executor
async def make_app(config_file=None, settings=None, loop=None, server_app=None): ''' Make application from configuration :param config_file: path to configuration file to load :param settings: dictionary of settings :param loop: if not using with default event loop :param settings: provide your own aiohttp application ''' # reset app_settings startup_vars = {} for key in app_settings.keys(): if key[0] == '_': startup_vars[key] = app_settings[key] app_settings.clear() app_settings.update(startup_vars) app_settings.update(default_settings) if loop is None: loop = asyncio.get_event_loop() # chainmap task factory is actually very important # default task factory uses inheritance in a way # that bubbles back down. So it's possible for a sub-task # to clear out the request of the parent task loop.set_task_factory(aiotask_context.chainmap_task_factory) if config_file is not None: with open(config_file, 'r') as config: settings = json.load(config) elif settings is None: raise Exception('Neither configuration or settings') # Create root Application root = ApplicationRoot(config_file, loop) provide_utility(root, IApplication, 'root') # Initialize global (threadlocal) ZCA configuration config = root.config = ConfigurationMachine() import guillotina import guillotina.db.factory import guillotina.db.writer import guillotina.db.db configure.scan('guillotina.renderers') configure.scan('guillotina.api') configure.scan('guillotina.content') configure.scan('guillotina.registry') configure.scan('guillotina.auth') configure.scan('guillotina.json') configure.scan('guillotina.behaviors') configure.scan('guillotina.languages') configure.scan('guillotina.permissions') configure.scan('guillotina.security.security_local') configure.scan('guillotina.security.policy') configure.scan('guillotina.auth.participation') configure.scan('guillotina.catalog.index') configure.scan('guillotina.catalog.catalog') configure.scan('guillotina.files') configure.scan('guillotina.annotations') configure.scan('guillotina.constraintypes') configure.scan('guillotina.subscribers') configure.scan('guillotina.db.strategies') configure.scan('guillotina.db.cache') configure.scan('guillotina.exc_resp') configure.scan('guillotina.fields') configure.scan('guillotina.migrations') load_application(guillotina, root, settings) config.execute_actions() config.commit() configured = ['guillotina'] for module_name in settings.get('applications') or []: configure_application(module_name, config, root, settings, configured) apply_concrete_behaviors() # update *after* plugins loaded update_app_settings(settings) if 'logging' in app_settings: logging.config.dictConfig(app_settings['logging']) # Make and initialize aiohttp app if server_app is None: server_app = make_aiohttp_application() root.app = server_app server_app.root = root server_app.config = config optimize_settings(app_settings) await notify(ApplicationConfiguredEvent(server_app, loop)) for key, dbconfig in list_or_dict_items(app_settings['databases']): factory = get_utility(IDatabaseConfigurationFactory, name=dbconfig['storage']) root[key] = await factory(key, dbconfig, loop) await notify(DatabaseInitializedEvent(root[key])) for key, file_path in list_or_dict_items(app_settings['static']): path = resolve_path(file_path).resolve() if not path.exists(): raise Exception('Invalid static directory {}'.format(file_path)) if path.is_dir(): root[key] = StaticDirectory(path) else: root[key] = StaticFile(path) for key, file_path in list_or_dict_items(app_settings['jsapps']): path = resolve_path(file_path).resolve() if not path.exists() or not path.is_dir(): raise Exception('Invalid jsapps directory {}'.format(file_path)) root[key] = JavaScriptApplication(path) root.set_root_user(app_settings['root_user']) if app_settings.get('jwk') and\ app_settings.get('jwk').get('k') and\ app_settings.get('jwk').get('kty'): key = jwk.JWK.from_json(json.dumps(app_settings.get('jwk'))) app_settings['jwk'] = key # {"k":"QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo","kty":"oct"} if not app_settings.get('debug') and app_settings['jwt'].get('secret'): # validate secret secret = app_settings['jwt']['secret'] if secret == 'secret': logger.warning( 'You are using a very insecure secret key in production mode. ' 'It is strongly advised that you provide a better value for ' '`jwt.secret` in your config.') elif not secure_passphrase(app_settings['jwt']['secret']): logger.warning( 'You are using a insecure secret key in production mode. ' 'It is recommended that you provide a more complex value for ' '`jwt.secret` in your config.') # Set router root server_app.router.set_root(root) server_app.on_cleanup.append(cleanup_app) for util in app_settings.get('utilities') or []: logger.warn('Adding : ' + util['provides']) root.add_async_utility(util['provides'], util, loop=loop) for key, util in app_settings['load_utilities'].items(): logger.info('Adding ' + key + ' : ' + util['provides']) root.add_async_utility(key, util, loop=loop) # Load cached Schemas load_cached_schema() await notify(ApplicationInitializedEvent(server_app, loop)) return server_app
def make_app(config_file=None, settings=None, loop=None, server_app=None): app_settings.update(_delayed_default_settings) if loop is None: loop = asyncio.get_event_loop() loop.set_task_factory(aiotask_context.task_factory) if config_file is not None: with open(config_file, 'r') as config: settings = json.load(config) elif settings is None: raise Exception('Neither configuration or settings') # Create root Application root = ApplicationRoot(config_file) provide_utility(root, IApplication, 'root') # Initialize global (threadlocal) ZCA configuration config = root.config = ConfigurationMachine() import guillotina import guillotina.db.factory import guillotina.db.writer import guillotina.db.db configure.scan('guillotina.translation') configure.scan('guillotina.renderers') configure.scan('guillotina.api') configure.scan('guillotina.content') configure.scan('guillotina.registry') configure.scan('guillotina.auth') configure.scan('guillotina.json') configure.scan('guillotina.behaviors') configure.scan('guillotina.languages') configure.scan('guillotina.permissions') configure.scan('guillotina.security.security_local') configure.scan('guillotina.security.policy') configure.scan('guillotina.auth.participation') configure.scan('guillotina.catalog.index') configure.scan('guillotina.catalog.catalog') configure.scan('guillotina.framing') configure.scan('guillotina.files') configure.scan('guillotina.annotations') configure.scan('guillotina.constraintypes') configure.scan('guillotina.subscribers') configure.scan('guillotina.db.strategies') configure.scan('guillotina.db.cache') load_application(guillotina, root, settings) config.execute_actions() config.commit() for module_name in settings.get('applications', []): config.begin(module_name) load_application(resolve_dotted_name(module_name), root, settings) config.execute_actions() config.commit() # XXX we clear now to save some memory # it's unclear to me if this is necesary or not but it seems to me that # we don't need things registered in both components AND here. configure.clear() # update *after* plugins loaded update_app_settings(settings) if 'logging' in app_settings: logging.config.dictConfig(app_settings['logging']) # Make and initialize aiohttp app if server_app is None: server_app = make_aiohttp_application() root.app = server_app server_app.root = root server_app.config = config content_type = ContentNegotiatorUtility('content_type', app_settings['renderers'].keys()) language = ContentNegotiatorUtility('language', app_settings['languages'].keys()) provide_utility(content_type, IContentNegotiation, 'content_type') provide_utility(language, IContentNegotiation, 'language') for database in app_settings['databases']: for key, dbconfig in database.items(): factory = get_utility(IDatabaseConfigurationFactory, name=dbconfig['storage']) if asyncio.iscoroutinefunction(factory): future = asyncio.ensure_future(factory(key, dbconfig, server_app), loop=loop) loop.run_until_complete(future) root[key] = future.result() else: root[key] = factory(key, dbconfig) for key, file_path in list_or_dict_items(app_settings['static']): path = resolve_path(file_path).resolve() if not path.exists(): raise Exception('Invalid static directory {}'.format(file_path)) if path.is_dir(): root[key] = StaticDirectory(path) else: root[key] = StaticFile(path) for key, file_path in list_or_dict_items(app_settings['jsapps']): path = resolve_path(file_path).resolve() if not path.exists() or not path.is_dir(): raise Exception('Invalid jsapps directory {}'.format(file_path)) root[key] = JavaScriptApplication(path) root.set_root_user(app_settings['root_user']) if RSA is not None and not app_settings.get('rsa'): key = RSA.generate(2048) pub_jwk = {'k': key.publickey().exportKey('PEM')} priv_jwk = {'k': key.exportKey('PEM')} app_settings['rsa'] = {'pub': pub_jwk, 'priv': priv_jwk} # Set router root server_app.router.set_root(root) for utility in get_all_utilities_registered_for(IAsyncUtility): # In case there is Utilties that are registered if hasattr(utility, 'initialize'): task = asyncio.ensure_future(lazy_apply(utility.initialize, app=server_app), loop=loop) root.add_async_task(utility, task, {}) else: logger.warn(f'No initialize method found on {utility} object') server_app.on_cleanup.append(close_utilities) for util in app_settings['utilities']: root.add_async_utility(util, loop=loop) # Load cached Schemas load_cached_schema() optimize_settings(app_settings) return server_app
async def real_resolve(self, request: IRequest) -> MatchInfo: """Main function to resolve a request.""" security = get_adapter(request, IInteraction) if request.method not in app_settings['http_methods']: raise HTTPMethodNotAllowed() method = app_settings['http_methods'][request.method] language = language_negotiation(request) language_object = language(request) try: resource, tail = await self.traverse(request) except ConflictError: # can also happen from connection errors so we bubble this... raise except Exception as _exc: logger.error('Unhandled exception occurred', exc_info=True) request.resource = request.tail = None request.exc = _exc data = { 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() raise HTTPBadRequest(text=ujson.dumps(data)) request.record('traversed') await notify(ObjectLoadedEvent(resource)) request.resource = resource request.tail = tail if request.resource is None: raise HTTPBadRequest(text='Resource not found') traverse_to = None if tail and len(tail) == 1: view_name = tail[0] elif tail is None or len(tail) == 0: view_name = '' else: view_name = tail[0] traverse_to = tail[1:] request.record('beforeauthentication') await self.apply_authorization(request) request.record('authentication') translator = query_adapter(language_object, ITranslated, args=[resource, request]) if translator is not None: resource = translator.translate() # Add anonymous participation if len(security.participations) == 0: security.add(AnonymousParticipation(request)) # container registry lookup try: view = query_multi_adapter((resource, request), method, name=view_name) except AttributeError: view = None request.found_view = view request.view_name = view_name # Traverse view if its needed if traverse_to is not None and view is not None: if not ITraversableView.providedBy(view): return None else: try: view = await view.publish_traverse(traverse_to) except KeyError: return None # not found, it's okay. except Exception as e: logger.error("Exception on view execution", exc_info=e, request=request) return None request.record('viewfound') permission = get_utility(IPermission, name='guillotina.AccessContent') if not security.check_permission(permission.id, resource): # Check if its a CORS call: if IOPTIONS != method: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.info( "No access content {content} with {auths}".format( content=resource, auths=str([ x.principal.id for x in security.participations ])), request=request) raise HTTPUnauthorized() if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) if view: ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if not security.check_permission(view_permission, view): logger.info("No access for view {content} with {auths}".format( content=resource, auths=str( [x.principal.id for x in security.participations])), request=request) raise HTTPUnauthorized() request.record('authorization') renderer = content_type_negotiation(request, resource, view) renderer_object = renderer(request) rendered = query_multi_adapter((renderer_object, view, request), IRendered) request.record('renderer') if rendered is not None: return MatchInfo(resource, request, view, rendered) else: return None
async def get_json(self): if not app_settings.get('store_json', True): return {} adapter = query_adapter(self._obj, ICatalogDataAdapter) if adapter is not None: return await adapter()
def serialize(self): protocol = app_settings.get("pickle_protocol", pickle.HIGHEST_PROTOCOL) return pickle.dumps(self._obj, protocol=protocol)
async def get_json(self): if not app_settings.get('store_json', False): return {} adapter = query_adapter(self._obj, IJSONDBSerializer) if adapter is not None: return await adapter()
def get_conflict_summary(self, oid, txn, old_serial, writer): from guillotina.utils import get_current_request req = get_current_request() max_attempts = app_settings.get('conflict_retry_attempts', 3) attempts = getattr(req, '_retry_attempt', 0) return f'''Object ID: {oid}
async def make_app(config_file=None, settings=None, loop=None, server_app=None): # reset app_settings app_settings.clear() app_settings.update(default_settings) if loop is None: loop = asyncio.get_event_loop() # chainmap task factory is actually very important # default task factory uses inheritance in a way # that bubbles back down. So it's possible for a sub-task # to clear out the request of the parent task loop.set_task_factory(aiotask_context.chainmap_task_factory) if config_file is not None: with open(config_file, 'r') as config: settings = json.load(config) elif settings is None: raise Exception('Neither configuration or settings') # Create root Application root = ApplicationRoot(config_file, loop) provide_utility(root, IApplication, 'root') # Initialize global (threadlocal) ZCA configuration config = root.config = ConfigurationMachine() import guillotina import guillotina.db.factory import guillotina.db.writer import guillotina.db.db configure.scan('guillotina.renderers') configure.scan('guillotina.api') configure.scan('guillotina.content') configure.scan('guillotina.registry') configure.scan('guillotina.auth') configure.scan('guillotina.json') configure.scan('guillotina.behaviors') configure.scan('guillotina.languages') configure.scan('guillotina.permissions') configure.scan('guillotina.security.security_local') configure.scan('guillotina.security.policy') configure.scan('guillotina.auth.participation') configure.scan('guillotina.catalog.index') configure.scan('guillotina.catalog.catalog') configure.scan('guillotina.files') configure.scan('guillotina.annotations') configure.scan('guillotina.constraintypes') configure.scan('guillotina.subscribers') configure.scan('guillotina.db.strategies') configure.scan('guillotina.db.cache') configure.scan('guillotina.exc_resp') configure.scan('guillotina.fields') load_application(guillotina, root, settings) config.execute_actions() config.commit() configured = ['guillotina'] for module_name in settings.get('applications') or []: configure_application(module_name, config, root, settings, configured) apply_concrete_behaviors() # update *after* plugins loaded update_app_settings(settings) if 'logging' in app_settings: logging.config.dictConfig(app_settings['logging']) # Make and initialize aiohttp app if server_app is None: server_app = make_aiohttp_application() root.app = server_app server_app.root = root server_app.config = config optimize_settings(app_settings) await notify(ApplicationConfiguredEvent(server_app, loop)) for key, dbconfig in list_or_dict_items(app_settings['databases']): factory = get_utility(IDatabaseConfigurationFactory, name=dbconfig['storage']) root[key] = await factory(key, dbconfig, loop) await notify(DatabaseInitializedEvent(root[key])) for key, file_path in list_or_dict_items(app_settings['static']): path = resolve_path(file_path).resolve() if not path.exists(): raise Exception('Invalid static directory {}'.format(file_path)) if path.is_dir(): root[key] = StaticDirectory(path) else: root[key] = StaticFile(path) for key, file_path in list_or_dict_items(app_settings['jsapps']): path = resolve_path(file_path).resolve() if not path.exists() or not path.is_dir(): raise Exception('Invalid jsapps directory {}'.format(file_path)) root[key] = JavaScriptApplication(path) root.set_root_user(app_settings['root_user']) if RSA is not None and not app_settings.get('rsa'): key = RSA.generate(2048) pub_jwk = {'k': key.publickey().exportKey('PEM')} priv_jwk = {'k': key.exportKey('PEM')} app_settings['rsa'] = {'pub': pub_jwk, 'priv': priv_jwk} # Set router root server_app.router.set_root(root) server_app.on_cleanup.append(cleanup_app) for util in app_settings.get('utilities') or []: logger.warn('Adding : ' + util['provides']) root.add_async_utility(util['provides'], util, loop=loop) for key, util in app_settings['load_utilities'].items(): logger.info('Adding ' + key + ' : ' + util['provides']) root.add_async_utility(key, util, loop=loop) # Load cached Schemas load_cached_schema() await notify(ApplicationInitializedEvent(server_app, loop)) return server_app
async def get_json(self): if not app_settings.get('store_json', False): return {} adapter = query_adapter(self._obj, IJSONDBSerializer) if adapter is not None: return await adapter()
async def make_app(config_file=None, settings=None, loop=None, server_app=None): """ Make application from configuration :param config_file: path to configuration file to load :param settings: dictionary of settings :param loop: if not using with default event loop :param settings: provide your own aiohttp application """ # reset app_settings startup_vars = {} for key in app_settings.keys(): if key[0] == "_": startup_vars[key] = app_settings[key] app_settings.clear() app_settings.update(startup_vars) app_settings.update(deepcopy(default_settings)) if loop is None: loop = asyncio.get_event_loop() if config_file is not None: with open(config_file, "r") as config: settings = json.load(config) elif settings is None: raise Exception("Neither configuration or settings") # Create root Application root = ApplicationRoot(config_file, loop) provide_utility(root, IApplication, "root") # Initialize global (threadlocal) ZCA configuration config = root.config = ConfigurationMachine() app_configurator = ApplicationConfigurator( settings.get("applications") or [], config, root, settings) configure.scan("guillotina.renderers") configure.scan("guillotina.api") configure.scan("guillotina.content") configure.scan("guillotina.registry") configure.scan("guillotina.auth") configure.scan("guillotina.json") configure.scan("guillotina.behaviors") configure.scan("guillotina.languages") configure.scan("guillotina.permissions") configure.scan("guillotina.security.security_local") configure.scan("guillotina.security.policy") configure.scan("guillotina.catalog.index") configure.scan("guillotina.catalog.catalog") configure.scan("guillotina.files") configure.scan("guillotina.annotations") configure.scan("guillotina.constraintypes") configure.scan("guillotina.subscribers") configure.scan("guillotina.db.strategies") configure.scan("guillotina.db.storages.vacuum") configure.scan("guillotina.db.cache") configure.scan("guillotina.db.writer") configure.scan("guillotina.db.factory") configure.scan("guillotina.exc_resp") configure.scan("guillotina.fields") configure.scan("guillotina.migrations") # always load guillotina app_configurator.configure_application("guillotina") app_configurator.configure_all_applications() apply_concrete_behaviors() # update *after* plugins loaded update_app_settings(settings) if "logging" in app_settings: try: logging.config.dictConfig(app_settings["logging"]) except Exception: app_logger.error("Could not setup logging configuration", exc_info=True) # Make and initialize aiohttp app if server_app is None: server_app = make_aiohttp_application() root.app = server_app server_app.root = root server_app.config = config for k, v in _moved.items(): # for b/w compatibility, convert these if k in app_settings: app_settings[v] = app_settings[k] del app_settings[k] optimize_settings(app_settings) await notify(ApplicationConfiguredEvent(server_app, loop)) for key, dbconfig in list_or_dict_items(app_settings["databases"]): factory = get_utility(IDatabaseConfigurationFactory, name=dbconfig["storage"]) root[key] = await factory(key, dbconfig, loop) await notify(DatabaseInitializedEvent(root[key])) for key, file_path in list_or_dict_items(app_settings["static"]): path = resolve_path(file_path).resolve() if not path.exists(): raise Exception("Invalid static directory {}".format(file_path)) if path.is_dir(): root[key] = StaticDirectory(path) else: root[key] = StaticFile(path) for key, file_path in list_or_dict_items(app_settings["jsapps"]): path = resolve_path(file_path).resolve() if not path.exists() or not path.is_dir(): raise Exception("Invalid jsapps directory {}".format(file_path)) root[key] = JavaScriptApplication(path) root.set_root_user(app_settings["root_user"]) if app_settings.get("jwk") and app_settings.get("jwk").get( "k") and app_settings.get("jwk").get("kty"): key = jwk.JWK.from_json(json.dumps(app_settings.get("jwk"))) app_settings["jwk"] = key # {"k":"QqzzWH1tYqQO48IDvW7VH7gvJz89Ita7G6APhV-uLMo","kty":"oct"} if not app_settings.get("debug") and app_settings["jwt"].get("secret"): # validate secret secret = app_settings["jwt"]["secret"] if secret == "secret": app_logger.warning( "You are using a very insecure secret key in production mode. " "It is strongly advised that you provide a better value for " "`jwt.secret` in your config.") elif not secure_passphrase(app_settings["jwt"]["secret"]): app_logger.warning( "You are using a insecure secret key in production mode. " "It is recommended that you provide a more complex value for " "`jwt.secret` in your config.") # Set router root server_app.router.set_root(root) server_app.on_cleanup.append(cleanup_app) for key, util in app_settings["load_utilities"].items(): app_logger.info("Adding " + key + " : " + util["provides"]) await notify(BeforeAsyncUtilityLoadedEvent(key, util)) result = root.add_async_utility(key, util, loop=loop) if result is not None: await notify(AfterAsyncUtilityLoadedEvent(key, util, *result)) # Load cached Schemas load_cached_schema() await notify(ApplicationInitializedEvent(server_app, loop)) return server_app
async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]: """Main function to resolve a request.""" security = get_adapter(request, IInteraction) if request.method not in app_settings['http_methods']: raise HTTPMethodNotAllowed( method=request.method, allowed_methods=[k for k in app_settings['http_methods'].keys()]) method = app_settings['http_methods'][request.method] try: resource, tail = await self.traverse(request) except ConflictError: # can also happen from connection errors so we bubble this... raise except Exception as _exc: logger.error('Unhandled exception occurred', exc_info=True) request.resource = request.tail = None request.exc = _exc data = { 'success': False, 'exception_message': str(_exc), 'exception_type': getattr(type(_exc), '__name__', str(type(_exc))), # noqa } if app_settings.get('debug'): data['traceback'] = traceback.format_exc() raise HTTPBadRequest(content={ 'reason': data }) request.record('traversed') await notify(ObjectLoadedEvent(resource)) request.resource = resource request.tail = tail if request.resource is None: await notify(TraversalResourceMissEvent(request, tail)) raise HTTPNotFound(content={ "reason": 'Resource not found' }) if tail and len(tail) > 0: # convert match lookups view_name = routes.path_to_view_name(tail) elif not tail: view_name = '' request.record('beforeauthentication') await self.apply_authorization(request) request.record('authentication') for language in get_acceptable_languages(request): translator = query_adapter((resource, request), ILanguage, name=language) if translator is not None: resource = translator.translate() break # Add anonymous participation if len(security.participations) == 0: security.add(AnonymousParticipation(request)) # container registry lookup try: view = query_multi_adapter( (resource, request), method, name=view_name) except AttributeError: view = None if view is None and method == IOPTIONS: view = DefaultOPTIONS(resource, request) # Check security on context to AccessContent unless # is view allows explicit or its OPTIONS permission = get_utility(IPermission, name='guillotina.AccessContent') if not security.check_permission(permission.id, resource): # Check if its a CORS call: if IOPTIONS != method: # Check if the view has permissions explicit if view is None or not view.__allow_access__: logger.info( "No access content {content} with {auths}".format( content=resource, auths=str([x.principal.id for x in security.participations])), request=request) raise HTTPUnauthorized( content={ "reason": "You are not authorized to access content", "content": str(resource), "auths": [x.principal.id for x in security.participations] } ) if not view and len(tail) > 0: # we should have a view in this case because we are matching routes await notify(TraversalViewMissEvent(request, tail)) return None request.found_view = view request.view_name = view_name request.record('viewfound') ViewClass = view.__class__ view_permission = get_view_permission(ViewClass) if not security.check_permission(view_permission, view): if IOPTIONS != method: raise HTTPUnauthorized( content={ "reason": "You are not authorized to view", "content": str(resource), "auths": [x.principal.id for x in security.participations] } ) try: view.__route__.matches(request, tail or []) except (KeyError, IndexError): await notify(TraversalRouteMissEvent(request, tail)) return None except AttributeError: pass if hasattr(view, 'prepare'): view = (await view.prepare()) or view request.record('authorization') return MatchInfo(resource, request, view)