From acf77f77ac14644cc345c4e2eeee144f11acb8c0 Mon Sep 17 00:00:00 2001 From: Ivan Grebenshchikov Date: Sun, 23 Jul 2023 17:47:57 +0200 Subject: [PATCH] LITE-28161 Add user id and name to Configuration events --- connect_ext_ppr/models/configuration.py | 4 ++-- connect_ext_ppr/schemas.py | 2 +- connect_ext_ppr/utils.py | 20 ++++++++++++++++++-- connect_ext_ppr/webapp.py | 11 ++++++++--- poetry.lock | 19 ++++++++++++++++++- pyproject.toml | 1 + tests/api/test_configurations.py | 21 ++++++++++++++++++++- tests/conftest.py | 12 +++++++++++- tests/test_schemas.py | 14 ++++++++++---- 9 files changed, 89 insertions(+), 15 deletions(-) diff --git a/connect_ext_ppr/models/configuration.py b/connect_ext_ppr/models/configuration.py index 017fdcc..b48143f 100644 --- a/connect_ext_ppr/models/configuration.py +++ b/connect_ext_ppr/models/configuration.py @@ -20,9 +20,9 @@ class Configuration(Model): default=ConfigurationStateChoices.INACTIVE, ) created_at = db.Column(db.DateTime(), default=datetime.utcnow) - created_by = db.Column(db.String(20)) + created_by = db.Column(db.JSON) updated_at = db.Column(db.DateTime(), default=datetime.utcnow) - updated_by = db.Column(db.String(20)) + updated_by = db.Column(db.JSON) def activate(self): self.state = ConfigurationStateChoices.ACTIVE diff --git a/connect_ext_ppr/schemas.py b/connect_ext_ppr/schemas.py index d13e930..463e9a7 100644 --- a/connect_ext_ppr/schemas.py +++ b/connect_ext_ppr/schemas.py @@ -72,7 +72,7 @@ class ConfigurationSchema(NonNullSchema): id: str file: FileSchema state: ConfigurationStateChoices - events: Dict[str, Dict[str, Union[datetime, str]]] + events: Dict[str, Dict[str, Union[datetime, Dict[str, str]]]] class ConfigurationReferenceSchema(NonNullSchema): diff --git a/connect_ext_ppr/utils.py b/connect_ext_ppr/utils.py index c95a9ce..87971cd 100644 --- a/connect_ext_ppr/utils.py +++ b/connect_ext_ppr/utils.py @@ -5,6 +5,7 @@ from connect.eaas.core.logging import RequestLogger from fastapi import status from jsonschema.exceptions import _Error +import jwt import pandas as pd from connect_ext_ppr.errors import ExtensionHttpError @@ -224,8 +225,14 @@ def get_configuration_schema(configuration, file): file=file_schema, state=configuration.state, events={ - 'created': {'at': configuration.created_at}, - 'updated': {'at': configuration.updated_at}, + 'created': { + 'at': configuration.created_at, + 'by': configuration.created_by, + }, + 'updated': { + 'at': configuration.updated_at, + 'by': configuration.updated_by, + }, }, ) @@ -279,3 +286,12 @@ def _parse_json_schema_error(ex: _Error): sub_list = _parse_json_schema_error(sub_ex) error_list.extend(sub_list) return error_list + + +def get_user_data_from_auth_token(token): + payload = jwt.decode(token, options={"verify_signature": False}) + + return { + 'id': payload['u']['oid'], + 'name': payload['u']['name'], + } diff --git a/connect_ext_ppr/webapp.py b/connect_ext_ppr/webapp.py index 3d8edf9..f615eb2 100644 --- a/connect_ext_ppr/webapp.py +++ b/connect_ext_ppr/webapp.py @@ -14,7 +14,7 @@ ) from connect.eaas.core.inject.synchronous import get_installation, get_installation_client from connect.eaas.core.extension import WebApplicationBase -from fastapi import Depends, Response, status +from fastapi import Depends, Request, Response, status from sqlalchemy import exists from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.orm import joinedload @@ -44,6 +44,7 @@ get_deployment_request_schema, get_deployment_schema, get_hubs, + get_user_data_from_auth_token, ) @@ -61,7 +62,7 @@ class ConnectExtensionXvsWebApplication(WebApplicationBase): @router.get( '/deployments/requests', - summary='List all request accross deployments', + summary='List all requests across deployments', response_model=List[DeploymentRequestSchema], ) def list_deployment_requests( @@ -220,6 +221,7 @@ def add_configuration( deployment_id: str, db: VerboseBaseSession = Depends(get_db), installation: dict = Depends(get_installation), + request: Request = None, ): get_deployment_by_id(deployment_id, db, installation) file_data = configuration.file @@ -238,7 +240,7 @@ def add_configuration( mime_type=file_data.mime_type, ) db.add(file_instance) - db.commit() + db.flush() prev_configuration = ( db.query(Configuration) @@ -251,10 +253,13 @@ def add_configuration( if prev_configuration: prev_configuration.state = ConfigurationStateChoices.INACTIVE + user_data = get_user_data_from_auth_token(request.headers['connect-auth']) configuration_instance = Configuration( file=file_data.id, deployment=deployment_id, state=ConfigurationStateChoices.ACTIVE, + created_by=user_data, + updated_by=user_data, ) db.set_verbose(configuration_instance) db.commit() diff --git a/poetry.lock b/poetry.lock index 0d2b1e3..74c0d9b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1170,6 +1170,23 @@ files = [ [package.extras] plugins = ["importlib-metadata"] +[[package]] +name = "pyjwt" +version = "2.8.0" +description = "JSON Web Token implementation in Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyJWT-2.8.0-py3-none-any.whl", hash = "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320"}, + {file = "PyJWT-2.8.0.tar.gz", hash = "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de"}, +] + +[package.extras] +crypto = ["cryptography (>=3.4.0)"] +dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +docs = ["sphinx (>=4.5.0,<5.0.0)", "sphinx-rtd-theme", "zope.interface"] +tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"] + [[package]] name = "pytest" version = "7.4.0" @@ -1625,4 +1642,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = ">=3.8,<4" -content-hash = "6295f5cb2941f991b8f7fd60d2fe49edc92829f3d38f91009ff3a935d6951337" +content-hash = "79cb7007047e91c38456e818b0ca1c517914ca26adc6f06a65d7a915bc892894" diff --git a/pyproject.toml b/pyproject.toml index ceb5a9b..105c068 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ sqlalchemy = "^1.3.12" psycopg2-binary = "^2.9.6" pandas = "^2.0.3" openpyxl = "^3.1.2" +PyJWT = "^2.8.0" [tool.poetry.dev-dependencies] pytest = ">=6.1.2,<8" diff --git a/tests/api/test_configurations.py b/tests/api/test_configurations.py index 02dfe04..3f342f1 100644 --- a/tests/api/test_configurations.py +++ b/tests/api/test_configurations.py @@ -108,6 +108,12 @@ def test_post_configuration( 'mime_type': media_response['mime_type'], }, }, + headers={ + "connect-auth": ( + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1Ijp7Im9pZCI6IlNVLTI5NS02ODktN" + "jI4IiwibmFtZSI6Ik5lcmkifX0.U_T6vuXnD293hcWNTJZ9QBViteNv8JXUL2gM0BezQ-k" + ), + }, ) assert response.status_code == 200 data = response.json() @@ -123,8 +129,15 @@ def test_post_configuration( 'size': 17, 'mime_type': 'application/json', } - assert data['state'] == ConfigurationStateChoices.ACTIVE + assert data['events']['created']['by'] == { + 'id': 'SU-295-689-628', + 'name': 'Neri', + } + assert data['events']['updated']['by'] == { + 'id': 'SU-295-689-628', + 'name': 'Neri', + } assert dbsession.query(Configuration).count() == 1 assert dbsession.query(File).count() == 1 @@ -150,6 +163,12 @@ def test_post_configuration_deactivate_previous( 'mime_type': file.mime_type, }, }, + headers={ + "connect-auth": ( + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1Ijp7Im9pZCI6IlNVLTI5NS02ODktN" + "jI4IiwibmFtZSI6Ik5lcmkifX0.U_T6vuXnD293hcWNTJZ9QBViteNv8JXUL2gM0BezQ-k" + ), + }, ) assert response.status_code == 200 diff --git a/tests/conftest.py b/tests/conftest.py index 56eda43..f3ee092 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -474,10 +474,12 @@ def api_client(test_client_factory, dbsession): @pytest.fixture -def configuration(dbsession, deployment, file): +def configuration(dbsession, deployment, file, user): conf = Configuration( file=file.id, deployment=deployment.id, + created_by=user, + updated_by=user, ) dbsession.set_verbose(conf) dbsession.commit() @@ -779,3 +781,11 @@ def price_proposal_response(): 'currency': [], }, } + + +@pytest.fixture +def user(): + return { + 'id': 'SU-295-689-628', + 'name': 'Neri', + } diff --git a/tests/test_schemas.py b/tests/test_schemas.py index 1184b34..caa3b14 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -120,8 +120,8 @@ def test_configuration_schema(state, file): ), state=state, events={ - 'created': {'at': now, 'by': 'SU-295-689-628'}, - 'updated': {'at': now, 'by': 'SU-295-689-628'}, + 'created': {'at': now, 'by': {'id': 'SU-295-689-628', 'name': 'Neri'}}, + 'updated': {'at': now, 'by': {'id': 'SU-295-689-628', 'name': 'Neri'}}, }, ) assert serializer.dict() == { @@ -137,11 +137,17 @@ def test_configuration_schema(state, file): "events": { "created": { "at": now, - "by": "SU-295-689-628", + "by": { + 'id': 'SU-295-689-628', + 'name': 'Neri', + }, }, "updated": { "at": now, - "by": "SU-295-689-628", + "by": { + 'id': 'SU-295-689-628', + 'name': 'Neri', + }, }, }, }