cornflow 1.3.5rc4__tar.gz → 1.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cornflow-1.3.5rc4/cornflow.egg-info → cornflow-1.3.6}/PKG-INFO +4 -4
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/auxiliar.py +2 -2
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/execution.py +2 -2
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/execution.py +5 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/const.py +6 -1
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/base_test_execution.py +0 -1
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_cli.py +5 -5
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_executions.py +162 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_roles.py +13 -5
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_users.py +93 -1
- {cornflow-1.3.5rc4 → cornflow-1.3.6/cornflow.egg-info}/PKG-INFO +4 -4
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow.egg-info/requires.txt +3 -3
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/requirements.txt +3 -3
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/setup.py +1 -1
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/MANIFEST.in +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/README.rst +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/airflow_config/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/airflow_config/airflow_local_settings.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/airflow_config/plugins/XCom/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/airflow_config/plugins/XCom/gce_xcom_backend.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/airflow_config/plugins/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/airflow_config/webserver_ldap.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/app.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/actions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/arguments.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/config.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/migrations.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/permissions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/roles.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/schemas.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/service.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/api_generator.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/endpoint_tools.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/models_tools.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/schema_generator.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/schemas_tools.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/tools/tools.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/users.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/utils.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/cli/views.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/access.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/actions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/cleanup.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/dag.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/permissions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/roles.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/schemas.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/users.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/commands/views.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/config.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/action.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/apiview.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/case.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/dag.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/data_check.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/example_data.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/execution.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/health.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/instance.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/licenses.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/login.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/main_alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/meta_resource.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/permission.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/roles.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/schemas.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/signup.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/tables.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/token.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/user.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/endpoints/user_role.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/gunicorn.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/README +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/alembic.ini +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/env.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/script.py.mako +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/00757b557b02_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/1af47a419bbd_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/4729cd156460_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/4aac5e0c6e66_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/509d280698e4_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/7c3ea5ab5501_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/991b98e24225_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/999b98e24225.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/9cacf194fa1c_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/a472b5ad50b7_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/c2db9409cb5f_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/c8a6c762e818_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/ca449af8034c_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/cef1df240b27_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/d0e0700dcd8e_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/d1b5be1f0549_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/e1a50dae1ac9_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/e937a5234ce4_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/ebdd955fcc5e_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/migrations/versions/f3bee20314a2_.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/action.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/base_data_model.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/case.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/dag.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/dag_permissions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/instance.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/main_alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/meta_models.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/permissions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/role.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/user.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/user_role.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/models/view.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/action.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/case.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/common.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/dag.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/example_data.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/health.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/instance.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/main_alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/model_json.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/patch.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/permissions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/query.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/role.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/schemas.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/solution_log.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/tables.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/user.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/user_role.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/schemas/view.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/authentication/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/authentication/auth.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/authentication/decorators.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/authentication/ldap.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/compress.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/email.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/exceptions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/licenses.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/log_config.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/query_tools.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/utils.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/utils_tables.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/shared/validators.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/const.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/custom_liveServer.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/custom_test_case.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/integration/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/integration/test_commands.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/integration/test_cornflowclient.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/integration/test_data_checks_kpis.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/ldap/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/ldap/test_ldap_authentication.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/__init__.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_actions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_apiview.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_application.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_cases.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_commands.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_dags.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_data_checks.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_example_data.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_external_role_creation.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_generate_from_schema.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_get_resources.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_health.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_instances.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_instances_file.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_licenses.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_log_in.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_main_alarms.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_permissions.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_schema_from_models.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_schemas.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_sign_up.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_tables.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/test_token.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow/tests/unit/tools.py +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow.egg-info/SOURCES.txt +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow.egg-info/dependency_links.txt +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow.egg-info/entry_points.txt +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/cornflow.egg-info/top_level.txt +0 -0
- {cornflow-1.3.5rc4 → cornflow-1.3.6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cornflow
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: cornflow is an open source multi-solver optimization server with a REST API built using flask.
|
|
5
5
|
Home-page: https://github.com/baobabsoluciones/cornflow
|
|
6
6
|
Author: baobab soluciones
|
|
@@ -14,8 +14,8 @@ Requires-Dist: alembic==1.9.2
|
|
|
14
14
|
Requires-Dist: apispec==6.3.0
|
|
15
15
|
Requires-Dist: cachetools==5.3.3
|
|
16
16
|
Requires-Dist: click==8.1.7
|
|
17
|
-
Requires-Dist: cornflow-client==1.3.
|
|
18
|
-
Requires-Dist: cryptography==
|
|
17
|
+
Requires-Dist: cornflow-client==1.3.6
|
|
18
|
+
Requires-Dist: cryptography==48.0.1
|
|
19
19
|
Requires-Dist: disposable-email-domains==0.0.162
|
|
20
20
|
Requires-Dist: Flask==2.3.2
|
|
21
21
|
Requires-Dist: flask-apispec==0.11.4
|
|
@@ -35,7 +35,7 @@ Requires-Dist: ldap3==2.9.1
|
|
|
35
35
|
Requires-Dist: marshmallow==3.26.2
|
|
36
36
|
Requires-Dist: PuLP==2.9.0
|
|
37
37
|
Requires-Dist: psycopg2==2.9.9
|
|
38
|
-
Requires-Dist: PyJWT==2.
|
|
38
|
+
Requires-Dist: PyJWT==2.13.0
|
|
39
39
|
Requires-Dist: pytups==0.86.2
|
|
40
40
|
Requires-Dist: requests==2.32.4
|
|
41
41
|
Requires-Dist: SQLAlchemy==1.3.21
|
|
@@ -87,8 +87,8 @@ def get_new_roles_to_add(extra_permissions, resources_roles_with_access):
|
|
|
87
87
|
|
|
88
88
|
for role_id in roles_with_access:
|
|
89
89
|
if role_id not in existing_roles:
|
|
90
|
-
if role_id in
|
|
91
|
-
# Create
|
|
90
|
+
if role_id in ROLES_MAP:
|
|
91
|
+
# Create role with its predefined name from ROLES_MAP
|
|
92
92
|
role_name = ROLES_MAP[role_id]
|
|
93
93
|
new_role = RoleModel(
|
|
94
94
|
{
|
|
@@ -7,6 +7,7 @@ from flask import current_app
|
|
|
7
7
|
import hashlib
|
|
8
8
|
from sqlalchemy.dialects.postgresql import JSON, TEXT
|
|
9
9
|
from sqlalchemy import desc, or_
|
|
10
|
+
from sqlalchemy.orm import defer
|
|
10
11
|
from sqlalchemy.sql.expression import false
|
|
11
12
|
|
|
12
13
|
# Imports from internal modules
|
|
@@ -184,7 +185,7 @@ class ExecutionModel(BaseDataModel):
|
|
|
184
185
|
:return: The objects
|
|
185
186
|
:rtype: list(:class:`BaseDataModel`)
|
|
186
187
|
"""
|
|
187
|
-
query = cls.query.filter(cls.deleted_at == None)
|
|
188
|
+
query = cls.query.options(defer(cls.data), defer(cls.checks)).filter(cls.deleted_at == None)
|
|
188
189
|
user_access = int(current_app.config["USER_ACCESS_ALL_OBJECTS"])
|
|
189
190
|
if (
|
|
190
191
|
user is not None
|
|
@@ -207,7 +208,6 @@ class ExecutionModel(BaseDataModel):
|
|
|
207
208
|
cls.checks_and_kpis_only.is_(None),
|
|
208
209
|
)
|
|
209
210
|
)
|
|
210
|
-
# if airflow they also return total_entries = query.count(), for some reason
|
|
211
211
|
|
|
212
212
|
return query.order_by(desc(cls.created_at)).offset(offset).limit(limit).all()
|
|
213
213
|
|
|
@@ -150,6 +150,11 @@ class ExecutionDetailsWithIndicatorsAndLogResponse(
|
|
|
150
150
|
):
|
|
151
151
|
log = fields.Nested(BasicLogSchema, attribute="log_json")
|
|
152
152
|
|
|
153
|
+
class Meta:
|
|
154
|
+
# Exclude 'indicators' from the list endpoint schema: data is deferred in
|
|
155
|
+
# get_all_objects, so accessing obj.data here would trigger N+1 lazy loads.
|
|
156
|
+
exclude = ("indicators",)
|
|
157
|
+
|
|
153
158
|
|
|
154
159
|
class ExecutionStatusEndpointResponse(Schema):
|
|
155
160
|
id = fields.Str()
|
|
@@ -7,7 +7,7 @@ AIRFLOW_BACKEND = 1
|
|
|
7
7
|
DATABRICKS_BACKEND = 2
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
CORNFLOW_VERSION = "1.3.
|
|
10
|
+
CORNFLOW_VERSION = "1.3.6"
|
|
11
11
|
INTERNAL_TOKEN_ISSUER = "cornflow"
|
|
12
12
|
|
|
13
13
|
# endpoints responses for health check
|
|
@@ -99,6 +99,7 @@ DELETE_ACTION = 5
|
|
|
99
99
|
|
|
100
100
|
ALL_DEFAULT_ACTIONS = [GET_ACTION, PATCH_ACTION, POST_ACTION, PUT_ACTION, DELETE_ACTION]
|
|
101
101
|
|
|
102
|
+
DUMMY_ROLE = 0
|
|
102
103
|
VIEWER_ROLE = 1
|
|
103
104
|
PLANNER_ROLE = 2
|
|
104
105
|
ADMIN_ROLE = 3
|
|
@@ -123,6 +124,7 @@ PERMISSION_METHOD_MAP = {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
ROLES_MAP = {
|
|
127
|
+
DUMMY_ROLE: "dummy",
|
|
126
128
|
PLANNER_ROLE: "planner",
|
|
127
129
|
VIEWER_ROLE: "viewer",
|
|
128
130
|
ADMIN_ROLE: "admin",
|
|
@@ -149,7 +151,10 @@ BASE_PERMISSION_ASSIGNATION = [
|
|
|
149
151
|
]
|
|
150
152
|
|
|
151
153
|
EXTRA_PERMISSION_ASSIGNATION = [
|
|
154
|
+
(DUMMY_ROLE, GET_ACTION, "user-detail"),
|
|
155
|
+
(DUMMY_ROLE, PUT_ACTION, "user-detail"),
|
|
152
156
|
(VIEWER_ROLE, PUT_ACTION, "user-detail"),
|
|
157
|
+
(DUMMY_ROLE, GET_ACTION, "user-roles"),
|
|
153
158
|
(VIEWER_ROLE, GET_ACTION, "user-roles"),
|
|
154
159
|
(PLANNER_ROLE, GET_ACTION, "user-roles"),
|
|
155
160
|
(SERVICE_ROLE, GET_ACTION, "user-roles"),
|
|
@@ -249,7 +249,7 @@ class CLITests(TestCase):
|
|
|
249
249
|
result = runner.invoke(cli, ["roles", "init", "-v"])
|
|
250
250
|
self.assertEqual(result.exit_code, 0)
|
|
251
251
|
roles = RoleModel.get_all_objects().all()
|
|
252
|
-
self.assertEqual(len(roles),
|
|
252
|
+
self.assertEqual(len(roles), 5)
|
|
253
253
|
|
|
254
254
|
def test_views_entrypoint(self):
|
|
255
255
|
"""
|
|
@@ -325,9 +325,9 @@ class CLITests(TestCase):
|
|
|
325
325
|
views = ViewModel.get_all_objects().all()
|
|
326
326
|
permissions = PermissionViewRoleModel.get_all_objects().all()
|
|
327
327
|
self.assertEqual(len(actions), 5)
|
|
328
|
-
self.assertEqual(len(roles),
|
|
328
|
+
self.assertEqual(len(roles), 5)
|
|
329
329
|
self.assertEqual(len(views), (len(resources) + len(alarms_resources)))
|
|
330
|
-
self.assertEqual(len(permissions),
|
|
330
|
+
self.assertEqual(len(permissions), 632)
|
|
331
331
|
|
|
332
332
|
def test_permissions_base_command(self):
|
|
333
333
|
"""
|
|
@@ -351,9 +351,9 @@ class CLITests(TestCase):
|
|
|
351
351
|
views = ViewModel.get_all_objects().all()
|
|
352
352
|
permissions = PermissionViewRoleModel.get_all_objects().all()
|
|
353
353
|
self.assertEqual(len(actions), 5)
|
|
354
|
-
self.assertEqual(len(roles),
|
|
354
|
+
self.assertEqual(len(roles), 5)
|
|
355
355
|
self.assertEqual(len(views), (len(resources) + len(alarms_resources)))
|
|
356
|
-
self.assertEqual(len(permissions),
|
|
356
|
+
self.assertEqual(len(permissions), 632)
|
|
357
357
|
|
|
358
358
|
def test_service_entrypoint(self):
|
|
359
359
|
"""
|
|
@@ -12,6 +12,7 @@ from datetime import datetime, timedelta, timezone
|
|
|
12
12
|
from unittest.mock import patch
|
|
13
13
|
|
|
14
14
|
from flask import current_app
|
|
15
|
+
from sqlalchemy import event, inspect as sa_inspect
|
|
15
16
|
from cornflow.app import create_app
|
|
16
17
|
from cornflow.tests import base_test_execution
|
|
17
18
|
|
|
@@ -30,9 +31,11 @@ from cornflow.shared.const import (
|
|
|
30
31
|
VIEWER_ROLE,
|
|
31
32
|
)
|
|
32
33
|
from cornflow.tests.const import (
|
|
34
|
+
DAG_URL,
|
|
33
35
|
EXECUTION_FILES_CLEANUP_URL,
|
|
34
36
|
EXECUTION_FILES_URL,
|
|
35
37
|
EXECUTION_PATH,
|
|
38
|
+
EXECUTION_SOLUTION_PATH,
|
|
36
39
|
EXECUTION_URL_NORUN,
|
|
37
40
|
INSTANCE_PATH,
|
|
38
41
|
INSTANCE_URL,
|
|
@@ -492,3 +495,162 @@ class TestExecutionFilesEndpoint(CustomTestCase):
|
|
|
492
495
|
self.assertEqual("0 files were deleted.", response.json["message"])
|
|
493
496
|
|
|
494
497
|
# endregion
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
class TestExecutionListDataLoading(CustomTestCase):
|
|
501
|
+
"""
|
|
502
|
+
Tests that the execution list endpoint does not load heavy columns from the
|
|
503
|
+
database and returns only the expected basic fields.
|
|
504
|
+
"""
|
|
505
|
+
|
|
506
|
+
def setUp(self):
|
|
507
|
+
super().setUp()
|
|
508
|
+
# Load instance fixture and create a parent instance
|
|
509
|
+
with open(INSTANCE_PATH) as f:
|
|
510
|
+
instance_payload = json.load(f)
|
|
511
|
+
self.instance_id = self.create_new_row(
|
|
512
|
+
INSTANCE_URL, InstanceModel, instance_payload
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
# Load execution fixture and create the execution (without triggering a run)
|
|
516
|
+
with open(EXECUTION_PATH) as f:
|
|
517
|
+
execution_payload = json.load(f)
|
|
518
|
+
execution_payload["instance_id"] = self.instance_id
|
|
519
|
+
self.execution_id = self.create_new_row(
|
|
520
|
+
EXECUTION_URL_NORUN, ExecutionModel, execution_payload
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
# Use a service user to push solution data into the execution via the DAG
|
|
524
|
+
# endpoint so that the `data` column is non-NULL in the database.
|
|
525
|
+
service_token = self.create_service_user()
|
|
526
|
+
with open(EXECUTION_SOLUTION_PATH) as f:
|
|
527
|
+
solution_data = json.load(f)
|
|
528
|
+
self.update_row(
|
|
529
|
+
url=DAG_URL + self.execution_id + "/",
|
|
530
|
+
change={"data": solution_data},
|
|
531
|
+
payload_to_check={},
|
|
532
|
+
check_payload=False,
|
|
533
|
+
token=service_token,
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
def _capture_queries_for_get_all_objects(self):
|
|
537
|
+
captured_queries = []
|
|
538
|
+
|
|
539
|
+
def _listener(conn, cursor, statement, parameters, context, executemany):
|
|
540
|
+
captured_queries.append(statement)
|
|
541
|
+
|
|
542
|
+
engine = db.engine
|
|
543
|
+
event.listen(engine, "before_cursor_execute", _listener)
|
|
544
|
+
try:
|
|
545
|
+
executions = ExecutionModel.get_all_objects(user=self.user)
|
|
546
|
+
finally:
|
|
547
|
+
event.remove(engine, "before_cursor_execute", _listener)
|
|
548
|
+
|
|
549
|
+
return executions, captured_queries
|
|
550
|
+
|
|
551
|
+
def test_data_is_deferred_in_list_via_sqlalchemy_inspect(self):
|
|
552
|
+
executions = ExecutionModel.get_all_objects(user=self.user)
|
|
553
|
+
|
|
554
|
+
self.assertGreater(
|
|
555
|
+
len(executions),
|
|
556
|
+
0,
|
|
557
|
+
"Expected at least one execution to be returned by get_all_objects",
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
for execution in executions:
|
|
561
|
+
state = sa_inspect(execution)
|
|
562
|
+
self.assertIn(
|
|
563
|
+
"data",
|
|
564
|
+
state.unloaded,
|
|
565
|
+
"'data' should be deferred (not loaded eagerly) in the list query.",
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
def test_data_is_not_in_select_via_sql_interception(self):
|
|
569
|
+
executions, captured_queries = self._capture_queries_for_get_all_objects()
|
|
570
|
+
|
|
571
|
+
self.assertGreater(
|
|
572
|
+
len(executions),
|
|
573
|
+
0,
|
|
574
|
+
"Expected at least one execution to be returned by get_all_objects",
|
|
575
|
+
)
|
|
576
|
+
|
|
577
|
+
self.assertTrue(
|
|
578
|
+
len(captured_queries) > 0,
|
|
579
|
+
"No SQL queries were captured; the event listener may not have fired.",
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
data_in_query = any(
|
|
583
|
+
'"data"' in q or " data," in q.lower() or " data " in q.lower()
|
|
584
|
+
for q in captured_queries
|
|
585
|
+
)
|
|
586
|
+
self.assertFalse(
|
|
587
|
+
data_in_query,
|
|
588
|
+
"The SELECT generated by get_all_objects must not include the 'data' column. "
|
|
589
|
+
"Captured queries: " + str(captured_queries),
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
def test_list_endpoint_does_not_return_indicators(self):
|
|
593
|
+
from cornflow.tests.const import EXECUTION_URL
|
|
594
|
+
|
|
595
|
+
response = self.client.get(
|
|
596
|
+
EXECUTION_URL,
|
|
597
|
+
follow_redirects=True,
|
|
598
|
+
headers=self.get_header_with_auth(self.token),
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
self.assertEqual(
|
|
602
|
+
200,
|
|
603
|
+
response.status_code,
|
|
604
|
+
f"GET /execution/ returned unexpected status {response.status_code}",
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
items = response.json
|
|
608
|
+
self.assertIsInstance(items, list)
|
|
609
|
+
self.assertGreater(len(items), 0, "Expected at least one execution in the list")
|
|
610
|
+
|
|
611
|
+
for item in items:
|
|
612
|
+
self.assertNotIn(
|
|
613
|
+
"indicators",
|
|
614
|
+
item,
|
|
615
|
+
"'indicators' must not appear in execution list items.",
|
|
616
|
+
)
|
|
617
|
+
|
|
618
|
+
def test_list_endpoint_returns_basic_fields(self):
|
|
619
|
+
from cornflow.tests.const import EXECUTION_URL
|
|
620
|
+
|
|
621
|
+
response = self.client.get(
|
|
622
|
+
EXECUTION_URL,
|
|
623
|
+
follow_redirects=True,
|
|
624
|
+
headers=self.get_header_with_auth(self.token),
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
self.assertEqual(200, response.status_code)
|
|
628
|
+
|
|
629
|
+
items = response.json
|
|
630
|
+
self.assertIsInstance(items, list)
|
|
631
|
+
self.assertGreater(len(items), 0, "Expected at least one execution in the list")
|
|
632
|
+
|
|
633
|
+
required_fields = [
|
|
634
|
+
"id",
|
|
635
|
+
"name",
|
|
636
|
+
"description",
|
|
637
|
+
"created_at",
|
|
638
|
+
"updated_at",
|
|
639
|
+
"user_id",
|
|
640
|
+
"username",
|
|
641
|
+
"data_hash",
|
|
642
|
+
"state",
|
|
643
|
+
"message",
|
|
644
|
+
"config",
|
|
645
|
+
"instance_id",
|
|
646
|
+
"schema",
|
|
647
|
+
"log",
|
|
648
|
+
]
|
|
649
|
+
|
|
650
|
+
for item in items:
|
|
651
|
+
for field in required_fields:
|
|
652
|
+
self.assertIn(
|
|
653
|
+
field,
|
|
654
|
+
item,
|
|
655
|
+
f"Required field '{field}' is missing from the execution list response.",
|
|
656
|
+
)
|
|
@@ -19,6 +19,8 @@ from cornflow.models import (
|
|
|
19
19
|
)
|
|
20
20
|
from cornflow.shared.const import (
|
|
21
21
|
ADMIN_ROLE,
|
|
22
|
+
ALL_DEFAULT_ROLES,
|
|
23
|
+
DUMMY_ROLE,
|
|
22
24
|
PLANNER_ROLE,
|
|
23
25
|
ROLES_MAP,
|
|
24
26
|
SERVICE_ROLE,
|
|
@@ -82,7 +84,7 @@ class TestRolesListEndpoint(CustomTestCase):
|
|
|
82
84
|
)
|
|
83
85
|
|
|
84
86
|
self.assertEqual(200, response.status_code)
|
|
85
|
-
self.assertEqual(
|
|
87
|
+
self.assertEqual(6, len(response.json))
|
|
86
88
|
|
|
87
89
|
def test_get_no_roles(self):
|
|
88
90
|
for role in ROLES_MAP:
|
|
@@ -254,7 +256,7 @@ class TestUserRolesListEndpoint(CustomTestCase):
|
|
|
254
256
|
self.assertEqual(200, response.status_code)
|
|
255
257
|
self.assertCountEqual(self.payload, response.json)
|
|
256
258
|
|
|
257
|
-
for role in (VIEWER_ROLE, PLANNER_ROLE, SERVICE_ROLE):
|
|
259
|
+
for role in (VIEWER_ROLE, PLANNER_ROLE, SERVICE_ROLE, DUMMY_ROLE):
|
|
258
260
|
self.token = self.create_user_with_role(role)
|
|
259
261
|
user = UserModel.get_one_object(username=f"testuser{role}")
|
|
260
262
|
response = self.client.get(
|
|
@@ -484,18 +486,24 @@ class TestRolesModelMethods(CustomTestCase):
|
|
|
484
486
|
"""
|
|
485
487
|
Tests the get_all_objects method
|
|
486
488
|
"""
|
|
487
|
-
# We expect
|
|
489
|
+
# We expect 5 roles to be present (from ROLES_MAP constant)
|
|
488
490
|
instances = RoleModel.get_all_objects().all()
|
|
489
|
-
self.assertEqual(len(instances),
|
|
491
|
+
self.assertEqual(len(instances), 5)
|
|
490
492
|
|
|
491
493
|
# Check that all the roles from ROLES_MAP are present
|
|
492
494
|
role_names = [role.name for role in instances]
|
|
493
495
|
expected_names = list(ROLES_MAP.values())
|
|
494
496
|
self.assertCountEqual(role_names, expected_names)
|
|
495
497
|
|
|
498
|
+
# The dummy role is registered with its ROLES_MAP name and is not a default role
|
|
499
|
+
dummy_role = RoleModel.get_one_object(idx=DUMMY_ROLE)
|
|
500
|
+
self.assertIsNotNone(dummy_role)
|
|
501
|
+
self.assertEqual(dummy_role.name, "dummy")
|
|
502
|
+
self.assertNotIn(DUMMY_ROLE, ALL_DEFAULT_ROLES)
|
|
503
|
+
|
|
496
504
|
# Test offset parameter - should get all except the first role
|
|
497
505
|
instances = RoleModel.get_all_objects(offset=1).all()
|
|
498
|
-
self.assertEqual(len(instances),
|
|
506
|
+
self.assertEqual(len(instances), 4)
|
|
499
507
|
|
|
500
508
|
# Get the names of all roles except the first one
|
|
501
509
|
remaining_roles = [role.name for role in instances]
|
|
@@ -30,7 +30,13 @@ from cornflow.models import (
|
|
|
30
30
|
UserRoleModel,
|
|
31
31
|
)
|
|
32
32
|
from cornflow.shared import db
|
|
33
|
-
from cornflow.shared.const import
|
|
33
|
+
from cornflow.shared.const import (
|
|
34
|
+
ADMIN_ROLE,
|
|
35
|
+
DUMMY_ROLE,
|
|
36
|
+
SERVICE_ROLE,
|
|
37
|
+
PLANNER_ROLE,
|
|
38
|
+
VIEWER_ROLE,
|
|
39
|
+
)
|
|
34
40
|
from cornflow.tests.const import (
|
|
35
41
|
CASE_PATH,
|
|
36
42
|
CASE_URL,
|
|
@@ -89,6 +95,12 @@ class TestUserEndpoint(TestCase):
|
|
|
89
95
|
password="Tpass_service_user1",
|
|
90
96
|
)
|
|
91
97
|
|
|
98
|
+
self.dummy = dict(
|
|
99
|
+
username="aDummyUser",
|
|
100
|
+
email="dummy@test.com",
|
|
101
|
+
password="Testpassword1!",
|
|
102
|
+
)
|
|
103
|
+
|
|
92
104
|
self.login_keys = ["username", "password"]
|
|
93
105
|
self.items_to_check = ["email", "username", "id"]
|
|
94
106
|
self.modifiable_items = [
|
|
@@ -106,6 +118,7 @@ class TestUserEndpoint(TestCase):
|
|
|
106
118
|
self.admin,
|
|
107
119
|
self.admin_2,
|
|
108
120
|
self.service_user,
|
|
121
|
+
self.dummy,
|
|
109
122
|
]
|
|
110
123
|
|
|
111
124
|
for u_data in self.payloads:
|
|
@@ -142,6 +155,17 @@ class TestUserEndpoint(TestCase):
|
|
|
142
155
|
)
|
|
143
156
|
user_role.save()
|
|
144
157
|
|
|
158
|
+
if "dummy" in u_data["email"]:
|
|
159
|
+
user_role = UserRoleModel(
|
|
160
|
+
{"user_id": u_data["id"], "role_id": DUMMY_ROLE}
|
|
161
|
+
)
|
|
162
|
+
user_role.save()
|
|
163
|
+
|
|
164
|
+
UserRoleModel.query.filter_by(
|
|
165
|
+
user_id=u_data["id"], role_id=PLANNER_ROLE
|
|
166
|
+
).delete()
|
|
167
|
+
db.session.commit()
|
|
168
|
+
|
|
145
169
|
db.session.commit()
|
|
146
170
|
register_dag_permissions_command(verbose=False)
|
|
147
171
|
|
|
@@ -391,6 +415,74 @@ class TestUserEndpoint(TestCase):
|
|
|
391
415
|
response = self.log_in(self.planner)
|
|
392
416
|
self.assertEqual(False, response.json["change_password"])
|
|
393
417
|
|
|
418
|
+
def test_dummy_gets_own_user_detail(self):
|
|
419
|
+
# the dummy role can read its own user info
|
|
420
|
+
response = self.get_user(self.dummy, self.dummy)
|
|
421
|
+
self.assertEqual(200, response.status_code)
|
|
422
|
+
self.assertEqual(self.dummy["id"], response.json["id"])
|
|
423
|
+
|
|
424
|
+
def test_dummy_cannot_get_other_user_detail(self):
|
|
425
|
+
# the dummy role can not read another user's info
|
|
426
|
+
response = self.get_user(self.dummy, self.planner)
|
|
427
|
+
self.assertEqual(400, response.status_code)
|
|
428
|
+
self.assertTrue("error" in response.json)
|
|
429
|
+
|
|
430
|
+
def test_dummy_edits_own_user_info(self):
|
|
431
|
+
# the dummy role can edit its own user info
|
|
432
|
+
payload = {"first_name": "Dummy", "last_name": "User"}
|
|
433
|
+
response = self.modify_info(self.dummy, self.dummy, payload)
|
|
434
|
+
self.assertEqual(200, response.status_code)
|
|
435
|
+
self.assertEqual("Updated correctly", response.json["message"])
|
|
436
|
+
|
|
437
|
+
response = self.get_user(self.dummy, self.dummy)
|
|
438
|
+
self.assertEqual(200, response.status_code)
|
|
439
|
+
self.assertEqual("Dummy", response.json["first_name"])
|
|
440
|
+
|
|
441
|
+
def test_dummy_cannot_edit_other_user_info(self):
|
|
442
|
+
# the dummy role can not edit another user's info
|
|
443
|
+
payload = {"first_name": "Nope"}
|
|
444
|
+
response = self.modify_info(self.dummy, self.planner, payload)
|
|
445
|
+
self.assertEqual(403, response.status_code)
|
|
446
|
+
self.assertTrue("error" in response.json)
|
|
447
|
+
|
|
448
|
+
def test_dummy_cannot_get_all_users(self):
|
|
449
|
+
# the dummy role can not list all the users
|
|
450
|
+
response = self.get_user(self.dummy)
|
|
451
|
+
self.assertEqual(403, response.status_code)
|
|
452
|
+
self.assertTrue("error" in response.json)
|
|
453
|
+
|
|
454
|
+
def test_dummy_cannot_delete_user(self):
|
|
455
|
+
# the dummy role has no delete permission, even on itself
|
|
456
|
+
response = self.delete_user(self.dummy, self.dummy)
|
|
457
|
+
self.assertEqual(403, response.status_code)
|
|
458
|
+
|
|
459
|
+
def test_dummy_cannot_get_instances(self):
|
|
460
|
+
# the dummy role can not access unrelated endpoints
|
|
461
|
+
token = self.log_in(self.dummy).json["token"]
|
|
462
|
+
response = self.client.get(
|
|
463
|
+
INSTANCE_URL,
|
|
464
|
+
follow_redirects=True,
|
|
465
|
+
headers={
|
|
466
|
+
"Content-Type": "application/json",
|
|
467
|
+
"Authorization": "Bearer " + token,
|
|
468
|
+
},
|
|
469
|
+
)
|
|
470
|
+
self.assertEqual(403, response.status_code)
|
|
471
|
+
|
|
472
|
+
def test_dummy_cannot_post_instance(self):
|
|
473
|
+
# permission is denied before any payload validation
|
|
474
|
+
token = self.log_in(self.dummy).json["token"]
|
|
475
|
+
response = self.client.post(
|
|
476
|
+
INSTANCE_URL,
|
|
477
|
+
data=json.dumps({}),
|
|
478
|
+
follow_redirects=True,
|
|
479
|
+
headers={
|
|
480
|
+
"Content-Type": "application/json",
|
|
481
|
+
"Authorization": "Bearer " + token,
|
|
482
|
+
},
|
|
483
|
+
)
|
|
484
|
+
self.assertEqual(403, response.status_code)
|
|
485
|
+
|
|
394
486
|
|
|
395
487
|
class TestUserModel(TestCase):
|
|
396
488
|
def create_app(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cornflow
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.6
|
|
4
4
|
Summary: cornflow is an open source multi-solver optimization server with a REST API built using flask.
|
|
5
5
|
Home-page: https://github.com/baobabsoluciones/cornflow
|
|
6
6
|
Author: baobab soluciones
|
|
@@ -14,8 +14,8 @@ Requires-Dist: alembic==1.9.2
|
|
|
14
14
|
Requires-Dist: apispec==6.3.0
|
|
15
15
|
Requires-Dist: cachetools==5.3.3
|
|
16
16
|
Requires-Dist: click==8.1.7
|
|
17
|
-
Requires-Dist: cornflow-client==1.3.
|
|
18
|
-
Requires-Dist: cryptography==
|
|
17
|
+
Requires-Dist: cornflow-client==1.3.6
|
|
18
|
+
Requires-Dist: cryptography==48.0.1
|
|
19
19
|
Requires-Dist: disposable-email-domains==0.0.162
|
|
20
20
|
Requires-Dist: Flask==2.3.2
|
|
21
21
|
Requires-Dist: flask-apispec==0.11.4
|
|
@@ -35,7 +35,7 @@ Requires-Dist: ldap3==2.9.1
|
|
|
35
35
|
Requires-Dist: marshmallow==3.26.2
|
|
36
36
|
Requires-Dist: PuLP==2.9.0
|
|
37
37
|
Requires-Dist: psycopg2==2.9.9
|
|
38
|
-
Requires-Dist: PyJWT==2.
|
|
38
|
+
Requires-Dist: PyJWT==2.13.0
|
|
39
39
|
Requires-Dist: pytups==0.86.2
|
|
40
40
|
Requires-Dist: requests==2.32.4
|
|
41
41
|
Requires-Dist: SQLAlchemy==1.3.21
|
|
@@ -2,8 +2,8 @@ alembic==1.9.2
|
|
|
2
2
|
apispec==6.3.0
|
|
3
3
|
cachetools==5.3.3
|
|
4
4
|
click==8.1.7
|
|
5
|
-
cornflow-client==1.3.
|
|
6
|
-
cryptography==
|
|
5
|
+
cornflow-client==1.3.6
|
|
6
|
+
cryptography==48.0.1
|
|
7
7
|
disposable-email-domains==0.0.162
|
|
8
8
|
Flask==2.3.2
|
|
9
9
|
flask-apispec==0.11.4
|
|
@@ -21,7 +21,7 @@ ldap3==2.9.1
|
|
|
21
21
|
marshmallow==3.26.2
|
|
22
22
|
PuLP==2.9.0
|
|
23
23
|
psycopg2==2.9.9
|
|
24
|
-
PyJWT==2.
|
|
24
|
+
PyJWT==2.13.0
|
|
25
25
|
pytups==0.86.2
|
|
26
26
|
requests==2.32.4
|
|
27
27
|
SQLAlchemy==1.3.21
|
|
@@ -2,8 +2,8 @@ alembic==1.9.2
|
|
|
2
2
|
apispec==6.3.0
|
|
3
3
|
cachetools==5.3.3
|
|
4
4
|
click==8.1.7
|
|
5
|
-
cornflow-client==1.3.
|
|
6
|
-
cryptography==
|
|
5
|
+
cornflow-client==1.3.6
|
|
6
|
+
cryptography==48.0.1
|
|
7
7
|
disposable-email-domains==0.0.162
|
|
8
8
|
Flask==2.3.2
|
|
9
9
|
flask-apispec==0.11.4
|
|
@@ -23,7 +23,7 @@ ldap3==2.9.1
|
|
|
23
23
|
marshmallow==3.26.2
|
|
24
24
|
PuLP==2.9.0
|
|
25
25
|
psycopg2==2.9.9
|
|
26
|
-
PyJWT==2.
|
|
26
|
+
PyJWT==2.13.0
|
|
27
27
|
pytups==0.86.2
|
|
28
28
|
requests==2.32.4
|
|
29
29
|
SQLAlchemy==1.3.21
|
|
@@ -9,7 +9,7 @@ with open("requirements.txt", "r") as fh:
|
|
|
9
9
|
|
|
10
10
|
setuptools.setup(
|
|
11
11
|
name="cornflow",
|
|
12
|
-
version="1.3.
|
|
12
|
+
version="1.3.6",
|
|
13
13
|
author="baobab soluciones",
|
|
14
14
|
author_email="cornflow@baobabsoluciones.es",
|
|
15
15
|
description="cornflow is an open source multi-solver optimization server with a REST API built using flask.",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|