extended the api to create users and groups, added some tests, and added some helpful commands w/ burnettk
This commit is contained in:
parent
672e517528
commit
3c8ded606e
|
@ -7,12 +7,18 @@ function error_handler() {
|
|||
trap 'error_handler ${LINENO} $?' ERR
|
||||
set -o errtrace -o errexit -o nounset -o pipefail
|
||||
|
||||
rm -rf migrations/
|
||||
rm -f ./src/spiff_workflow_webapp/db.sqlite3
|
||||
tasks=""
|
||||
if [[ "${1:-}" == "clean" ]]; then
|
||||
tasks="$tasks init"
|
||||
|
||||
mysql -uroot -e "DROP DATABASE IF EXISTS spiff_workflow_webapp_development"
|
||||
mysql -uroot -e "CREATE DATABASE spiff_workflow_webapp_development"
|
||||
rm -rf migrations/
|
||||
rm -f ./src/spiff_workflow_webapp/db.sqlite3
|
||||
|
||||
for task in init migrate upgrade ; do
|
||||
mysql -uroot -e "DROP DATABASE IF EXISTS spiff_workflow_webapp_development"
|
||||
mysql -uroot -e "CREATE DATABASE spiff_workflow_webapp_development"
|
||||
fi
|
||||
tasks="$tasks migrate upgrade"
|
||||
|
||||
for task in $tasks ; do
|
||||
FLASK_ENV=development FLASK_APP=src/spiff_workflow_webapp poetry run flask db "$task"
|
||||
done
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
function error_handler() {
|
||||
>&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}."
|
||||
exit "$2"
|
||||
}
|
||||
trap 'error_handler ${LINENO} $?' ERR
|
||||
set -o errtrace -o errexit -o nounset -o pipefail
|
||||
|
||||
FLASK_ENV=development FLASK_APP=src/spiff_workflow_webapp poetry run flask run
|
|
@ -12,7 +12,7 @@ if [[ "${1:-}" == "c" ]]; then
|
|||
elif grep -qE '^[0-9]$' <<<"${1:-}" ; then
|
||||
curl --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d "{ \"task_identifier\": \"${1}\"}"
|
||||
else
|
||||
./bin/recreate_db
|
||||
./bin/recreate_db clean
|
||||
curl --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Product Name": "G", "Quantity": "2"}}'
|
||||
curl --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Sleeve Type": "Short"}}'
|
||||
curl --fail localhost:5000/run_process -H "Content-type: application/json" -X POST -d '{ "task_identifier": "1", "answer": {"Continue shopping?": "N"}}'
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import pytest
|
||||
from spiff_workflow_webapp import create_app
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def app():
|
||||
app = create_app()
|
||||
return app
|
|
@ -74,7 +74,7 @@ wrapt = ">=1.11,<2"
|
|||
name = "atomicwrites"
|
||||
version = "1.4.0"
|
||||
description = "Atomic file writes."
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
|
@ -82,7 +82,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|||
name = "attrs"
|
||||
version = "21.4.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
|
@ -804,7 +804,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
|
|||
name = "iniconfig"
|
||||
version = "1.1.1"
|
||||
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
|
@ -1049,7 +1049,7 @@ test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytes
|
|||
name = "pluggy"
|
||||
version = "1.0.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
|
@ -1108,11 +1108,19 @@ category = "main"
|
|||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "psycopg2"
|
||||
version = "2.9.3"
|
||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
|
@ -1177,7 +1185,7 @@ diagrams = ["railroad-diagrams", "jinja2"]
|
|||
name = "pytest"
|
||||
version = "6.2.5"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
|
@ -1195,6 +1203,54 @@ toml = "*"
|
|||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-flask"
|
||||
version = "1.2.0"
|
||||
description = "A set of py.test fixtures to test Flask applications."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[package.dependencies]
|
||||
Flask = "*"
|
||||
pytest = ">=5.2"
|
||||
Werkzeug = ">=0.7"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "sphinx-rtd-theme"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-flask-sqlalchemy"
|
||||
version = "1.1.0"
|
||||
description = "A pytest plugin for preserving test isolation in Flask-SQlAlchemy using database transactions."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
Flask-SQLAlchemy = ">=2.3"
|
||||
packaging = ">=14.1"
|
||||
pytest = ">=3.2.1"
|
||||
pytest-mock = ">=1.6.2"
|
||||
SQLAlchemy = ">=1.2.2"
|
||||
|
||||
[package.extras]
|
||||
tests = ["pytest-postgresql (>=2.4.0,<4.0.0)", "psycopg2-binary", "pytest (>=6.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-mock"
|
||||
version = "3.7.0"
|
||||
description = "Thin-wrapper around the mock package for easier use with pytest"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=5.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox", "pytest-asyncio"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
|
@ -1618,7 +1674,7 @@ python-versions = ">=3.6.1"
|
|||
name = "toml"
|
||||
version = "0.10.2"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
category = "dev"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
|
@ -1815,7 +1871,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.7"
|
||||
content-hash = "0294c8b538946b050d6db1ebeaad601bbb3288e036604f970e86bd3aea4e1c3e"
|
||||
content-hash = "93a1364b751e27cf2cca33214753d89549b2a9a82d01b90ff43702f34a87a0b1"
|
||||
|
||||
[metadata.files]
|
||||
alabaster = [
|
||||
|
@ -2525,6 +2581,19 @@ protobuf = [
|
|||
{file = "protobuf-3.20.1-py2.py3-none-any.whl", hash = "sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388"},
|
||||
{file = "protobuf-3.20.1.tar.gz", hash = "sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9"},
|
||||
]
|
||||
psycopg2 = [
|
||||
{file = "psycopg2-2.9.3-cp310-cp310-win32.whl", hash = "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362"},
|
||||
{file = "psycopg2-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca"},
|
||||
{file = "psycopg2-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56"},
|
||||
{file = "psycopg2-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305"},
|
||||
{file = "psycopg2-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2"},
|
||||
{file = "psycopg2-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461"},
|
||||
{file = "psycopg2-2.9.3-cp38-cp38-win32.whl", hash = "sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7"},
|
||||
{file = "psycopg2-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf"},
|
||||
{file = "psycopg2-2.9.3-cp39-cp39-win32.whl", hash = "sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126"},
|
||||
{file = "psycopg2-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c"},
|
||||
{file = "psycopg2-2.9.3.tar.gz", hash = "sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981"},
|
||||
]
|
||||
py = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
|
@ -2557,6 +2626,18 @@ pytest = [
|
|||
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
|
||||
]
|
||||
pytest-flask = [
|
||||
{file = "pytest-flask-1.2.0.tar.gz", hash = "sha256:46fde652f77777bf02dc91205aec4ce20cdf2acbbbd66a918ab91f5c14693d3d"},
|
||||
{file = "pytest_flask-1.2.0-py3-none-any.whl", hash = "sha256:fe25b39ad0db09c3d1fe728edecf97ced85e774c775db259a6d25f0270a4e7c9"},
|
||||
]
|
||||
pytest-flask-sqlalchemy = [
|
||||
{file = "pytest-flask-sqlalchemy-1.1.0.tar.gz", hash = "sha256:db71a57b90435e5d854b21c37a2584056d6fc3ddb28c09d8d0a2546bd6e390ff"},
|
||||
{file = "pytest_flask_sqlalchemy-1.1.0-py3-none-any.whl", hash = "sha256:b9f272d5c4092fcbe4a6284e402a37cad84f5b9be3c0bbe1a11927f24c99ff83"},
|
||||
]
|
||||
pytest-mock = [
|
||||
{file = "pytest-mock-3.7.0.tar.gz", hash = "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534"},
|
||||
{file = "pytest_mock-3.7.0-py3-none-any.whl", hash = "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231"},
|
||||
]
|
||||
python-dateutil = [
|
||||
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
|
||||
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
|
||||
|
|
|
@ -32,6 +32,9 @@ sentry-sdk = "0.14.4"
|
|||
sphinx-autoapi = "^1.8.4"
|
||||
flask-bpmn = {develop = true, path = "/home/jason/projects/github/sartography/flask-bpmn"}
|
||||
mysql-connector-python = "^8.0.29"
|
||||
pytest-flask = "^1.2.0"
|
||||
pytest-flask-sqlalchemy = "^1.1.0"
|
||||
psycopg2 = "^2.9.3"
|
||||
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""__init__."""
|
||||
from flask import Flask
|
||||
|
||||
from .routes.api import api
|
||||
from .routes.main import main
|
||||
from spiff_workflow_webapp.routes.api import api
|
||||
from spiff_workflow_webapp.routes.user_blueprint import user_blueprint
|
||||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.db import migrate
|
||||
|
||||
|
@ -10,14 +10,15 @@ from flask_bpmn.models.db import migrate
|
|||
def create_app():
|
||||
"""Create_app."""
|
||||
app = Flask(__name__)
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite3"
|
||||
# app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+mysqlconnector://root:@localhost/spiff_workflow_webapp_development"
|
||||
# app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite3"
|
||||
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+mysqlconnector://root:@localhost/spiff_workflow_webapp_development"
|
||||
# app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://crc_user:crc_pass@localhost:5432/spiff_test"
|
||||
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||
|
||||
db.init_app(app)
|
||||
migrate.init_app(app, db)
|
||||
|
||||
app.register_blueprint(main)
|
||||
app.register_blueprint(user_blueprint)
|
||||
app.register_blueprint(api)
|
||||
|
||||
return app
|
||||
|
|
Binary file not shown.
|
@ -1,6 +0,0 @@
|
|||
"""Extensions."""
|
||||
from flask_migrate import Migrate
|
||||
from flask_sqlalchemy import SQLAlchemy
|
||||
|
||||
db = SQLAlchemy()
|
||||
migrate = Migrate()
|
|
@ -1,7 +0,0 @@
|
|||
from flask_bpmn.models.db import db
|
||||
|
||||
|
||||
class CartModel(db.Model):
|
||||
__tablename__ = 'carts'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
name = db.Column(db.String(255))
|
|
@ -0,0 +1,11 @@
|
|||
from flask_bpmn.models.db import db
|
||||
from flask_bpmn.models.group import FlaskBpmnGroupModel
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
|
||||
class GroupModel(FlaskBpmnGroupModel):
|
||||
__tablename__ = "group"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
new_name_two = db.Column(db.String(255))
|
||||
user_group_assignments = relationship("UserGroupAssignmentModel", cascade="all, delete")
|
||||
users = relationship("UserModel", secondary="user_group_assignment")
|
|
@ -3,6 +3,6 @@ from sqlalchemy.orm import deferred
|
|||
|
||||
|
||||
class ProcessModel(db.Model):
|
||||
__tablename__ = 'process_models'
|
||||
__tablename__ = 'process_model'
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
bpmn_json = deferred(db.Column(db.JSON))
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
"""User."""
|
||||
from ..extensions import db
|
||||
from flask_bpmn.models.db import db
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
|
||||
class User(db.Model):
|
||||
"""User."""
|
||||
class UserModel(db.Model):
|
||||
"""UserModel."""
|
||||
|
||||
__tablename__ = "user"
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
username = db.Column(db.String(50), nullable=False, unique=True)
|
||||
name = db.Column(db.String(50))
|
||||
email = db.Column(db.String(50))
|
||||
user_group_assignments = relationship("UserGroupAssignmentModel", cascade="all, delete")
|
||||
groups = relationship("GroupModel", secondary="user_group_assignment")
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
"""UserGroupAssignment."""
|
||||
from flask_bpmn.models.db import db
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from spiff_workflow_webapp.models.group import GroupModel
|
||||
from spiff_workflow_webapp.models.user import UserModel
|
||||
|
||||
|
||||
class UserGroupAssignmentModel(db.Model):
|
||||
"""UserGroupAssignmentModel."""
|
||||
|
||||
__tablename__ = "user_group_assignment"
|
||||
__table_args__ = (
|
||||
db.UniqueConstraint('user_id', 'group_id', name='user_group_assignment_unique'),
|
||||
)
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
user_id = db.Column(ForeignKey(UserModel.id), nullable=False)
|
||||
group_id = db.Column(ForeignKey(GroupModel.id), nullable=False)
|
||||
group = relationship("GroupModel")
|
||||
user = relationship("UserModel")
|
|
@ -4,7 +4,7 @@ import os
|
|||
from flask import Blueprint
|
||||
from flask import request
|
||||
|
||||
from ..models.user import User
|
||||
from ..models.user import UserModel
|
||||
from spiff_workflow_webapp.spiff_workflow_connector import parse
|
||||
from spiff_workflow_webapp.spiff_workflow_connector import run
|
||||
|
||||
|
@ -20,14 +20,6 @@ serializer = BpmnWorkflowSerializer(wf_spec_converter)
|
|||
api = Blueprint("api", __name__)
|
||||
|
||||
|
||||
@api.route("/user/<name>")
|
||||
def create_user(name):
|
||||
"""Create_user."""
|
||||
user = User.query.filter_by(name=name).first()
|
||||
|
||||
return {"user": user.name}
|
||||
|
||||
|
||||
@api.route("/run_process", methods=['POST'])
|
||||
def run_process():
|
||||
"""Run_process."""
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
"""Main."""
|
||||
from flask import Blueprint
|
||||
|
||||
from ..extensions import db
|
||||
from ..models.user import User
|
||||
|
||||
main = Blueprint("main", __name__)
|
||||
|
||||
|
||||
@main.route("/user/<name>")
|
||||
def create_user(name):
|
||||
"""Create_user."""
|
||||
user = User(name=name)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
return "Created User!"
|
|
@ -0,0 +1,108 @@
|
|||
"""Main."""
|
||||
import json
|
||||
from flask import Blueprint
|
||||
from flask import Response
|
||||
from flask import request
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
from flask_bpmn.models.db import db
|
||||
from spiff_workflow_webapp.models.group import GroupModel
|
||||
from spiff_workflow_webapp.models.user import UserModel
|
||||
from spiff_workflow_webapp.models.user_group_assignment import UserGroupAssignmentModel
|
||||
|
||||
user_blueprint = Blueprint("main", __name__)
|
||||
|
||||
|
||||
@user_blueprint.route("/user/<username>", methods=["GET"])
|
||||
def create_user(username):
|
||||
"""Create_user."""
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
if user is not None:
|
||||
return Response(json.dumps({"error": f"User already exists: {username}"}), status=409, mimetype='application/json')
|
||||
|
||||
user = UserModel(username=username)
|
||||
try:
|
||||
db.session.add(user)
|
||||
except IntegrityError as exception:
|
||||
return Response(json.dumps({"error": repr(exception)}), status=500, mimetype='application/json')
|
||||
|
||||
db.session.commit()
|
||||
return Response(json.dumps({"id": user.id}), status=201, mimetype='application/json')
|
||||
|
||||
|
||||
@user_blueprint.route("/user/<username>", methods=["DELETE"])
|
||||
def delete_user(username):
|
||||
"""Delete_user."""
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
if user is None:
|
||||
return Response(json.dumps({"error": f"User cannot be found: {username}"}), status=400, mimetype='application/json')
|
||||
|
||||
db.session.delete(user)
|
||||
db.session.commit()
|
||||
|
||||
return Response(json.dumps({"ok": True}), status=204, mimetype='application/json')
|
||||
|
||||
|
||||
@user_blueprint.route("/group/<group_name>", methods=["GET"])
|
||||
def create_group(group_name):
|
||||
"""Create_group."""
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
if group is not None:
|
||||
return Response(json.dumps({"error": f"Group already exists: {group_name}"}), status=409, mimetype='application/json')
|
||||
|
||||
group = GroupModel(name=group_name)
|
||||
try:
|
||||
db.session.add(group)
|
||||
except IntegrityError as exception:
|
||||
return Response(json.dumps({"error": repr(exception)}), status=500, mimetype='application/json')
|
||||
db.session.commit()
|
||||
|
||||
return Response(json.dumps({"id": group.id}), status=201, mimetype='application/json')
|
||||
|
||||
|
||||
@user_blueprint.route("/group/<group_name>", methods=["DELETE"])
|
||||
def delete_group(group_name):
|
||||
"""Delete_group."""
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
if group is None:
|
||||
return Response(json.dumps({"error": f"Group cannot be found: {group_name}"}), status=400, mimetype='application/json')
|
||||
|
||||
db.session.delete(group)
|
||||
db.session.commit()
|
||||
|
||||
return Response(json.dumps({"ok": True}), status=204, mimetype='application/json')
|
||||
|
||||
|
||||
@user_blueprint.route("/assign_user_to_group", methods=["POST"])
|
||||
def assign_user_to_group():
|
||||
"""Assign_user_to_group."""
|
||||
content = request.json
|
||||
user_id = content.get("user_id")
|
||||
group_id = content.get("group_id")
|
||||
|
||||
if user_id is None:
|
||||
return Response("{error:'user_id required'}", status=400, mimetype='application/json')
|
||||
|
||||
if group_id is None:
|
||||
return Response("{error:'group_id required'}", status=400, mimetype='application/json')
|
||||
|
||||
user = UserModel.query.filter_by(id=user_id).first()
|
||||
if user is None:
|
||||
return Response(json.dumps({"error": f"User cannot be found: {user_id}"}), status=400, mimetype='application/json')
|
||||
|
||||
group = GroupModel.query.filter_by(id=group_id).first()
|
||||
if group is None:
|
||||
return Response(json.dumps({"error": f"Group cannot be found: {group_id}"}), status=400, mimetype='application/json')
|
||||
|
||||
user_group_assignment = UserGroupAssignmentModel.query.filter_by(user_id=user.id, group_id=group.id).first()
|
||||
if user_group_assignment is not None:
|
||||
return Response(
|
||||
json.dumps({"error": f"User ({user.id}) is already in group ({group.id})"}),
|
||||
status=409, mimetype='application/json'
|
||||
)
|
||||
|
||||
user_group_assignment = UserGroupAssignmentModel(user_id=user.id, group_id=group.id)
|
||||
db.session.add(user_group_assignment)
|
||||
db.session.commit()
|
||||
|
||||
return Response(json.dumps({"id": user_group_assignment.id}), status=201, mimetype='application/json')
|
|
@ -22,9 +22,6 @@ from SpiffWorkflow.task import Task
|
|||
from flask_bpmn.models.db import db
|
||||
from spiff_workflow_webapp.models.process_model import ProcessModel
|
||||
|
||||
from flask_bpmn.models.group import GroupModel
|
||||
from spiff_workflow_webapp.models.cart import CartModel
|
||||
|
||||
# from custom_script_engine import CustomScriptEngine
|
||||
|
||||
wf_spec_converter = BpmnWorkflowSerializer.configure_workflow_spec_converter(
|
||||
|
@ -181,41 +178,3 @@ def run(workflow, task_identifier=None, answer=None):
|
|||
# dump.write(state)
|
||||
tasks_status["next_activity"] = formatted_options
|
||||
return tasks_status
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser("Simple BPMN runner")
|
||||
parser.add_argument(
|
||||
"-p", "--process", dest="process", help="The top-level BPMN Process ID"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b", "--bpmn", dest="bpmn", nargs="+", help="BPMN files to load"
|
||||
)
|
||||
parser.add_argument("-d", "--dmn", dest="dmn", nargs="*", help="DMN files to load")
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--restore",
|
||||
dest="restore",
|
||||
metavar="FILE",
|
||||
help="Restore state from %(metavar)s",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--step",
|
||||
dest="step",
|
||||
action="store_true",
|
||||
help="Display state after each step",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
if args.restore is not None:
|
||||
with open(args.restore) as state:
|
||||
wf = serializer.deserialize_json(state.read())
|
||||
else:
|
||||
wf = parse(args.process, args.bpmn, args.dmn)
|
||||
run(wf, args.step)
|
||||
except Exception:
|
||||
sys.stderr.write(traceback.format_exc())
|
||||
sys.exit(1)
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
"""Test User Blueprint."""
|
||||
|
||||
import json
|
||||
from spiff_workflow_webapp.models.user import UserModel
|
||||
from spiff_workflow_webapp.models.group import GroupModel
|
||||
|
||||
|
||||
def test_user_can_be_created_and_deleted(client):
|
||||
username = "joe"
|
||||
response = client.get(f"/user/{username}")
|
||||
assert response.status_code == 201
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
assert user.username == username
|
||||
|
||||
response = client.delete(f"/user/{username}")
|
||||
assert response.status_code == 204
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
assert user is None
|
||||
|
||||
|
||||
def test_delete_returns_an_error_if_user_is_not_found(client):
|
||||
username = "joe"
|
||||
response = client.delete(f"/user/{username}")
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_create_returns_an_error_if_user_exists(client):
|
||||
username = "joe"
|
||||
response = client.get(f"/user/{username}")
|
||||
assert response.status_code == 201
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
assert user.username == username
|
||||
|
||||
response = client.get(f"/user/{username}")
|
||||
assert response.status_code == 409
|
||||
|
||||
response = client.delete(f"/user/{username}")
|
||||
assert response.status_code == 204
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
assert user is None
|
||||
|
||||
|
||||
def test_group_can_be_created_and_deleted(client):
|
||||
group_name = "administrators"
|
||||
response = client.get(f"/group/{group_name}")
|
||||
assert response.status_code == 201
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
assert group.name == group_name
|
||||
|
||||
response = client.delete(f"/group/{group_name}")
|
||||
assert response.status_code == 204
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
assert group is None
|
||||
|
||||
|
||||
def test_delete_returns_an_error_if_group_is_not_found(client):
|
||||
group_name = "administrators"
|
||||
response = client.delete(f"/group/{group_name}")
|
||||
assert response.status_code == 400
|
||||
|
||||
|
||||
def test_create_returns_an_error_if_group_exists(client):
|
||||
group_name = "administrators"
|
||||
response = client.get(f"/group/{group_name}")
|
||||
assert response.status_code == 201
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
assert group.name == group_name
|
||||
|
||||
response = client.get(f"/group/{group_name}")
|
||||
assert response.status_code == 409
|
||||
|
||||
response = client.delete(f"/group/{group_name}")
|
||||
assert response.status_code == 204
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
assert group is None
|
||||
|
||||
|
||||
def test_user_can_be_assigned_to_a_group(client):
|
||||
user = create_user(client, "joe")
|
||||
group = create_group(client, "administrators")
|
||||
response = client.post("/assign_user_to_group", content_type='application/json', data=json.dumps({"user_id": user.id, "group_id": group.id}))
|
||||
assert response.status_code == 201
|
||||
user = UserModel.query.filter_by(id=user.id).first()
|
||||
assert len(user.user_group_assignments) == 1
|
||||
assert user.user_group_assignments[0].group_id == group.id
|
||||
delete_user(client, user.username)
|
||||
delete_group(client, group.name)
|
||||
|
||||
|
||||
def create_user(client, username):
|
||||
response = client.get(f"/user/{username}")
|
||||
assert response.status_code == 201
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
assert user.username == username
|
||||
return user
|
||||
|
||||
|
||||
def delete_user(client, username):
|
||||
response = client.delete(f"/user/{username}")
|
||||
assert response.status_code == 204
|
||||
user = UserModel.query.filter_by(username=username).first()
|
||||
assert user is None
|
||||
|
||||
|
||||
def create_group(client, group_name):
|
||||
response = client.get(f"/group/{group_name}")
|
||||
assert response.status_code == 201
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
assert group.name == group_name
|
||||
return group
|
||||
|
||||
|
||||
def delete_group(client, group_name):
|
||||
response = client.delete(f"/group/{group_name}")
|
||||
assert response.status_code == 204
|
||||
group = GroupModel.query.filter_by(name=group_name).first()
|
||||
assert group is None
|
Loading…
Reference in New Issue