def app_factory(api_name: str = "api", vocab_route: str = "vocab") -> Flask:
    """
    Create an app object
    :param api_name : Name of the api
    :param vocab_route : The route at which the vocab of the apidoc is present
    :return : API with all routes directed at /[api_name].
    """
    from flask import redirect, request
    import uuid
    from flask_cors import CORS
    from flask_restful import Api
    from hydrus.resources import (
        Index,
        Vocab,
        Contexts,
        Entrypoint,
        ItemCollection,
        Item,
    )

    app = Flask(__name__)
    app.config["SECRET_KEY"] = "secret key"
    CORS(app)
    app.url_map.strict_slashes = False
    api = Api(app)

    # Redirecting root_path to root_path/api_name
    if api_name:

        @app.route("/")
        def root_url():
            return redirect(f"/{api_name}/")

    api.add_resource(Index, f"/{api_name}/", endpoint="api")
    api.add_resource(Vocab, f"/{api_name}/{vocab_route}", endpoint="vocab")
    api.add_resource(
        Contexts, f"/{api_name}/contexts/<string:category>.jsonld", endpoint="contexts"
    )
    api.add_resource(
        Entrypoint,
        f"/{api_name}/contexts/EntryPoint.jsonld",
        endpoint="main_entrypoint",
    )
    api.add_resource(
        ItemCollection, f"/{api_name}/<string:path>", endpoint="item_collection"
    )
    api.add_resource(Item, f"/{api_name}/<string:path>/<uuid:id_>", endpoint="item")

    return app HYDRUS_SERVER_URL = f"http://localhost:{PORT}/" API_NAME = os.environ["API_NAME"] if "API_NAME" in dict(os.environ).keys() else "api" DB_URL = (
    os.environ["DB_URL"]
    if "DB_URL" in dict(os.environ).keys()
    else "sqlite:///database.db"
) APIDOC_OBJ = load_apidoc(path) PORT = int(os.environ["PORT"]) if "PORT" in dict(os.environ).keys() else 8080 DEBUG = bool(os.environ["DEBUG"]) def get_classes(apidoc: HydraDoc) -> List[Dict[str, Any]]:
def get_all_properties(classes: List[Dict[str, Any]]) -> Set[str]:
    COLLECTION_ID = "http://www.w3.org/ns/hydra/core#Collection"
    RESOURCE_ID = "http://www.w3.org/ns/hydra/core#Resource"
    ENTRYPOINT_ID = apidoc.entrypoint.entrypoint.id_ EXPIRY_TIME = 2700  # unit: seconds
def _set_sqlite_pragma(dbapi_connection, connection_record):
    def __init__(self, resource):
    def name(self):
    def resource(self):
    def supported_properties(self):
    def get_attr_dict(self):
    def foreign_key_column(foreign_table_name, title):
    def make_db_table(self):
    def is_valid(self):
def create_database_tables(classes):
class Resource:
class Modification(Base):
class User(Base):
class Token(Base):
class Nonce(Base): class UserExists(Exception):
    """Error when the User already exitst."""

    def __init__(self, id_: int) -> None:
        """Constructor."""
        self.id_ = id_

    def get_HTTP(self) -> HydraError:
        """Return the HTTP response for the Exception."""
        description = f"The user with ID {self.id_} already exists"
        return HydraError(code=400, title="User already exists.", desc=description) def add_user(id_: int, paraphrase: str, session: Session) -> None:
    """Add new users to the database.

    Raises:
        UserExits: If a user with `id_` already exists.

    """
    if session.query(exists().where(User.id == id_)).scalar():
        raise UserExists(id_=id_)
    else:
        new_user = User(
            id=id_, paraphrase=sha224(paraphrase.encode("utf-8")).hexdigest()
        )
        session.add(new_user)
        session.commit() @contextmanager
def set_session(application: Flask, DB_SESSION: scoped_session) -> Iterator:
    """
    Set the Database Session for the app before it is run in main.py.
    :param application: Flask app object
            <flask.app.Flask>
    :param DB_SESSION: SQLalchemy Session object
            <sqlalchemy.orm.session.Session>

    Raises:
        TypeError: If `DB_SESSION` is not an instance of `scoped_session` or `Session`.

    """
    if not isinstance(DB_SESSION, scoped_session) and not isinstance(
        DB_SESSION, Session
    ):
        raise TypeError(
            "The API Doc is not of type <sqlalchemy.orm.session.Session> or"
            " <sqlalchemy.orm.scoping.scoped_session>"
        )

    def handler(sender: Flask, **kwargs: Any) -> None:
        g.dbsession = DB_SESSION

    with appcontext_pushed.connected_to(handler, application):
        yield @contextmanager
def set_doc(application: Flask, APIDOC: HydraDoc) -> Iterator:
    """
    Set the API Documentation for the app (before it is run in main.py).
    :param application: Flask app object
            <flask.app.Flask>
    :param APIDOC : Hydra Documentation object
            <hydra_python_core.doc_writer.HydraDoc>

    Raises:
        TypeError: If `APIDOC` is not an instance of `HydraDoc`.

    """
    if not isinstance(APIDOC, HydraDoc):
        raise TypeError(
            "The API Doc is not of type <hydra_python_core.doc_writer.HydraDoc>"
        )

    def handler(sender: Flask, **kwargs: Any) -> None:
        g.doc = APIDOC

    with appcontext_pushed.connected_to(handler, application):
        yield @contextmanager
def set_hydrus_server_url(application: Flask, server_url: str) -> Iterator:
    """
    Set the server URL for the app (before it is run in main.py).
    :param application: Flask app object
            <flask.app.Flask>
    :param server_url : Server URL
            <str>

    Raises:
        TypeError: If the `server_url` is not a string.

    """
    if not isinstance(server_url, str):
        raise TypeError("The server_url is not of type <str>")

    def handler(sender: Flask, **kwargs: Any) -> None:
        g.hydrus_server_url = server_url

    with appcontext_pushed.connected_to(handler, application):
        yield @contextmanager
def set_token(application: Flask, token: bool) -> Iterator:
    """Set whether API needs to implement token based authentication.

    Raises:
        TypeError: If `token` is not a boolean value.

    """
    if not isinstance(token, bool):
        raise TypeError("Token flag must be of type <bool>")

    def handler(sender: Flask, **kwargs: Any) -> None:
        g.token_ = token

    with appcontext_pushed.connected_to(handler, application):
        yield @contextmanager
def set_api_name(application: Flask, api_name: str) -> Iterator:
    """
    Set the server name or EntryPoint for the app (before it is run in main.py).
    :param application: Flask app object
            <flask.app.Flask>
    :param api_name : API/Server name or EntryPoint
            <str>

    Raises:
        TypeError: If `api_name` is not a string.

    """
    if not isinstance(api_name, str):
        raise TypeError("The api_name is not of type <str>")

    def handler(sender: Flask, **kwargs: Any) -> None:
        g.api_name = api_name

    with appcontext_pushed.connected_to(handler, application):
        yield @contextmanager
def set_authentication(application: Flask, authentication: bool) -> Iterator:
    """
    Set the whether API needs to be authenticated or not (before it is run in main.py).

    :param application: Flask app object
            <flask.app.Flask>
    :param authentication : Bool. API Auth needed or not
            <bool>


    Raises:
        TypeError: If `authentication` is not a boolean value.

    """
    if not isinstance(authentication, bool):
        raise TypeError("Authentication flag must be of type <bool>")

    def handler(sender: Flask, **kwargs: Any) -> None:
        g.authentication_ = authentication

    with appcontext_pushed.connected_to(handler, application):
        yield def create_socket(app: Flask, session: scoped_session) -> SocketIO:
    socketio.init_app(app, logger=True)
    socketio.on_namespace(SyncNamespace(namespace='/sync', db_session=session))
    return socketio
import logging
from sqlalchemy import create_engine
from gevent.pywsgi import WSGIServer
from sqlalchemy.orm import sessionmaker
from hydrus.app_factory import app_factory
from hydrus.conf import HYDRUS_SERVER_URL, API_NAME, DB_URL, APIDOC_OBJ, PORT, DEBUG
from hydrus.data import doc_parse
from hydrus.data.db_models import Base, create_database_tables
from hydrus.data.exceptions import UserExists
from hydrus.data.user import add_user
from hydra_python_core import doc_maker
from hydrus.utils import (
    set_session,
    set_doc,
    set_hydrus_server_url,
    set_token,
    set_api_name,
    set_authentication,
)
from hydrus.extensions.socketio_factory import create_socket
"""Main route for the application"""





logger = logging.getLogger(__file__)

# TODO: loading the engine and creating the tables should be handled better
engine = create_engine(DB_URL)
session = sessionmaker(bind=engine)()

#
# Load ApiDoc with doc_maker
#
apidoc = doc_maker.create_doc(APIDOC_OBJ, HYDRUS_SERVER_URL, API_NAME)
classes = doc_parse.get_classes(apidoc)
try:
    Base.metadata.drop_all(engine)
    create_database_tables(classes)
    Base.metadata.create_all(engine)
except Exception:
    pass

AUTH = True
TOKEN = True

if AUTH:
    try:
        add_user(id_=1, paraphrase="test", session=session)
    except UserExists:
        pass

# Create a Hydrus app
app = app_factory(API_NAME)
socketio = create_socket(app, session)
#
# Nested context managers
#
# Use authentication for all requests
# Set the API Documentation
# Set HYDRUS_SERVER_URL
# Set the Database session
with set_authentication(app, AUTH), set_token(app, TOKEN), set_api_name(
    app, API_NAME
), set_doc(app, apidoc), set_hydrus_server_url(app, HYDRUS_SERVER_URL), set_session(
    app, session
):
    if __name__ == "__main__":
        # this is run only if development server is run
        # Set the name of the API

        socketio.run(app=app, debug=True, port=PORT)