spiff-arena/src/spiffworkflow_backend/__init__.py

158 lines
5.2 KiB
Python
Raw Normal View History

"""__init__."""
import os
from typing import Any
import connexion # type: ignore
import flask.app
import flask.json
import sqlalchemy
from apscheduler.schedulers.background import BackgroundScheduler # type: ignore
from flask.json.provider import DefaultJSONProvider
from flask_bpmn.api.api_error import api_error_blueprint
from flask_bpmn.models.db import db
from flask_bpmn.models.db import migrate
from flask_cors import CORS # type: ignore
from flask_mail import Mail # type: ignore
import spiffworkflow_backend.load_database_models # noqa: F401
from spiffworkflow_backend.config import setup_config
from spiffworkflow_backend.routes.admin_blueprint.admin_blueprint import admin_blueprint
from spiffworkflow_backend.routes.process_api_blueprint import process_api_blueprint
from spiffworkflow_backend.routes.user_blueprint import user_blueprint
from spiffworkflow_backend.services.background_processing_service import (
BackgroundProcessingService,
)
class MyJSONEncoder(DefaultJSONProvider):
"""MyJSONEncoder."""
def default(self, obj: Any) -> Any:
"""Default."""
if hasattr(obj, "serialized"):
return obj.serialized
elif isinstance(obj, sqlalchemy.engine.row.Row): # type: ignore
return_dict = {}
for row_key in obj.keys():
row_value = obj[row_key]
if hasattr(row_value, "__dict__"):
return_dict.update(row_value.__dict__)
else:
return_dict.update({row_key: row_value})
return_dict.pop("_sa_instance_state")
return return_dict
return super().default(obj)
def dumps(self, obj: Any, **kwargs: Any) -> Any:
"""Dumps."""
kwargs.setdefault("default", self.default)
return super().dumps(obj, **kwargs)
def start_scheduler(app: flask.app.Flask) -> None:
"""Start_scheduler."""
scheduler = BackgroundScheduler()
scheduler.add_job(
BackgroundProcessingService(app).process_message_instances_with_app_context,
"interval",
seconds=10,
)
scheduler.add_job(
BackgroundProcessingService(app).run,
"interval",
seconds=30,
)
scheduler.start()
def create_app() -> flask.app.Flask:
"""Create_app."""
# We need to create the sqlite database in a known location.
# If we rely on the app.instance_path without setting an environment
# variable, it will be one thing when we run flask db upgrade in the
# noxfile and another thing when the tests actually run.
# instance_path is described more at https://flask.palletsprojects.com/en/2.1.x/config/
connexion_app = connexion.FlaskApp(
__name__, server_args={"instance_path": os.environ.get("FLASK_INSTANCE_PATH")}
)
app = connexion_app.app
app.config["CONNEXION_APP"] = connexion_app
app.config["SESSION_TYPE"] = "filesystem"
if os.environ.get("FLASK_SESSION_SECRET_KEY") is None:
raise KeyError(
"Cannot find the secret_key from the environment. Please set FLASK_SESSION_SECRET_KEY"
)
app.secret_key = os.environ.get("FLASK_SESSION_SECRET_KEY")
setup_config(app)
db.init_app(app)
migrate.init_app(app, db)
app.register_blueprint(user_blueprint)
app.register_blueprint(process_api_blueprint)
app.register_blueprint(api_error_blueprint)
app.register_blueprint(admin_blueprint, url_prefix="/admin")
origins_re = [
r"^https?:\/\/%s(.*)" % o.replace(".", r"\.")
for o in app.config["CORS_ALLOW_ORIGINS"]
]
CORS(app, origins=origins_re)
connexion_app.add_api("api.yml", base_path="/v1.0")
mail = Mail(app)
app.config["MAIL_APP"] = mail
app.json = MyJSONEncoder(app)
if app.config["PROCESS_WAITING_MESSAGES"]:
start_scheduler(app)
configure_sentry(app)
return app # type: ignore
Squashed 'spiffworkflow-backend/' changes from 03bf7a61..10c443a2 10c443a2 Merge pull request #130 from sartography/feature/data 71c803aa allow passing in the log level into the app w/ burnettk daeb82d9 Merge pull request #126 from sartography/dependabot/pip/typing-extensions-4.4.0 14c8f52c Merge pull request #123 from sartography/dependabot/pip/dot-github/workflows/poetry-1.2.2 92d204e6 Merge remote-tracking branch 'origin/main' into feature/data 1cb77901 run the save all bpmn script on server boot w/ burnettk 16a6f476 Bump typing-extensions from 4.3.0 to 4.4.0 d8ac61fc Bump poetry from 1.2.1 to 1.2.2 in /.github/workflows 3be27786 Merge pull request #131 from sartography/feature/permissions2 1fd8fc78 Merge remote-tracking branch 'origin/main' into feature/permissions2 d29621ae data setup on app boot 0b21a5d4 refactor bin/save_all_bpmn.py into service code 02fb9d61 lint c95db461 refactor scripts 98628fc2 This caused a problem with scopes when token timed out. d8b2323b merged in main and resolved conflicts d01b4fc7 updated sentry-sdk to resolve deprecation warnings 5851ddf5 update for mypy in python 3.9 508f9900 merged in main and resolved conflicts 68d69978 precommit w/ burnettk 85a4ee16 removed debug print statements w/ burnettk 93eb91f4 added keycloak configs and user perms for staging w/ burnettk e4ded8fc added method to import permissions from yml file w/ burnettk 22ba89ae use percents instead of asterisks to better support db syntax w/ burnettk 0c116ae8 postgres does not use backticks w/ burnettk 621ad3ef attempting to see if sql like statement works in other dbs as well w/ burnettk git-subtree-dir: spiffworkflow-backend git-subtree-split: 10c443a2d82752e8ed9d1679afe6409d81029006
2022-10-12 19:28:52 +00:00
def get_hacked_up_app_for_script() -> flask.app.Flask:
"""Get_hacked_up_app_for_script."""
os.environ["SPIFFWORKFLOW_BACKEND_ENV"] = "development"
flask_env_key = "FLASK_SESSION_SECRET_KEY"
os.environ[flask_env_key] = "whatevs"
if "BPMN_SPEC_ABSOLUTE_DIR" not in os.environ:
home = os.environ["HOME"]
full_process_model_path = (
f"{home}/projects/github/sartography/sample-process-models"
)
if os.path.isdir(full_process_model_path):
os.environ["BPMN_SPEC_ABSOLUTE_DIR"] = full_process_model_path
else:
raise Exception(f"Could not find {full_process_model_path}")
app = create_app()
return app
def configure_sentry(app: flask.app.Flask) -> None:
"""Configure_sentry."""
import sentry_sdk
from flask import Flask
from sentry_sdk.integrations.flask import FlaskIntegration
sentry_sample_rate = app.config.get("SENTRY_SAMPLE_RATE")
if sentry_sample_rate is None:
return
sentry_sdk.init(
dsn=app.config.get("SENTRY_DSN"),
integrations=[
FlaskIntegration(),
],
# Set traces_sample_rate to 1.0 to capture 100%
# of transactions for performance monitoring.
# We recommend adjusting this value in production.
traces_sample_rate=float(sentry_sample_rate),
)
app = Flask(__name__)