Squashed 'spiffworkflow-backend/' changes from 153061d4..1092ed11

1092ed11 Merge branch 'main' of github.com:sartography/spiffworkflow-backend into main
97b96fa9 Merge commit '999e0f4d2b7a3c3665feb806fd4f00dc50f2de8e'
4d2ebbe2 Refresh token (#6)
2c47d862 Revert "Assure that the Active Task Users table is cleared out before deleting the Active Task Record."
6c1660a3 Merge commit 'eff49e1ddb2e70d62e45866b429a1350443107d0' into main
f7949ada Merge commit 'ac929cbae7717affed5fa357a56cf1a0256289d5' into main
b70804ea Merge commit '65283df3cbfe95c6cd0d69e1cc0204d91c5d535b'
5b9ad7a7 Merge commit 'a59108db95274bef304cbd9246537206d0b449cf'
038c8e68 Merge commit '835160e5a82c7e0518fa25ed7fa1168c9c435739'
aae7966b Merge commit 'a1cce807be1c4ac5f04c42d780df06c216a0de9c'
8527c6be Merge commit '7026fe1f779051f6eb99b872bcd45b14c0cbe88f'
1aa9a8da Merge commit '70480e9f91a1053531ea5db32a13a791c39fd89f'
40383711 Merge commit '9a1e33696a744527a18dbec667140edb4038ac94'
2c7b2e28 Merge commit 'd643de93e5ceaae28a6e65044cc85dd039530d2c'
e5e70161 Merge commit '2b702661f3bd9b79de887e82e5a5925d07341eb6'
b0b92474 updateing poetry lock file.
e5fd3df1 Merge commit 'f0b608789b6cdc3ef4303efac053746c98571a48'
dfe4e3e1 Merge commit 'c5a2f8b16c9a614b944a6e4610594eba1dac7b9f' into main
78dcaec3 pointless change

git-subtree-dir: spiffworkflow-backend
git-subtree-split: 1092ed11187d1b825fa1c5e18f0d96592f0b98e7
This commit is contained in:
burnettk 2022-10-25 16:54:06 -04:00
parent 999e0f4d2b
commit 1f25521506
10 changed files with 50 additions and 161 deletions

View File

@ -90,3 +90,5 @@ This project was generated from `@cjolowicz`_'s `Hypermodern Python Cookiecutter
.. github-only
.. _Contributor Guide: CONTRIBUTING.rst
.. _Usage: https://spiffworkflow-backend.readthedocs.io/en/latest/usage.html
(test)

View File

@ -1,8 +1,8 @@
"""empty message
Revision ID: 4ba2ed52a63a
Revision ID: 3bd6b0b1b8ae
Revises:
Create Date: 2022-10-21 09:31:30.520942
Create Date: 2022-10-25 12:31:50.177599
"""
from alembic import op
@ -10,7 +10,7 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4ba2ed52a63a'
revision = '3bd6b0b1b8ae'
down_revision = None
branch_labels = None
depends_on = None
@ -146,10 +146,10 @@ def upgrade():
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('key', sa.String(length=50), nullable=False),
sa.Column('value', sa.Text(), nullable=False),
sa.Column('creator_user_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('updated_at_in_seconds', sa.Integer(), nullable=True),
sa.Column('created_at_in_seconds', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['creator_user_id'], ['user.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
sa.PrimaryKeyConstraint('id'),
sa.UniqueConstraint('key')
)

View File

@ -2117,8 +2117,8 @@ components:
type: string
example: my_super_secret_value
nullable: false
creator_user_id:
description: The id of the logged in user that created this secret
user_id:
description: The id of the logged in user that updated this secret
type: number
example: 1
nullable: false

View File

@ -17,7 +17,7 @@ class SecretModel(SpiffworkflowBaseDBModel):
id: int = db.Column(db.Integer, primary_key=True)
key: str = db.Column(db.String(50), unique=True, nullable=False)
value: str = db.Column(db.Text(), nullable=False)
creator_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=False)
user_id: int = db.Column(ForeignKey(UserModel.id), nullable=False)
updated_at_in_seconds: int = db.Column(db.Integer)
created_at_in_seconds: int = db.Column(db.Integer)
@ -29,4 +29,4 @@ class SecretModelSchema(Schema):
"""Meta."""
model = SecretModel
fields = ["key", "value", "creator_user_id"]
fields = ["key", "value", "user_id"]

View File

@ -1408,7 +1408,7 @@ def add_secret(body: Dict) -> Response:
def update_secret(key: str, body: dict) -> Response:
"""Update secret."""
SecretService().update_secret(key, body["value"], body["creator_user_id"])
SecretService().update_secret(key, body["value"], body["user_id"])
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")

View File

@ -522,10 +522,6 @@ class ProcessInstanceProcessor:
).all()
if len(active_tasks) > 0:
for at in active_tasks:
active_task_users = at.active_task_users
for atu in active_task_users:
# don't trust sqlalchemy to cascade - ran into race condition here.
db.session.delete(atu)
db.session.delete(at)
db.session.add(self.process_instance_model)

View File

@ -33,12 +33,12 @@ class SecretService:
def add_secret(
key: str,
value: str,
creator_user_id: int,
user_id: int,
) -> SecretModel:
"""Add_secret."""
# encrypted_key = self.encrypt_key(key)
secret_model = SecretModel(
key=key, value=value, creator_user_id=creator_user_id
key=key, value=value, user_id=user_id
)
db.session.add(secret_model)
try:
@ -67,29 +67,22 @@ class SecretService:
def update_secret(
key: str,
value: str,
creator_user_id: int,
user_id: int,
create_if_not_exists: Optional[bool] = False,
) -> None:
"""Does this pass pre commit?"""
secret_model = SecretModel.query.filter(SecretModel.key == key).first()
if secret_model:
if secret_model.creator_user_id == creator_user_id:
secret_model.value = value
db.session.add(secret_model)
try:
db.session.commit()
except Exception as e:
db.session.rollback()
raise e
else:
raise ApiError(
error_code="update_secret_error",
message=f"User: {creator_user_id} cannot update the secret with key : {key}",
status_code=401,
)
secret_model.value = value
db.session.add(secret_model)
try:
db.session.commit()
except Exception as e:
db.session.rollback()
raise e
elif create_if_not_exists:
SecretService.add_secret(
key=key, value=value, creator_user_id=creator_user_id
key=key, value=value, user_id=user_id
)
else:
raise ApiError(
@ -103,21 +96,14 @@ class SecretService:
"""Delete secret."""
secret_model = SecretModel.query.filter(SecretModel.key == key).first()
if secret_model:
if secret_model.creator_user_id == user_id:
db.session.delete(secret_model)
try:
db.session.commit()
except Exception as e:
raise ApiError(
error_code="delete_secret_error",
message=f"Could not delete secret with key: {key}. Original error is: {e}",
) from e
else:
db.session.delete(secret_model)
try:
db.session.commit()
except Exception as e:
raise ApiError(
error_code="delete_secret_error",
message=f"User: {user_id} cannot delete the secret with key : {key}",
status_code=401,
)
message=f"Could not delete secret with key: {key}. Original error is: {e}",
) from e
else:
raise ApiError(
error_code="delete_secret_error",

View File

@ -4,6 +4,7 @@ from typing import Any
import requests
from flask import current_app
from flask import g
from spiffworkflow_backend.services.file_system_service import FileSystemService
from spiffworkflow_backend.services.secret_service import SecretService
@ -57,7 +58,20 @@ class ServiceTaskDelegate:
if proxied_response.status_code != 200:
print("got error from connector proxy")
return proxied_response.text
parsed_response = json.loads(proxied_response.text)
if "refreshed_token_set" not in parsed_response:
return proxied_response.text
secret_key = parsed_response["auth"]
refreshed_token_set = json.dumps(
parsed_response["refreshed_token_set"]
)
SecretService().update_secret(
secret_key, refreshed_token_set, g.user.id
)
return json.dumps(parsed_response["api_response"])
class ServiceTaskService:

View File

@ -71,7 +71,7 @@ class TestSecretService(SecretServiceTestHelpers):
assert test_secret is not None
assert test_secret.key == self.test_key
assert test_secret.value == self.test_value
assert test_secret.creator_user_id == with_super_admin_user.id
assert test_secret.user_id == with_super_admin_user.id
def test_add_secret_duplicate_key_fails(
self,
@ -129,24 +129,6 @@ class TestSecretService(SecretServiceTestHelpers):
assert new_secret
assert new_secret.value == "new_secret_value" # noqa: S105
def test_update_secret_bad_user_fails(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
"""Test_update_secret_bad_user."""
self.add_test_secret(with_super_admin_user)
with pytest.raises(ApiError) as ae:
SecretService.update_secret(
self.test_key, "new_secret_value", with_super_admin_user.id + 1
) # noqa: S105
assert (
ae.value.message
== f"User: {with_super_admin_user.id+1} cannot update the secret with key : test_key"
)
def test_update_secret_bad_secret_fails(
self,
app: Flask,
@ -174,27 +156,11 @@ class TestSecretService(SecretServiceTestHelpers):
self.add_test_secret(with_super_admin_user)
secrets = SecretModel.query.all()
assert len(secrets) == 1
assert secrets[0].creator_user_id == with_super_admin_user.id
assert secrets[0].user_id == with_super_admin_user.id
SecretService.delete_secret(self.test_key, with_super_admin_user.id)
secrets = SecretModel.query.all()
assert len(secrets) == 0
def test_delete_secret_bad_user_fails(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
"""Test_delete_secret_bad_user."""
self.add_test_secret(with_super_admin_user)
with pytest.raises(ApiError) as ae:
SecretService.delete_secret(self.test_key, with_super_admin_user.id + 1)
assert (
f"User: {with_super_admin_user.id+1} cannot delete the secret with key"
in ae.value.message
)
def test_delete_secret_bad_secret_fails(
self,
app: Flask,
@ -223,7 +189,7 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
secret_model = SecretModel(
key=self.test_key,
value=self.test_value,
creator_user_id=with_super_admin_user.id,
user_id=with_super_admin_user.id,
)
data = json.dumps(SecretModelSchema().dump(secret_model))
response: TestResponse = client.post(
@ -234,11 +200,11 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
)
assert response.json
secret: dict = response.json
for key in ["key", "value", "creator_user_id"]:
for key in ["key", "value", "user_id"]:
assert key in secret.keys()
assert secret["key"] == self.test_key
assert secret["value"] == self.test_value
assert secret["creator_user_id"] == with_super_admin_user.id
assert secret["user_id"] == with_super_admin_user.id
def test_get_secret(
self,
@ -273,7 +239,7 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
secret_model = SecretModel(
key=self.test_key,
value="new_secret_value",
creator_user_id=with_super_admin_user.id,
user_id=with_super_admin_user.id,
)
response = client.put(
f"/v1.0/secrets/{self.test_key}",
@ -308,32 +274,6 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
with pytest.raises(ApiError):
secret = SecretService.get_secret(self.test_key)
def test_delete_secret_bad_user(
self,
app: Flask,
client: FlaskClient,
with_db_and_bpmn_file_cleanup: None,
with_super_admin_user: UserModel,
) -> None:
"""Test_delete_secret_bad_user."""
user_1 = self.find_or_create_user()
user_2 = self.find_or_create_user("test_user_2")
self.add_test_secret(user_1)
# ensure user has permissions to delete the given secret
self.add_permissions_to_user(
user_2,
target_uri=f"/v1.0/secrets/{self.test_key}",
permission_names=["delete"],
)
secret_response = client.delete(
f"/v1.0/secrets/{self.test_key}",
headers=self.logged_in_headers(user_2),
)
assert secret_response.status_code == 401
assert secret_response.json
assert secret_response.json["error_code"] == "delete_secret_error"
def test_delete_secret_bad_key(
self,
app: Flask,

View File

@ -1,49 +0,0 @@
"""Process Model."""
from decimal import Decimal
from flask.app import Flask
from flask_bpmn.models.db import db
from spiffworkflow_backend.models.active_task import ActiveTaskModel
from spiffworkflow_backend.models.active_task_user import ActiveTaskUserModel
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
class TestActiveTask(BaseTest):
def test_can_create_and_delete_an_active_task (
self, app: Flask, with_db_and_bpmn_file_cleanup: None
) -> None:
process_model = load_test_spec(
"call_activity_test",
process_model_source_directory="call_activity_same_directory",
)
process_instance = self.create_process_instance_from_process_model(
process_model
)
active_task = ActiveTaskModel(
process_instance_id=process_instance.id,
process_model_display_name="my shorts",
form_file_name="my_file_name",
ui_form_file_name="",
task_id="1234",
task_name="any old thing",
task_title="",
task_type="test type",
task_status="WAITING",
lane_assignment_id=None,
)
initiator_user = self.find_or_create_user("initiator_user")
db.session.add(active_task)
db.session.commit()
active_task_user = ActiveTaskUserModel(active_task_id=active_task.id, user_id=initiator_user.id)
db.session.add(active_task_user)
db.session.commit()
processor = ProcessInstanceProcessor(process_instance)
processor.save() # This should clear out all active tasks and active task users.
assert(len(db.session.query(ActiveTaskModel).all()) == 0)