async def create_app(): app = web.Application() app.on_startup.append(on_startup) aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates')) aiojobs_setup(app) app.add_routes([web.static('/static', 'static')]) app.router.add_get('/hello', hello_handler) # app.router.add_post('/cow', job_handler) app.add_routes([web.get('/ws', ws_handler)]) app.add_routes(routes) return app
async def create_app(): """ Create web application and manage connection to redis :return: instance of application """ app = web.Application() jinja_env = aiohttp_jinja2.setup( app, loader=jinja2.FileSystemLoader('templates')) for route in routes: app.router.add_route(**route) startup_tasks = [startup] app.on_startup.extend(startup_tasks) app.on_cleanup.append(cleanup) aiojobs_setup(app) return app
async def test_atomic(test_client): @atomic async def handler(request): await asyncio.sleep(0) return web.Response() app = web.Application() app.router.add_get('/', handler) aiojobs_setup(app) client = await test_client(app) resp = await client.get('/') assert resp.status == 200 scheduler = get_scheduler_from_app(app) assert scheduler.active_count == 0 assert scheduler.pending_count == 0
async def test_nested_application(test_client): app = web.Application() aiojobs_setup(app) app2 = web.Application() class MyView(web.View): async def get(self): assert get_scheduler_from_request(self.request) ==\ get_scheduler_from_app(app) return web.Response() app2.router.add_route("*", "/", MyView) app.add_subapp("/sub/", app2) client = await test_client(app) resp = await client.get("/sub/") assert resp.status == 200
async def test_atomic_from_view(test_client): app = web.Application() class MyView(web.View): @atomic async def get(self): return web.Response() app.router.add_route("*", "/", MyView) aiojobs_setup(app) client = await test_client(app) resp = await client.get('/') assert resp.status == 200 scheduler = get_scheduler_from_app(app) assert scheduler.active_count == 0 assert scheduler.pending_count == 0
async def test_plugin(test_client): job = None async def coro(): await asyncio.sleep(10) async def handler(request): nonlocal job job = await spawn(request, coro()) assert not job.closed return web.Response() app = web.Application() app.router.add_get('/', handler) aiojobs_setup(app) client = await test_client(app) resp = await client.get('/') assert resp.status == 200 assert job.active await client.close() assert job.closed
def setup_postschema(app, appname: str, *, plugin_config={}, extra_config={}, after_create=[], **app_config): roles = app_config.get('roles', []) ROLES = frozenset(role.title() for role in DEFAULT_ROLES | set(roles)) os.environ['ROLES'] = dumps(ROLES) app_config = AppConfig(**app_config) app_config.initial_logging_context['version'] = app_config.version app_config.initial_logging_context['app_mode'] = app_config.app_mode = os.environ.get('APP_MODE') plugin_config = PluginConfig(**plugin_config) url_prefix = app_config.url_prefix if url_prefix and not url_prefix.startswith('/'): url_prefix = '/' + url_prefix if url_prefix.endswith('/'): url_prefix = url_prefix[:-1] app.app_name = appname app.url_prefix = url_prefix app.app_mode = app_config.app_mode app.app_description = app_config.description app.version = app_config.version app.queries = { os.path.split(filename)[1].rsplit('.', 1)[0]: open(filename).read().strip() for filename in glob(str(Q_PATTERN)) } # create loggers info_logger, error_logger, access_logger = setup_logging( app_config.info_logger_processors, app_config.error_logger_processors, app_config.default_logging_level) from . import middlewares from .actor import PrincipalActor from .core import Base from .provision_db import setup_db from .scope import ScopeBase from .workspace import Workspace # noqa ScopeBase._validate_roles(ROLES) # setup middlewares app.middlewares.append(middlewares.postschema_middleware) app.info_logger = info_logger.new(**app_config.initial_logging_context) app.error_logger = error_logger.new(**app_config.initial_logging_context) app.access_logger = access_logger.new(**app_config.initial_logging_context) aiojobs_setup(app, exception_handler=exception_handler(app.error_logger)) aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader( [AUTH_TEMPLATES_DIR, *app_config.template_dirs] )) if not app_config.redirect_reset_password_to: app_config.redirect_reset_password_to = redirect_reset_password_to = '/passform/{checkcode}/' app.add_routes( [aiohttp.web.get(redirect_reset_password_to, pass_reset_checkcode_template)] ) else: app.add_routes( [aiohttp.web.get(app_config.redirect_reset_password_to, pass_reset_checkcode_raw)] ) if not app_config.password_reset_form_link: app_config.password_reset_form_link = '{scheme}passform/{checkcode}/' app.on_startup.extend([startup, init_resources]) app.on_cleanup.append(cleanup) if app_config.alembic_dest is None: stack = inspect.stack() stack_frame = stack[1] calling_module_path = Path(inspect.getmodule(stack_frame[0]).__file__).parent os.environ.setdefault('POSTCHEMA_INSTANCE_PATH', str(calling_module_path)) else: alembic_destination = str(app_config.alembic_dest) assert os.path.exists(alembic_destination),\ "`alembic_dest` argument doesn't point to an existing directory" os.environ.setdefault('POSTCHEMA_INSTANCE_PATH', alembic_destination) app_config.activation_email_html = jinja2.Template(app_config.activation_email_html) app_config.invitation_email_html = jinja2.Template(app_config.invitation_email_html) app_config.reset_pass_email_html = jinja2.Template(app_config.reset_pass_email_html) app_config.verification_email_html = jinja2.Template(app_config.verification_email_html) config = ConfigBearer(**extra_config, **plugin_config.__dict__) # extend with immutable config opts app_config._update(ImmutableConfig(scopes=ScopeBase._scopes)) config.update(app_config.__dict__) app.config = config app.scopes = frozenset(ScopeBase._scopes) app.allowed_roles = frozenset([role for role in ROLES if role not in ['Admin', '*', 'Owner']]) app.principal_actor_schema = PrincipalActor app.schemas = registered_schemas app.config.roles = ROLES app.send_sms = app_config.send_sms or default_send_sms app.invitation_link = app_config.invitation_link app.created_email_confirmation_link = app_config.created_email_confirmation_link.format( url_prefix=url_prefix) app.invited_email_confirmation_link = app_config.invited_email_confirmation_link.format( url_prefix=url_prefix) # build the views router, openapi_spec = build_app(app, registered_schemas) # hash the spec app.spec_hash = md5(dumps(openapi_spec).encode()).hexdigest() # map paths to roles app.paths_by_roles = PathReturner(openapi_spec, router) # parse plugins installed_plugins = {} for plugin in app_config.plugins: print(f"* Installing plugin {plugin}...") assert plugin in ['shield', 'sentry'], f'Plugin `{plugin}` is not recognized' installed_plugins[plugin] = plugin_module = import_module(f'.{plugin}', 'postschema') with suppress(AttributeError, TypeError): plugin_module.install(app) app.installed_plugins = installed_plugins.keys() @auth(roles=['Admin']) @aiohttp_jinja2.template('redoc.html') async def apidoc(request): return {'appname': request.app.app_name} @auth(roles=['Admin']) async def apispec_context(request): return json_response(openapi_spec) @auth(roles=['*'], email_verified=False) async def actor_apispec(request): '''OpenAPI JSON spec filtered to include only the public and requester-specific routes. ''' request.app.paths_by_roles.roles = set(request.session.roles) return json_response(request.app.paths_by_roles.paths_by_roles) try: app.info_logger.debug("Provisioning DB...") setup_db(Base, after_create) app.info_logger.debug("DB provisioning done") except Exception: app.error_logger.exception("Provisioning failed", exc_info=True) raise router.add_get(f'{url_prefix}/doc/', apidoc) router.add_get(f'{url_prefix}/doc/openapi.yaml', apispec_context) router.add_get(f'{url_prefix}/doc/spec.json', actor_apispec) router.add_get(f'{url_prefix}/doc/meta/', apispec_metainfo)