diff --git a/api/Pipfile b/api/Pipfile index e9c7c9b13..62bf20b26 100644 --- a/api/Pipfile +++ b/api/Pipfile @@ -5,18 +5,19 @@ name = "pypi" [packages] requests = "==2.31.0" -boto3 = "==1.28.67" +boto3 = "==1.33.8" pyjwt = "==2.8.0" psycopg2-binary = "==2.9.9" -elasticsearch = "==8.10.1" +elasticsearch = "==8.11.0" jira = "==3.5.2" -fastapi = "==0.104.0" +fastapi = "==0.104.1" python-decouple = "==3.8" apscheduler = "==3.10.4" redis = "==5.0.1" urllib3 = "==1.26.16" uvicorn = {extras = ["standard"], version = "==0.23.2"} pydantic = {extras = ["email"], version = "==2.3.0"} +psycopg = {extras = ["binary", "pool"], version = "==3.1.14"} [dev-packages] diff --git a/api/app.py b/api/app.py index a72b64ad6..34b78a2ca 100644 --- a/api/app.py +++ b/api/app.py @@ -14,8 +14,8 @@ from starlette.responses import StreamingResponse from chalicelib.utils import helper from chalicelib.utils import pg_client from crons import core_crons, core_dynamic_crons -from routers import core, core_dynamic, additional_routes -from routers.subs import insights, metrics, v1_api, health +from routers import core, core_dynamic +from routers.subs import insights, metrics, v1_api, health, usability_tests loglevel = config("LOGLEVEL", default=logging.WARNING) print(f">Loglevel set to: {loglevel}") @@ -30,7 +30,6 @@ class ORPYAsyncConnection(AsyncConnection): super().__init__(*args, row_factory=dict_row, **kwargs) - @asynccontextmanager async def lifespan(app: FastAPI): # Startup @@ -49,7 +48,6 @@ async def lifespan(app: FastAPI): for job in app.schedule.get_jobs(): ap_logger.info({"Name": str(job.id), "Run Frequency": str(job.trigger), "Next Run": str(job.next_run_time)}) - database = { "host": config("pg_host", default="localhost"), "dbname": config("pg_dbname", default="orpy"), @@ -122,9 +120,9 @@ app.include_router(health.public_app) app.include_router(health.app) app.include_router(health.app_apikey) -app.include_router(additional_routes.public_app) -app.include_router(additional_routes.app) -app.include_router(additional_routes.app_apikey) +app.include_router(usability_tests.public_app) +app.include_router(usability_tests.app) +app.include_router(usability_tests.app_apikey) # @app.get('/private/shutdown', tags=["private"]) # async def stop_server(): diff --git a/api/requirements-alerts.txt b/api/requirements-alerts.txt index d4b024e11..991c6d773 100644 --- a/api/requirements-alerts.txt +++ b/api/requirements-alerts.txt @@ -1,9 +1,10 @@ # Keep this version to not have conflicts between requests and boto3 urllib3==1.26.16 requests==2.31.0 -boto3==1.29.7 +boto3==1.33.8 pyjwt==2.8.0 psycopg2-binary==2.9.9 +psycopg[pool,binary]==3.1.14 elasticsearch==8.11.0 jira==3.5.2 diff --git a/api/requirements.txt b/api/requirements.txt index a591c90c3..7d981bae4 100644 --- a/api/requirements.txt +++ b/api/requirements.txt @@ -1,9 +1,10 @@ # Keep this version to not have conflicts between requests and boto3 urllib3==1.26.16 requests==2.31.0 -boto3==1.29.7 +boto3==1.33.8 pyjwt==2.8.0 psycopg2-binary==2.9.9 +psycopg[pool,binary]==3.1.14 elasticsearch==8.11.0 jira==3.5.2 @@ -16,5 +17,3 @@ pydantic[email]==2.3.0 apscheduler==3.10.4 redis==5.0.1 - -psycopg[pool,binary]==3.1.12 diff --git a/api/routers/additional_routes.py b/api/routers/additional_routes.py deleted file mode 100644 index 4e678a427..000000000 --- a/api/routers/additional_routes.py +++ /dev/null @@ -1,3 +0,0 @@ -from routers.base import get_routers - -public_app, app, app_apikey = get_routers() diff --git a/api/routers/core.py b/api/routers/core.py index 7821edc28..1e772038b 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -1,7 +1,7 @@ -from typing import Union, Optional +from typing import Union from decouple import config -from fastapi import Depends, Body, Query +from fastapi import Depends, Body import schemas from chalicelib.core import log_tool_rollbar, sourcemaps, events, sessions_assignments, projects, \ @@ -14,7 +14,6 @@ from chalicelib.core import log_tool_rollbar, sourcemaps, events, sessions_assig from chalicelib.core.collaboration_msteams import MSTeams from chalicelib.core.collaboration_slack import Slack from or_dependencies import OR_context, OR_role -from chalicelib.core.usability_testing.routes import app as usability_testing_routes from routers.base import get_routers public_app, app, app_apikey = get_routers() @@ -704,14 +703,14 @@ def get_slack_channels(context: schemas.CurrentContext = Depends(OR_context)): return {"data": webhook.get_by_type(tenant_id=context.tenant_id, webhook_type=schemas.WebhookType.slack)} -@app.get('/integrations/slack/{webhookId}', tags=["integrations"]) -def get_slack_webhook(webhookId: int, context: schemas.CurrentContext = Depends(OR_context)): - return {"data": Slack.get_integration(tenant_id=context.tenant_id, integration_id=webhookId)} +@app.get('/integrations/slack/{integrationId}', tags=["integrations"]) +def get_slack_webhook(integrationId: int, context: schemas.CurrentContext = Depends(OR_context)): + return {"data": Slack.get_integration(tenant_id=context.tenant_id, integration_id=integrationId)} -@app.delete('/integrations/slack/{webhookId}', tags=["integrations"]) -def delete_slack_integration(webhookId: int, _=Body(None), context: schemas.CurrentContext = Depends(OR_context)): - return webhook.delete(tenant_id=context.tenant_id, webhook_id=webhookId) +@app.delete('/integrations/slack/{integrationId}', tags=["integrations"]) +def delete_slack_integration(integrationId: int, _=Body(None), context: schemas.CurrentContext = Depends(OR_context)): + return webhook.delete(tenant_id=context.tenant_id, webhook_id=integrationId) @app.put('/webhooks', tags=["webhooks"]) @@ -861,6 +860,3 @@ async def check_recording_status(project_id: int): @public_app.get('/', tags=["health"]) def health_check(): return {} - - -app.include_router(usability_testing_routes) diff --git a/api/chalicelib/core/usability_testing/routes.py b/api/routers/subs/usability_tests.py similarity index 78% rename from api/chalicelib/core/usability_testing/routes.py rename to api/routers/subs/usability_tests.py index 753ad9773..b284969e2 100644 --- a/api/chalicelib/core/usability_testing/routes.py +++ b/api/routers/subs/usability_tests.py @@ -1,8 +1,7 @@ from fastapi import Body, Depends -from chalicelib.core.usability_testing.schema import UTTestCreate, UTTestRead, UTTestUpdate, UTTestDelete, SearchResult, \ - UTTestSearch, UTTestSessionsSearch, UTTestResponsesSearch, StatusEnum, UTTestStatusUpdate from chalicelib.core.usability_testing import service +from chalicelib.core.usability_testing.schema import UTTestCreate, UTTestUpdate, UTTestSearch from or_dependencies import OR_context from routers.base import get_routers from schemas import schemas @@ -11,7 +10,7 @@ public_app, app, app_apikey = get_routers() tags = ["usability-tests"] -@app.post("/{projectId}/usability-tests/search", tags=tags) +@app.post('/{projectId}/usability-tests/search', tags=tags) async def search_ui_tests( projectId: int, search: UTTestSearch = Body(..., @@ -28,7 +27,7 @@ async def search_ui_tests( return service.search_ui_tests(projectId, search) -@app.post("/{projectId}/usability-tests", tags=tags) +@app.post('/{projectId}/usability-tests', tags=tags) async def create_ut_test(projectId: int, test_data: UTTestCreate, context: schemas.CurrentContext = Depends(OR_context)): """ @@ -42,7 +41,7 @@ async def create_ut_test(projectId: int, test_data: UTTestCreate, return service.create_ut_test(test_data) -@app.get("/{projectId}/usability-tests/{test_id}", tags=tags) +@app.get('/{projectId}/usability-tests/{test_id}', tags=tags) async def get_ut_test(projectId: int, test_id: int): """ Retrieve a specific UT test by its ID. @@ -53,7 +52,7 @@ async def get_ut_test(projectId: int, test_id: int): return service.get_ut_test(projectId, test_id) -@app.delete("/{projectId}/usability-tests/{test_id}", tags=tags) +@app.delete('/{projectId}/usability-tests/{test_id}', tags=tags) async def delete_ut_test(projectId: int, test_id: int): """ Delete a specific UT test by its ID. @@ -64,7 +63,7 @@ async def delete_ut_test(projectId: int, test_id: int): return service.delete_ut_test(projectId, test_id) -@app.put("/{projectId}/usability-tests/{test_id}", tags=tags) +@app.put('/{projectId}/usability-tests/{test_id}', tags=tags) async def update_ut_test(projectId: int, test_id: int, test_update: UTTestUpdate): """ Update a specific UT test by its ID. @@ -77,7 +76,7 @@ async def update_ut_test(projectId: int, test_id: int, test_update: UTTestUpdate return service.update_ut_test(projectId, test_id, test_update) -@app.get("/{projectId}/usability-tests/{test_id}/sessions", tags=tags) +@app.get('/{projectId}/usability-tests/{test_id}/sessions', tags=tags) async def get_sessions(projectId: int, test_id: int, page: int = 1, limit: int = 10, live: bool = False, user_id: str = None): @@ -91,8 +90,8 @@ async def get_sessions(projectId: int, test_id: int, page: int = 1, limit: int = return service.ut_tests_sessions(projectId, test_id, page, limit, user_id, live) -@app.get("/{projectId}/usability-tests/{test_id}/responses/{task_id}", tags=tags) -async def get_responses(test_id: int, task_id: int, page: int = 1, limit: int = 10, query: str = None): +@app.get('/{projectId}/usability-tests/{test_id}/responses/{task_id}', tags=tags) +async def get_responses(projectId: int, test_id: int, task_id: int, page: int = 1, limit: int = 10, query: str = None): """ Get responses related to a specific UT test. @@ -102,8 +101,8 @@ async def get_responses(test_id: int, task_id: int, page: int = 1, limit: int = return service.get_responses(test_id, task_id, page, limit, query) -@app.get("/{projectId}/usability-tests/{test_id}/statistics", tags=tags) -async def get_statistics(test_id: int): +@app.get('/{projectId}/usability-tests/{test_id}/statistics', tags=tags) +async def get_statistics(projectId: int, test_id: int): """ Get statistics related to a specific UT test. @@ -113,8 +112,8 @@ async def get_statistics(test_id: int): return service.get_statistics(test_id=test_id) -@app.get("/{projectId}/usability-tests/{test_id}/task-statistics", tags=tags) -async def get_task_statistics(test_id: int): +@app.get('/{projectId}/usability-tests/{test_id}/task-statistics', tags=tags) +async def get_task_statistics(projectId: int, test_id: int): """ Get statistics related to a specific UT test. diff --git a/ee/api/.gitignore b/ee/api/.gitignore index 00968c20a..eabdcc1e4 100644 --- a/ee/api/.gitignore +++ b/ee/api/.gitignore @@ -263,6 +263,7 @@ Pipfile.lock /routers/core.py /routers/subs/__init__.py /routers/subs/v1_api.py +/routers/subs/usability_tests.py /run-alerts-dev.sh /run-dev.sh /schemas/overrides.py @@ -270,3 +271,6 @@ Pipfile.lock /schemas/transformers_validators.py /test/ /chalicelib/core/user_testing.py +/orpy.py +/chalicelib/core/usability_testing/ +/NOTES.md diff --git a/ee/api/Pipfile b/ee/api/Pipfile index 1342801c7..1279cb550 100644 --- a/ee/api/Pipfile +++ b/ee/api/Pipfile @@ -6,22 +6,23 @@ name = "pypi" [packages] urllib3 = "==1.26.16" requests = "==2.31.0" -boto3 = "==1.28.67" +boto3 = "==1.29.7" pyjwt = "==2.8.0" psycopg2-binary = "==2.9.9" -elasticsearch = "==8.10.1" +elasticsearch = "==8.11.0" jira = "==3.5.2" -fastapi = "==0.104.0" +fastapi = "==0.104.1" gunicorn = "==21.2.0" python-decouple = "==3.8" apscheduler = "==3.10.4" python-multipart = "==0.0.6" redis = "==5.0.1" +python3-saml = "==1.16.0" +azure-storage-blob = "==12.19.0" uvicorn = {extras = ["standard"], version = "==0.23.2"} pydantic = {extras = ["email"], version = "==2.3.0"} clickhouse-driver = {extras = ["lz4"], version = "==0.2.6"} -python3-saml = "==1.16.0" -azure-storage-blob = "==12.18.3" +psycopg = {extras = ["binary", "pool"], version = "==3.1.12"} [dev-packages] diff --git a/ee/api/app.py b/ee/api/app.py index c2481e371..018765251 100644 --- a/ee/api/app.py +++ b/ee/api/app.py @@ -23,8 +23,8 @@ from routers import ee if config("ENABLE_SSO", cast=bool, default=True): from routers import saml from crons import core_crons, ee_crons, core_dynamic_crons -from routers.subs import insights, metrics, v1_api_ee -from routers.subs import v1_api, health +from routers.subs import insights, metrics, v1_api, health, usability_tests +from routers.subs import v1_api_ee loglevel = config("LOGLEVEL", default=logging.WARNING) print(f">Loglevel set to: {loglevel}") @@ -39,7 +39,6 @@ class ORPYAsyncConnection(AsyncConnection): super().__init__(*args, row_factory=dict_row, **kwargs) - @asynccontextmanager async def lifespan(app: FastAPI): # Startup @@ -60,7 +59,6 @@ async def lifespan(app: FastAPI): for job in app.schedule.get_jobs(): ap_logger.info({"Name": str(job.id), "Run Frequency": str(job.trigger), "Next Run": str(job.next_run_time)}) - database = { "host": config("pg_host", default="localhost"), "dbname": config("pg_dbname", default="orpy"), @@ -143,6 +141,10 @@ app.include_router(health.public_app) app.include_router(health.app) app.include_router(health.app_apikey) +app.include_router(usability_tests.public_app) +app.include_router(usability_tests.app) +app.include_router(usability_tests.app_apikey) + if config("ENABLE_SSO", cast=bool, default=True): app.include_router(saml.public_app) app.include_router(saml.app) diff --git a/ee/api/clean-dev.sh b/ee/api/clean-dev.sh index e9f829aee..ceb638ed4 100755 --- a/ee/api/clean-dev.sh +++ b/ee/api/clean-dev.sh @@ -86,8 +86,11 @@ rm -rf ./routers/base.py rm -rf ./routers/core.py rm -rf ./routers/subs/__init__.py rm -rf ./routers/subs/v1_api.py +rm -rf ./routers/subs/usability_tests.py rm -rf ./run-alerts-dev.sh rm -rf ./run-dev.sh rm -rf ./schemas/overrides.py rm -rf ./schemas/schemas.py -rm -rf ./schemas/transformers_validators.py \ No newline at end of file +rm -rf ./schemas/transformers_validators.py +rm -rf ./orpy.py +rm -rf ./chalicelib/core/usability_testing/ \ No newline at end of file diff --git a/ee/api/requirements-alerts.txt b/ee/api/requirements-alerts.txt index f78b224c1..3e7aed3a9 100644 --- a/ee/api/requirements-alerts.txt +++ b/ee/api/requirements-alerts.txt @@ -4,6 +4,7 @@ requests==2.31.0 boto3==1.29.7 pyjwt==2.8.0 psycopg2-binary==2.9.9 +psycopg[pool,binary]==3.1.14 elasticsearch==8.11.0 jira==3.5.2 diff --git a/ee/api/requirements-crons.txt b/ee/api/requirements-crons.txt index 99fa1d577..b879aed2d 100644 --- a/ee/api/requirements-crons.txt +++ b/ee/api/requirements-crons.txt @@ -4,6 +4,7 @@ requests==2.31.0 boto3==1.29.7 pyjwt==2.8.0 psycopg2-binary==2.9.9 +psycopg[pool,binary]==3.1.14 elasticsearch==8.11.0 jira==3.5.2 diff --git a/ee/api/requirements.txt b/ee/api/requirements.txt index 198752e6d..a55666eea 100644 --- a/ee/api/requirements.txt +++ b/ee/api/requirements.txt @@ -4,6 +4,7 @@ requests==2.31.0 boto3==1.29.7 pyjwt==2.8.0 psycopg2-binary==2.9.9 +psycopg[pool,binary]==3.1.14 elasticsearch==8.11.0 jira==3.5.2 @@ -19,12 +20,10 @@ apscheduler==3.10.4 clickhouse-driver[lz4]==0.2.6 # TODO: enable after xmlsec fix https://github.com/xmlsec/python-xmlsec/issues/252 #--no-binary is used to avoid libxml2 library version incompatibilities between xmlsec and lxml -#python3-saml==1.15.0 --no-binary=lxml +#python3-saml==1.16.0 --no-binary=lxml python3-saml==1.16.0 python-multipart==0.0.6 redis==5.0.1 #confluent-kafka==2.1.0 azure-storage-blob==12.19.0 - -psycopg[pool,binary]==3.1.12