diff --git a/api/helpers/db_helper.py b/api/helpers/db_helper.py index 69ab2e33..33ca3d46 100644 --- a/api/helpers/db_helper.py +++ b/api/helpers/db_helper.py @@ -20,7 +20,7 @@ def get_class_by_tablename(tablename): :param tablename: String with name of table. :return: Class reference or None. """ - for classObject in db.Model._decl_class_registry.values(): + for classObject in db.Model.registry._class_registry.values(): if ( hasattr(classObject, "__tablename__") and classObject.__tablename__ == tablename diff --git a/api/models/call_log.py b/api/models/call_log.py index b1a5ee0a..c7a9607d 100644 --- a/api/models/call_log.py +++ b/api/models/call_log.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class CallLogQuery(BaseQuery): diff --git a/api/models/contact_fields_mapping.py b/api/models/contact_fields_mapping.py index d588d46a..24d32744 100644 --- a/api/models/contact_fields_mapping.py +++ b/api/models/contact_fields_mapping.py @@ -1,5 +1,5 @@ from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery from utils.loggingutils import logger diff --git a/api/models/content.py b/api/models/content.py index 59aef5bf..5fd0f77f 100644 --- a/api/models/content.py +++ b/api/models/content.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class ContentQuery(BaseQuery): diff --git a/api/models/content_version.py b/api/models/content_version.py index 17f334b2..55c82112 100644 --- a/api/models/content_version.py +++ b/api/models/content_version.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class ContentVersionQuery(BaseQuery): diff --git a/api/models/ivr_prompt.py b/api/models/ivr_prompt.py index ef4de91a..a35831bd 100644 --- a/api/models/ivr_prompt.py +++ b/api/models/ivr_prompt.py @@ -1,7 +1,7 @@ from api.mixins import TimestampMixin from api import db from sqlalchemy import desc, and_, func -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class IvrPromptQuery(BaseQuery): diff --git a/api/models/ivr_prompt_mapping.py b/api/models/ivr_prompt_mapping.py index e5420778..a00af706 100644 --- a/api/models/ivr_prompt_mapping.py +++ b/api/models/ivr_prompt_mapping.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class IvrPromptMappingQuery(BaseQuery): diff --git a/api/models/ivr_prompt_response.py b/api/models/ivr_prompt_response.py index cf33b87d..9f66db6f 100644 --- a/api/models/ivr_prompt_response.py +++ b/api/models/ivr_prompt_response.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class IvrPromptResponseQuery(BaseQuery): diff --git a/api/models/language.py b/api/models/language.py index 1eb6ff6e..c73424ed 100644 --- a/api/models/language.py +++ b/api/models/language.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class LanguageQuery(BaseQuery): diff --git a/api/models/module_content.py b/api/models/module_content.py index 8df91327..2e975eaf 100644 --- a/api/models/module_content.py +++ b/api/models/module_content.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class ModuleContentQuery(BaseQuery): diff --git a/api/models/partner_system_phone.py b/api/models/partner_system_phone.py index 87005b15..40adbf42 100644 --- a/api/models/partner_system_phone.py +++ b/api/models/partner_system_phone.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class PartnerSystemPhoneQuery(BaseQuery): diff --git a/api/models/program_module.py b/api/models/program_module.py index 103be070..a9b7372a 100644 --- a/api/models/program_module.py +++ b/api/models/program_module.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class ProgramModuleQuery(BaseQuery): diff --git a/api/models/program_sequence.py b/api/models/program_sequence.py index 1913d560..b186bafc 100644 --- a/api/models/program_sequence.py +++ b/api/models/program_sequence.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class ProgramSequenceQuery(BaseQuery): diff --git a/api/models/registration.py b/api/models/registration.py index 2baf6083..37d9ff10 100644 --- a/api/models/registration.py +++ b/api/models/registration.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class RegistrationQuery(BaseQuery): diff --git a/api/models/system_phone.py b/api/models/system_phone.py index fdb5d783..d34da195 100644 --- a/api/models/system_phone.py +++ b/api/models/system_phone.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class SystemPhoneQuery(BaseQuery): diff --git a/api/models/user.py b/api/models/user.py index f28cd168..6f855a8d 100644 --- a/api/models/user.py +++ b/api/models/user.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class UserQuery(BaseQuery): diff --git a/api/models/user_custom_fields.py b/api/models/user_custom_fields.py index 633d0195..19087501 100644 --- a/api/models/user_custom_fields.py +++ b/api/models/user_custom_fields.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery from sqlalchemy import and_ diff --git a/api/models/user_group.py b/api/models/user_group.py index 4fbfa0ea..13c618e7 100644 --- a/api/models/user_group.py +++ b/api/models/user_group.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery from sqlalchemy import desc, and_ diff --git a/api/models/user_program.py b/api/models/user_program.py index d34b0a71..beac746f 100644 --- a/api/models/user_program.py +++ b/api/models/user_program.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db, app -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery from api.helpers import common_helper, db_helper from utils.loggingutils import logger diff --git a/api/models/webhook_transaction_log.py b/api/models/webhook_transaction_log.py index be7492ad..ec97d66b 100644 --- a/api/models/webhook_transaction_log.py +++ b/api/models/webhook_transaction_log.py @@ -1,6 +1,6 @@ from api.mixins import TimestampMixin from api import db -from flask_sqlalchemy import BaseQuery +from flask_sqlalchemy.query import Query as BaseQuery class WebhookTransactionLogQuery(BaseQuery): diff --git a/api/services/prompt_service.py b/api/services/prompt_service.py index 218f80d5..71a733e7 100644 --- a/api/services/prompt_service.py +++ b/api/services/prompt_service.py @@ -1,8 +1,9 @@ # This file is treated as service layer -from api import models, db +from api import db from datetime import datetime from api.helpers import prompt_helper, common_helper, db_helper from utils.loggingutils import logger +from api import models class PromptService: diff --git a/config.py b/config.py index 0c522952..92bbdc76 100644 --- a/config.py +++ b/config.py @@ -48,7 +48,6 @@ if github_action_db_url: SQLALCHEMY_DATABASE_URI = github_action_db_url -SQLALCHEMY_TRACK_MODIFICATIONS = True WTF_CSRF_ENABLED = True SECRET_KEY = os.environ.get("SECRET_KEY") diff --git a/main.py b/main.py index fbbb9daa..9ef50137 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,5 @@ -from api import services, models from flask import jsonify -from api.helpers import db_helper +from api import app, helpers, services, models from utils.loggingutils import logger import json @@ -8,30 +7,31 @@ ### Endpoint for Cloud function def webhook(request): - try: - if request.method == "POST": - try: - jsonData = request.get_json() - except Exception as e: - logger.warning( - f"[WARN] Could not retrieve JSON data from the request. Error:{e}" - ) - return jsonify(message="Something went wrong!"), 400 - - if jsonData.get("flow_category", None) == "dry_flow": - handle_dry_flow(jsonData) - else: - handle_regular_flow(jsonData) - return jsonify(message="Success"), 200 - - logger.warning("[WARN] Received a GET request instead of POST") - return ( - jsonify(message="Currently, the system does not accept a GET request"), - 405, - ) - except Exception as e: - logger.error(f"An unexpected error occurred. Error message: {e}") - return jsonify(message="Internal server error"), 500 + with app.app_context(): + try: + if request.method == "POST": + try: + jsonData = request.get_json() + except Exception as e: + logger.warning( + f"[WARN] Could not retrieve JSON data from the request. Error:{e}" + ) + return jsonify(message="Something went wrong!"), 400 + + if jsonData.get("flow_category", None) == "dry_flow": + handle_dry_flow(jsonData) + else: + handle_regular_flow(jsonData) + return jsonify(message="Success"), 200 + + logger.warning("[WARN] Received a GET request instead of POST") + return ( + jsonify(message="Currently, the system does not accept a GET request"), + 405, + ) + except Exception as e: + logger.error(f"An unexpected error occurred. Error message: {e}") + return jsonify(message="Internal server error"), 500 def handle_dry_flow(jsonData): @@ -77,7 +77,7 @@ def retry_failed_webhook(transaction_log_service): for log in failed_webhook_logs: log.attempts += 1 - db_helper.save(log) + helpers.db_helper.save(log) json_data = json.loads(log.payload) json_data["log_created_on"] = log.created_on @@ -86,7 +86,7 @@ def retry_failed_webhook(transaction_log_service): continue log.processed = True - db_helper.save(log) + helpers.db_helper.save(log) def handle_payload(jsonData): diff --git a/manage.py b/manage.py index 1783bd53..52ebebb3 100644 --- a/manage.py +++ b/manage.py @@ -1,12 +1,11 @@ from __future__ import absolute_import from api import db, app -from api.models import * from flask_migrate import Migrate -from flask_script import Manager +from flask.cli import FlaskGroup migrate = Migrate(app, db) -manager = Manager(app) +cli = FlaskGroup(app) if __name__ == "__main__": - manager.run() + cli() diff --git a/requirements-dev.txt b/requirements-dev.txt index 95c84a52..b3a30d94 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,5 @@ # Includes dev dependencies on top of requirements.txt -r requirements.txt -functions-framework==2.1.2 flake8==3.8.4 flake8-polyfill==1.0.2 pep8-naming==0.10.0 diff --git a/requirements.txt b/requirements.txt index d6b6e9b0..00d48fb4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,24 +1,27 @@ certifi==2020.12.5 chardet==4.0.0 -click==7.1.2 -Flask==1.1.2 +click==8.1.3 +Flask==3.0.0 requests==2.25.1 python-dotenv==0.15.0 -Flask-SQLAlchemy==2.1 +Flask-SQLAlchemy==3.1.1 +functions-framework==3.5.0 +greenlet==3.0.3 idna==2.10 -itsdangerous==1.1.0 -Jinja2==2.11.3 -MarkupSafe==1.1.1 -psycopg2==2.8.6 +itsdangerous==2.1.2 +Jinja2==3.1.2 +MarkupSafe==2.1.1 +psycopg2==2.9.9 python-dotenv==0.15.0 requests==2.25.1 -SQLAlchemy==1.3.23 +SQLAlchemy==2.0.23 urllib3==1.26.3 -Werkzeug==1.0.1 +Werkzeug==3.0.0 google-cloud-logging==3.5.0 -Flask-Migrate==2.1.1 +Flask-Migrate==4.0.5 Flask-Script==2.0.6 pytest==7.4.3 faker==20.1.0 setuptools==68.2.2 pytest-cov==4.0.0 +watchdog==3.0.0 diff --git a/tests/conftest.py b/tests/conftest.py index 64f9aede..32eac7a6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,8 +27,7 @@ def client(app): @pytest.fixture(scope="session") def db(): - db = SQLAlchemy(flask_app) - db.init_app(flask_app) + db = SQLAlchemy() return db @@ -36,12 +35,13 @@ def db(): @pytest.fixture(scope="session") def setup_test_environment(db): # Creating tables. - try: - os.system("flask db downgrade 31955a9b7348") - os.system("flask db downgrade") - os.system("flask db upgrade") - except: - os.system("flask db upgrade") - - # Loading pre-filled data for running tests. - testing_seeder.main() + with flask_app.app_context(): + try: + os.system("flask db downgrade 31955a9b7348") + os.system("flask db downgrade") + os.system("flask db upgrade") + except: + os.system("flask db upgrade") + + # Loading pre-filled data for running tests. + testing_seeder.main() diff --git a/tests/test_call_log.py b/tests/test_call_log.py index 239ae74b..d174be4b 100644 --- a/tests/test_call_log.py +++ b/tests/test_call_log.py @@ -25,56 +25,59 @@ def pytest_namespace(): def test_create_call_log(app, db, setup_test_environment): - # Get a specific user - user: User = User.query.get_by_id(1) + with app.app_context(): + # Get a specific user + user: User = User.query.get_by_id(1) - # Update user phone number to payload. - payload["contact"]["urn"] = f"tel:{user.phone}" + # Update user phone number to payload. + payload["contact"]["urn"] = f"tel:{user.phone}" - # Get a specific system phone number - system_phone: SystemPhone = SystemPhone.query.get_by_id(1) + # Get a specific system phone number + system_phone: SystemPhone = SystemPhone.query.get_by_id(1) - # Update system phone number to payload. - payload["channel"]["address"] = f"+91{system_phone.phone}" + # Update system phone number to payload. + payload["channel"]["address"] = f"+91{system_phone.phone}" - # Get a specific content - content_version: ContentVersion = ContentVersion.query.get_by_id(1) + # Get a specific content + content_version: ContentVersion = ContentVersion.query.get_by_id(1) - payload["content_id"] = content_version.content_id - payload["language_id"] = content_version.language_id + payload["content_id"] = content_version.content_id + payload["language_id"] = content_version.language_id - # Initialize the call log service. - call_log_service_instance = CallLogService() - call_log_service_instance.handle_call_log(payload) + # Initialize the call log service. + call_log_service_instance = CallLogService() + call_log_service_instance.handle_call_log(payload) - call_log_model = CallLog.query.get_by_flow_run_uuid(new_run_uuid) - pytest.initial_content_version_id = call_log_model.content_version_id - assert call_log_model != None + call_log_model = CallLog.query.get_by_flow_run_uuid(new_run_uuid) + pytest.initial_content_version_id = call_log_model.content_version_id + assert call_log_model != None def test_update_call_log(app, db, setup_test_environment): - # Get all content version records - all_content_version_records = ContentVersion.query.all() - - stop_iteration = False - new_content_id = None - new_language_id = None - while not stop_iteration: - random_index = randint(0, len(all_content_version_records) - 1) - if ( - all_content_version_records[random_index].id - != pytest.initial_content_version_id - ): - new_content_id = all_content_version_records[random_index].content_id - new_language_id = all_content_version_records[random_index].language_id - stop_iteration = True - - payload["content_id"] = new_content_id - payload["contact"]["fields"]["language_id"] = new_language_id - - # Initialize the call log service. - call_log_service_instance = CallLogService() - call_log_service_instance.handle_call_log(payload) - - call_log_model = CallLog.query.get_by_flow_run_uuid(new_run_uuid) - assert call_log_model.content_version_id != pytest.initial_content_version_id + with app.app_context(): + + # Get all content version records + all_content_version_records = ContentVersion.query.all() + + stop_iteration = False + new_content_id = None + new_language_id = None + while not stop_iteration: + random_index = randint(0, len(all_content_version_records) - 1) + if ( + all_content_version_records[random_index].id + != pytest.initial_content_version_id + ): + new_content_id = all_content_version_records[random_index].content_id + new_language_id = all_content_version_records[random_index].language_id + stop_iteration = True + + payload["content_id"] = new_content_id + payload["contact"]["fields"]["language_id"] = new_language_id + + # Initialize the call log service. + call_log_service_instance = CallLogService() + call_log_service_instance.handle_call_log(payload) + + call_log_model = CallLog.query.get_by_flow_run_uuid(new_run_uuid) + assert call_log_model.content_version_id != pytest.initial_content_version_id