#!/usr/bin/env python import logging import sys from contextlib import asynccontextmanager try: import coloredlogs # type: ignore except ImportError: pass else: coloredlogs.install() from fastapi import FastAPI, responses from fastapi.staticfiles import StaticFiles from treetrail.config import conf, get_cache_dir, create_dirs from treetrail.plantekey import setup as setup_plantekey, pek_app from treetrail.api_v1 import api_app from treetrail.tiles import tiles_app, registry as tiles_registry from treetrail.attachments import attachment_app from treetrail.database import create_db from treetrail.utils import mkdir @asynccontextmanager async def lifespan(app: FastAPI): create_dirs() setup_plantekey(app) await create_db() await tiles_registry.setup(app) yield await tiles_registry.shutdown(app) app = FastAPI( title=conf.app.title, lifespan=lifespan, version=conf.version, default_response_class=responses.ORJSONResponse, ) api_app.mount('/plantekey', pek_app) app.mount(f'{conf.base_href}/v1', api_app) app.mount(f'{conf.base_href}/tiles', tiles_app) app.mount(f'{conf.base_href}/attachment', attachment_app) app.mount( f'{conf.base_href}/static/cache', StaticFiles(directory=mkdir(get_cache_dir())), name='static_generated' ) def _main(argv=None): from argparse import ArgumentParser arg_parser = ArgumentParser( description="fastapi Application server", prog="fastapi" ) arg_parser.add_argument( '--path', help='Path of socket file', ) arg_parser.add_argument( "-H", "--hostname", help="TCP/IP hostname to serve on (default: %(default)r)", default="localhost" ) arg_parser.add_argument( "-P", "--port", help="TCP/IP port to serve on", type=int, ) arg_parser.add_argument( "-c", "--create-db", help="Create tables in database", action="store_true" ) arg_parser.add_argument( "--username", help="Create or update a user in database", type=str, ) arg_parser.add_argument( "--add-role", help="Add the role", type=str, ) arg_parser.add_argument( "--add-user-role", help="Add the role to the user", type=str, ) arg_parser.add_argument( "--password", help="Set the password for a user in database", type=str, ) arg_parser.add_argument( "--full-name", help="Set the full name for a user in database", type=str, ) arg_parser.add_argument( "--email", help="Set the email for a user in database", type=str, ) arg_parser.add_argument( "--enable", help="Enable user", action="store_true" ) arg_parser.add_argument( "--disable", help="Disable user", action="store_true" ) arg_parser.add_argument( "--delete-user", help="Delete user", action="store_true" ) arg_parser.add_argument( "--import-trees", help="Import trees (eg. gpkg file). Images can be imported.", type=str, ) arg_parser.add_argument( "--layers", help="Layers to import.", nargs='*', type=str, ) arg_parser.add_argument( "--import-zones", help="Import zones (eg. gpkg file).", type=str, ) arg_parser.add_argument( "--import-plantekey-trees-to-trail", help="Import trees from plantekey web site. Provide the trail id.", type=str, ) arg_parser.add_argument( "--import-plantekey-plants", help="Import plants from plantekey web site", action="store_true" ) arg_parser.add_argument( "--list-layers", help="List layers in the geodata file", type=str, ) arg_parser.add_argument( "-d", "--debug", '-d', help="Set debug logging", action="store_true" ) args = arg_parser.parse_args() if args.debug: logging.root.setLevel(logging.DEBUG) ## For ipdb: logging.getLogger('parso').setLevel(logging.WARNING) if args.create_db: from treetrail.database import create_db import asyncio asyncio.run(create_db()) sys.exit(0) if args.enable: from treetrail.security import enable_user import asyncio asyncio.run(enable_user(args.username)) sys.exit(0) if args.disable: from treetrail.security import enable_user import asyncio asyncio.run(enable_user(args.username, False)) sys.exit(0) if args.add_role: from treetrail.security import add_role import asyncio asyncio.run(add_role(args.add_role)) sys.exit(0) if args.add_user_role: from treetrail.security import add_user_role import asyncio if not args.username: print('Please provide username') sys.exit(1) asyncio.run(add_user_role(args.username, args.add_user_role)) sys.exit(0) if args.delete_user: from treetrail.security import delete_user import asyncio asyncio.run(delete_user(args.username)) sys.exit(0) if args.list_layers: from treetrail.import_cli import list_layers list_layers(args.list_layers) sys.exit(0) if args.import_trees: from treetrail.import_cli import import_trees import_trees(args) sys.exit(0) if args.import_zones: from treetrail.import_cli import import_zones import_zones(args) sys.exit(0) if args.import_plantekey_plants: from treetrail.import_cli import import_plantekey_plants import asyncio asyncio.run(import_plantekey_plants(args)) sys.exit(0) if args.import_plantekey_trees_to_trail: from treetrail.import_cli import import_plantekey_trees import_plantekey_trees(args) sys.exit(0) if args.username: from treetrail.security import create_user import asyncio asyncio.run(create_user(**vars(args))) sys.exit(0) print( 'This application needs to be run with an asgi server like uvicorn.', 'For example:', 'uvicorn application:app', 'or:', 'uvicorn application:app --port 5002', 'or (for development):', 'uvicorn --reload application:app --uds /var/run/treetrail.socket', 'or (for production):', 'uvicorn --loop uvloop application:app --port 5002', sep='\n' ) if __name__ == '__main__': _main()