cornflow 1.0.8a3__tar.gz → 1.0.10a1__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.0.8a3/cornflow.egg-info → cornflow-1.0.10a1}/PKG-INFO +1 -1
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/__init__.py +1 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/actions.py +1 -2
- cornflow-1.0.10a1/cornflow/cli/users.py +77 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/config.py +4 -2
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/authentication/auth.py +72 -19
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/licenses.py +1 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/custom_test_case.py +1 -3
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_cli.py +143 -3
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_licenses.py +2 -2
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_token.py +35 -4
- {cornflow-1.0.8a3 → cornflow-1.0.10a1/cornflow.egg-info}/PKG-INFO +1 -1
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow.egg-info/requires.txt +5 -5
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/setup.py +1 -1
- cornflow-1.0.8a3/cornflow/cli/users.py +0 -32
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/MANIFEST.in +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/README.rst +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/airflow_config/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/airflow_config/airflow_local_settings.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/airflow_config/plugins/XCom/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/airflow_config/plugins/XCom/gce_xcom_backend.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/airflow_config/plugins/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/airflow_config/webserver_ldap.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/app.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/arguments.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/config.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/migrations.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/permissions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/roles.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/schemas.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/service.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/api_generator.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/endpoint_tools.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/models_tools.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/schema_generator.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/schemas_tools.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/tools/tools.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/utils.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/cli/views.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/access.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/actions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/cleanup.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/dag.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/permissions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/roles.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/schemas.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/users.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/commands/views.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/action.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/apiview.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/case.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/dag.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/data_check.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/example_data.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/execution.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/health.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/instance.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/licenses.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/login.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/main_alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/meta_resource.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/permission.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/roles.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/schemas.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/signup.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/tables.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/token.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/user.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/endpoints/user_role.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/gunicorn.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/README +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/alembic.ini +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/env.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/script.py.mako +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/00757b557b02_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/1af47a419bbd_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/4aac5e0c6e66_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/7c3ea5ab5501_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/a472b5ad50b7_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/c2db9409cb5f_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/c8a6c762e818_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/ca449af8034c_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/d0e0700dcd8e_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/d1b5be1f0549_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/e1a50dae1ac9_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/e937a5234ce4_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/ebdd955fcc5e_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/migrations/versions/f3bee20314a2_.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/action.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/base_data_model.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/case.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/dag.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/dag_permissions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/execution.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/instance.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/main_alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/meta_models.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/permissions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/role.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/user.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/user_role.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/models/view.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/action.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/case.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/common.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/dag.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/example_data.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/execution.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/health.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/instance.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/main_alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/model_json.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/patch.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/permissions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/query.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/role.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/schemas.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/solution_log.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/tables.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/user.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/user_role.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/schemas/view.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/authentication/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/authentication/decorators.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/authentication/ldap.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/compress.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/const.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/email.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/exceptions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/log_config.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/query_tools.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/utils.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/utils_tables.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/shared/validators.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/const.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/custom_liveServer.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/integration/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/integration/test_commands.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/integration/test_cornflowclient.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/ldap/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/ldap/test_ldap_authentication.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/__init__.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_actions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_apiview.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_cases.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_commands.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_dags.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_data_checks.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_example_data.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_executions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_generate_from_schema.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_health.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_instances.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_instances_file.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_log_in.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_main_alarms.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_permissions.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_roles.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_schema_from_models.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_schemas.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_sign_up.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_tables.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/test_users.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow/tests/unit/tools.py +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow.egg-info/SOURCES.txt +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow.egg-info/dependency_links.txt +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow.egg-info/entry_points.txt +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/cornflow.egg-info/top_level.txt +0 -0
- {cornflow-1.0.8a3 → cornflow-1.0.10a1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 1.2
|
2
2
|
Name: cornflow
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.10a1
|
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
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import click
|
2
|
+
|
3
|
+
from cornflow.cli.arguments import username, password, email, verbose
|
4
|
+
from cornflow.cli.utils import get_app
|
5
|
+
from cornflow.commands import create_user_with_role
|
6
|
+
from cornflow.models import UserModel
|
7
|
+
from cornflow.shared.authentication.auth import BIAuth
|
8
|
+
from cornflow.shared.const import SERVICE_ROLE, VIEWER_ROLE
|
9
|
+
from cornflow.shared.exceptions import (
|
10
|
+
ObjectDoesNotExist,
|
11
|
+
NoPermission,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
@click.group(name="users", help="Commands to manage the users")
|
16
|
+
def users():
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
@click.group(name="create", help="Create a user")
|
21
|
+
def create():
|
22
|
+
pass
|
23
|
+
|
24
|
+
|
25
|
+
users.add_command(create)
|
26
|
+
|
27
|
+
|
28
|
+
@create.command(name="service", help="Create a service user")
|
29
|
+
@username
|
30
|
+
@password
|
31
|
+
@email
|
32
|
+
@verbose
|
33
|
+
def create_service_user(username, password, email, verbose):
|
34
|
+
app = get_app()
|
35
|
+
with app.app_context():
|
36
|
+
create_user_with_role(
|
37
|
+
username, email, password, "service user", SERVICE_ROLE, verbose=verbose
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
@create.command(name="viewer", help="Create a viewer user")
|
42
|
+
@username
|
43
|
+
@password
|
44
|
+
@email
|
45
|
+
@verbose
|
46
|
+
def create_viewer_user(username, password, email, verbose):
|
47
|
+
app = get_app()
|
48
|
+
with app.app_context():
|
49
|
+
create_user_with_role(
|
50
|
+
username, email, password, "viewer user", VIEWER_ROLE, verbose=verbose
|
51
|
+
)
|
52
|
+
|
53
|
+
|
54
|
+
@create.command(
|
55
|
+
name="token",
|
56
|
+
help="Creates a token for a user that is never going to expire. This token can only be used on BI endpoints",
|
57
|
+
)
|
58
|
+
@click.option(
|
59
|
+
"--idx", "-i", type=int, help="The id of the user to generate the token for"
|
60
|
+
)
|
61
|
+
@username
|
62
|
+
@password
|
63
|
+
def create_unexpiring_token(idx, username, password):
|
64
|
+
app = get_app()
|
65
|
+
with app.app_context():
|
66
|
+
user = UserModel.get_one_object(id=idx)
|
67
|
+
asking_user = UserModel.get_one_user_by_username(username)
|
68
|
+
|
69
|
+
if not asking_user.check_hash(password) or not asking_user.is_service_user():
|
70
|
+
raise NoPermission("The asking user has no permissions to generate tokens")
|
71
|
+
|
72
|
+
if not user:
|
73
|
+
raise ObjectDoesNotExist("User does not exist")
|
74
|
+
|
75
|
+
token = BIAuth.generate_token(idx)
|
76
|
+
click.echo(token)
|
77
|
+
return True
|
@@ -6,7 +6,8 @@ from apispec.ext.marshmallow import MarshmallowPlugin
|
|
6
6
|
|
7
7
|
class DefaultConfig(object):
|
8
8
|
SERVICE_NAME = os.getenv("SERVICE_NAME", "Cornflow")
|
9
|
-
|
9
|
+
SECRET_TOKEN_KEY = os.getenv("SECRET_KEY")
|
10
|
+
SECRET_BI_KEY = os.getenv("SECRET_BI_KEY")
|
10
11
|
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL", "sqlite:///cornflow.db")
|
11
12
|
AIRFLOW_URL = os.getenv("AIRFLOW_URL")
|
12
13
|
AIRFLOW_USER = os.getenv("AIRFLOW_USER")
|
@@ -91,7 +92,8 @@ class Testing(DefaultConfig):
|
|
91
92
|
DEBUG = False
|
92
93
|
TESTING = True
|
93
94
|
PROPAGATE_EXCEPTIONS = True
|
94
|
-
|
95
|
+
SECRET_TOKEN_KEY = "TESTINGSECRETKEY"
|
96
|
+
SECRET_BI_KEY = "THISISANOTHERKEY"
|
95
97
|
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL", "sqlite:///cornflow_test.db")
|
96
98
|
AIRFLOW_URL = os.getenv("AIRFLOW_URL", "http://localhost:8080")
|
97
99
|
PRESERVE_CONTEXT_ON_EXCEPTION = False
|
@@ -99,8 +99,7 @@ class Auth:
|
|
99
99
|
if user_id is None:
|
100
100
|
err = "The user id passed to generate the token is not valid."
|
101
101
|
raise InvalidUsage(
|
102
|
-
err,
|
103
|
-
log_txt="Error while trying to generate token. " + err
|
102
|
+
err, log_txt="Error while trying to generate token. " + err
|
104
103
|
)
|
105
104
|
|
106
105
|
payload = {
|
@@ -109,7 +108,9 @@ class Auth:
|
|
109
108
|
"sub": user_id,
|
110
109
|
}
|
111
110
|
|
112
|
-
return jwt.encode(
|
111
|
+
return jwt.encode(
|
112
|
+
payload, current_app.config["SECRET_TOKEN_KEY"], algorithm="HS256"
|
113
|
+
)
|
113
114
|
|
114
115
|
@staticmethod
|
115
116
|
def decode_token(token: str = None) -> dict:
|
@@ -123,27 +124,26 @@ class Auth:
|
|
123
124
|
if token is None:
|
124
125
|
err = "The provided token is not valid."
|
125
126
|
raise InvalidUsage(
|
126
|
-
err,
|
127
|
-
log_txt="Error while trying to decode token. " + err
|
127
|
+
err, log_txt="Error while trying to decode token. " + err
|
128
128
|
)
|
129
129
|
try:
|
130
130
|
payload = jwt.decode(
|
131
|
-
token, current_app.config["
|
131
|
+
token, current_app.config["SECRET_TOKEN_KEY"], algorithms="HS256"
|
132
132
|
)
|
133
133
|
return {"user_id": payload["sub"]}
|
134
134
|
except jwt.ExpiredSignatureError:
|
135
135
|
raise InvalidCredentials(
|
136
136
|
"The token has expired, please login again",
|
137
|
-
log_txt="Error while trying to decode token. The token has expired."
|
137
|
+
log_txt="Error while trying to decode token. The token has expired.",
|
138
138
|
)
|
139
139
|
except jwt.InvalidTokenError:
|
140
140
|
raise InvalidCredentials(
|
141
141
|
"Invalid token, please try again with a new token",
|
142
|
-
log_txt="Error while trying to decode token. The token is invalid."
|
142
|
+
log_txt="Error while trying to decode token. The token is invalid.",
|
143
143
|
)
|
144
144
|
|
145
145
|
def validate_oid_token(
|
146
|
-
|
146
|
+
self, token: str, client_id: str, tenant_id: str, issuer: str, provider: int
|
147
147
|
) -> dict:
|
148
148
|
"""
|
149
149
|
This method takes a token issued by an OID provider, the relevant information about the OID provider
|
@@ -172,12 +172,12 @@ class Auth:
|
|
172
172
|
except jwt.ExpiredSignatureError:
|
173
173
|
raise InvalidCredentials(
|
174
174
|
"The token has expired, please login again",
|
175
|
-
log_txt="Error while trying to validate a token. The token has expired.
|
175
|
+
log_txt="Error while trying to validate a token. The token has expired.",
|
176
176
|
)
|
177
177
|
except jwt.InvalidTokenError:
|
178
178
|
raise InvalidCredentials(
|
179
179
|
"Invalid token, please try again with a new token",
|
180
|
-
log_txt="Error while trying to validate a token. The token is not valid.
|
180
|
+
log_txt="Error while trying to validate a token. The token is not valid.",
|
181
181
|
)
|
182
182
|
|
183
183
|
@staticmethod
|
@@ -191,12 +191,14 @@ class Auth:
|
|
191
191
|
:rtype: str
|
192
192
|
"""
|
193
193
|
if headers is None:
|
194
|
-
raise InvalidUsage(
|
194
|
+
raise InvalidUsage(
|
195
|
+
log_txt="Error while trying to get a token from header. The header is invalid."
|
196
|
+
)
|
195
197
|
|
196
198
|
if "Authorization" not in headers:
|
197
199
|
raise InvalidCredentials(
|
198
200
|
"Auth token is not available",
|
199
|
-
log_txt="Error while trying to get a token from header. The auth token is not available."
|
201
|
+
log_txt="Error while trying to get a token from header. The auth token is not available.",
|
200
202
|
)
|
201
203
|
auth_header = headers.get("Authorization")
|
202
204
|
if not auth_header:
|
@@ -206,8 +208,7 @@ class Auth:
|
|
206
208
|
except Exception as e:
|
207
209
|
err = f"The authorization header has a bad syntax: {e}"
|
208
210
|
raise InvalidCredentials(
|
209
|
-
err,
|
210
|
-
log_txt=f"Error while trying to get a token from header. " + err
|
211
|
+
err, log_txt=f"Error while trying to get a token from header. " + err
|
211
212
|
)
|
212
213
|
|
213
214
|
def get_user_from_header(self, headers: Headers = None) -> UserModel:
|
@@ -222,8 +223,7 @@ class Auth:
|
|
222
223
|
if headers is None:
|
223
224
|
err = "Headers are missing from the request. Authentication was not possible to perform."
|
224
225
|
raise InvalidUsage(
|
225
|
-
err,
|
226
|
-
log_txt="Error while trying to get user from header. " + err
|
226
|
+
err, log_txt="Error while trying to get user from header. " + err
|
227
227
|
)
|
228
228
|
token = self.get_token_from_header(headers)
|
229
229
|
data = self.decode_token(token)
|
@@ -232,8 +232,7 @@ class Auth:
|
|
232
232
|
if user is None:
|
233
233
|
err = "User does not exist, invalid token."
|
234
234
|
raise ObjectDoesNotExist(
|
235
|
-
err,
|
236
|
-
log_txt="Error while trying to get user from header. " + err
|
235
|
+
err, log_txt="Error while trying to get user from header. " + err
|
237
236
|
)
|
238
237
|
return user
|
239
238
|
|
@@ -460,3 +459,57 @@ class Auth:
|
|
460
459
|
kid = self._get_key_id(token)
|
461
460
|
jwk = self._get_jwk(kid, tenant_id, provider)
|
462
461
|
return self._rsa_pem_from_jwk(jwk)
|
462
|
+
|
463
|
+
|
464
|
+
class BIAuth(Auth):
|
465
|
+
def __init__(self, user_model=UserModel):
|
466
|
+
super().__init__(user_model)
|
467
|
+
|
468
|
+
@staticmethod
|
469
|
+
def decode_token(token: str = None) -> dict:
|
470
|
+
"""
|
471
|
+
Decodes a given JSON Web token and extracts the sub from it to give it back.
|
472
|
+
|
473
|
+
:param str token: the given JSON Web Token
|
474
|
+
:return: the sub field of the token as the user_id
|
475
|
+
:rtype: dict
|
476
|
+
"""
|
477
|
+
if token is None:
|
478
|
+
err = "The provided token is not valid."
|
479
|
+
raise InvalidUsage(
|
480
|
+
err, log_txt="Error while trying to decode token. " + err
|
481
|
+
)
|
482
|
+
try:
|
483
|
+
payload = jwt.decode(
|
484
|
+
token, current_app.config["SECRET_BI_KEY"], algorithms="HS256"
|
485
|
+
)
|
486
|
+
return {"user_id": payload["sub"]}
|
487
|
+
except jwt.InvalidTokenError:
|
488
|
+
raise InvalidCredentials(
|
489
|
+
"Invalid token, please try again with a new token",
|
490
|
+
log_txt="Error while trying to decode token. The token is invalid.",
|
491
|
+
)
|
492
|
+
|
493
|
+
@staticmethod
|
494
|
+
def generate_token(user_id: int = None) -> str:
|
495
|
+
"""
|
496
|
+
Generates a token given a user_id with a duration of one day
|
497
|
+
|
498
|
+
:param int user_id: user code to be encoded in the token to identify the user afterward.
|
499
|
+
:return: the generated token
|
500
|
+
:rtype: str
|
501
|
+
"""
|
502
|
+
if user_id is None:
|
503
|
+
err = "The user id passed to generate the token is not valid."
|
504
|
+
raise InvalidUsage(
|
505
|
+
err, log_txt="Error while trying to generate token. " + err
|
506
|
+
)
|
507
|
+
|
508
|
+
payload = {
|
509
|
+
"iat": datetime.utcnow(),
|
510
|
+
"sub": user_id,
|
511
|
+
}
|
512
|
+
|
513
|
+
return jwt.encode(
|
514
|
+
payload, current_app.config["SECRET_BI_KEY"], algorithm="HS256"
|
515
|
+
)
|
@@ -65,6 +65,7 @@ def get_licenses_summary():
|
|
65
65
|
:return: a list of dicts with library, license, version, author, description, home page and license text.
|
66
66
|
"""
|
67
67
|
license_list = []
|
68
|
+
# TODO: pkg_resources.working_set is deprecated, find a better way to get the list of packages
|
68
69
|
for pkg in sorted(pkg_resources.working_set, key=lambda x: str(x).lower()):
|
69
70
|
license_list += [
|
70
71
|
{
|
@@ -101,7 +101,6 @@ class CustomTestCase(TestCase):
|
|
101
101
|
|
102
102
|
@staticmethod
|
103
103
|
def assign_role(user_id, role_id):
|
104
|
-
|
105
104
|
if UserRoleModel.check_if_role_assigned(user_id, role_id):
|
106
105
|
user_role = UserRoleModel.query.filter_by(
|
107
106
|
user_id=user_id, role_id=role_id
|
@@ -288,7 +287,6 @@ class CustomTestCase(TestCase):
|
|
288
287
|
self.assertEqual(payload_to_check["solution"], row.json["solution"])
|
289
288
|
|
290
289
|
def delete_row(self, url):
|
291
|
-
|
292
290
|
response = self.client.delete(
|
293
291
|
url, follow_redirects=True, headers=self.get_header_with_auth(self.token)
|
294
292
|
)
|
@@ -733,7 +731,7 @@ class LoginTestCases:
|
|
733
731
|
self.assertEqual(str, type(self.response.json["token"]))
|
734
732
|
decoded_token = jwt.decode(
|
735
733
|
self.response.json["token"],
|
736
|
-
current_app.config["
|
734
|
+
current_app.config["SECRET_TOKEN_KEY"],
|
737
735
|
algorithms="HS256",
|
738
736
|
)
|
739
737
|
|
@@ -2,17 +2,19 @@ import configparser
|
|
2
2
|
import os
|
3
3
|
|
4
4
|
from click.testing import CliRunner
|
5
|
+
from flask_testing import TestCase
|
6
|
+
|
5
7
|
from cornflow.app import create_app
|
6
8
|
from cornflow.cli import cli
|
7
|
-
from cornflow.models import UserModel
|
8
9
|
from cornflow.models import (
|
9
10
|
ActionModel,
|
10
11
|
RoleModel,
|
11
12
|
ViewModel,
|
12
13
|
PermissionViewRoleModel,
|
13
14
|
)
|
15
|
+
from cornflow.models import UserModel
|
14
16
|
from cornflow.shared import db
|
15
|
-
from
|
17
|
+
from cornflow.shared.exceptions import NoPermission, ObjectDoesNotExist
|
16
18
|
|
17
19
|
|
18
20
|
class CLITests(TestCase):
|
@@ -208,6 +210,7 @@ class CLITests(TestCase):
|
|
208
210
|
|
209
211
|
def test_service_user_command(self):
|
210
212
|
runner = CliRunner()
|
213
|
+
self.test_roles_init_command()
|
211
214
|
result = runner.invoke(
|
212
215
|
cli,
|
213
216
|
[
|
@@ -222,7 +225,144 @@ class CLITests(TestCase):
|
|
222
225
|
"test@test.org",
|
223
226
|
],
|
224
227
|
)
|
225
|
-
self.assertEqual(result.exit_code,
|
228
|
+
self.assertEqual(result.exit_code, 0)
|
226
229
|
user = UserModel.get_one_user_by_email("test@test.org")
|
227
230
|
self.assertEqual(user.username, "test")
|
228
231
|
self.assertEqual(user.email, "test@test.org")
|
232
|
+
self.assertEqual(user.roles, {4: "service"})
|
233
|
+
self.assertTrue(user.is_service_user())
|
234
|
+
|
235
|
+
def test_viewer_user_command(self):
|
236
|
+
runner = CliRunner()
|
237
|
+
self.test_roles_init_command()
|
238
|
+
result = runner.invoke(
|
239
|
+
cli,
|
240
|
+
[
|
241
|
+
"users",
|
242
|
+
"create",
|
243
|
+
"viewer",
|
244
|
+
"-u",
|
245
|
+
"test",
|
246
|
+
"-p",
|
247
|
+
"testPassword1!",
|
248
|
+
"-e",
|
249
|
+
"test@test.org",
|
250
|
+
],
|
251
|
+
)
|
252
|
+
|
253
|
+
self.assertEqual(result.exit_code, 0)
|
254
|
+
user = UserModel.get_one_user_by_email("test@test.org")
|
255
|
+
self.assertEqual(user.username, "test")
|
256
|
+
self.assertEqual(user.email, "test@test.org")
|
257
|
+
self.assertEqual(user.roles, {1: "viewer"})
|
258
|
+
self.assertFalse(user.is_service_user())
|
259
|
+
|
260
|
+
def test_generate_token(self):
|
261
|
+
runner = CliRunner()
|
262
|
+
|
263
|
+
self.test_roles_init_command()
|
264
|
+
|
265
|
+
result = runner.invoke(
|
266
|
+
cli,
|
267
|
+
[
|
268
|
+
"users",
|
269
|
+
"create",
|
270
|
+
"viewer",
|
271
|
+
"-u",
|
272
|
+
"viewer_user",
|
273
|
+
"-p",
|
274
|
+
"testPassword1!",
|
275
|
+
"-e",
|
276
|
+
"viewer@test.org",
|
277
|
+
],
|
278
|
+
)
|
279
|
+
|
280
|
+
self.assertEqual(result.exit_code, 0)
|
281
|
+
|
282
|
+
user_id = UserModel.get_one_user_by_username("viewer_user").id
|
283
|
+
|
284
|
+
result = runner.invoke(
|
285
|
+
cli,
|
286
|
+
[
|
287
|
+
"users",
|
288
|
+
"create",
|
289
|
+
"service",
|
290
|
+
"-u",
|
291
|
+
"test",
|
292
|
+
"-p",
|
293
|
+
"testPassword1!",
|
294
|
+
"-e",
|
295
|
+
"test@test.org",
|
296
|
+
],
|
297
|
+
)
|
298
|
+
|
299
|
+
self.assertEqual(result.exit_code, 0)
|
300
|
+
|
301
|
+
result = runner.invoke(
|
302
|
+
cli,
|
303
|
+
[
|
304
|
+
"users",
|
305
|
+
"create",
|
306
|
+
"token",
|
307
|
+
"-i",
|
308
|
+
user_id,
|
309
|
+
"-u",
|
310
|
+
"test",
|
311
|
+
"-p",
|
312
|
+
"testPassword1!",
|
313
|
+
],
|
314
|
+
)
|
315
|
+
|
316
|
+
self.assertIn("ey", result.output)
|
317
|
+
|
318
|
+
result = runner.invoke(
|
319
|
+
cli,
|
320
|
+
[
|
321
|
+
"users",
|
322
|
+
"create",
|
323
|
+
"token",
|
324
|
+
"-i",
|
325
|
+
user_id,
|
326
|
+
"-u",
|
327
|
+
"test",
|
328
|
+
"-p",
|
329
|
+
"Otherpassword",
|
330
|
+
],
|
331
|
+
)
|
332
|
+
|
333
|
+
self.assertEqual(result.exit_code, 1)
|
334
|
+
self.assertIsInstance(result.exception, NoPermission)
|
335
|
+
|
336
|
+
result = runner.invoke(
|
337
|
+
cli,
|
338
|
+
[
|
339
|
+
"users",
|
340
|
+
"create",
|
341
|
+
"token",
|
342
|
+
"-i",
|
343
|
+
user_id,
|
344
|
+
"-u",
|
345
|
+
"viewer_user",
|
346
|
+
"-p",
|
347
|
+
"testPassword1!",
|
348
|
+
],
|
349
|
+
)
|
350
|
+
|
351
|
+
self.assertIsInstance(result.exception, NoPermission)
|
352
|
+
|
353
|
+
result = runner.invoke(
|
354
|
+
cli,
|
355
|
+
[
|
356
|
+
"users",
|
357
|
+
"create",
|
358
|
+
"token",
|
359
|
+
"-i",
|
360
|
+
100,
|
361
|
+
"-u",
|
362
|
+
"test",
|
363
|
+
"-p",
|
364
|
+
"testPassword1!",
|
365
|
+
],
|
366
|
+
)
|
367
|
+
|
368
|
+
self.assertIsInstance(result.exception, ObjectDoesNotExist)
|
@@ -11,9 +11,9 @@ class TestLicensesListEndpoint(CustomTestCase):
|
|
11
11
|
requirements = content.split("\n")
|
12
12
|
|
13
13
|
requirements = [
|
14
|
-
r.split("=")[0].split(">")[0].split("<")[0].lower()
|
14
|
+
r.split("=")[0].split(">")[0].split("<")[0].split("@")[0].lower()
|
15
15
|
for r in requirements
|
16
|
-
if r != ""
|
16
|
+
if r != "" and not r.startswith("#")
|
17
17
|
]
|
18
18
|
return requirements
|
19
19
|
|
@@ -1,16 +1,16 @@
|
|
1
1
|
"""
|
2
2
|
Unit test for the token endpoint
|
3
3
|
"""
|
4
|
+
import json
|
4
5
|
|
5
|
-
# Import from libraries
|
6
6
|
from flask import current_app
|
7
|
-
import json
|
8
7
|
|
9
|
-
# Import from internal modules
|
10
8
|
from cornflow.models import UserModel
|
11
9
|
from cornflow.shared import db
|
12
|
-
from cornflow.
|
10
|
+
from cornflow.shared.authentication.auth import BIAuth, Auth
|
11
|
+
from cornflow.shared.exceptions import InvalidUsage
|
13
12
|
from cornflow.tests.const import LOGIN_URL
|
13
|
+
from cornflow.tests.custom_test_case import CheckTokenTestCase, CustomTestCase
|
14
14
|
|
15
15
|
|
16
16
|
class TestCheckToken(CheckTokenTestCase.TokenEndpoint):
|
@@ -64,3 +64,34 @@ class TestCheckToken(CheckTokenTestCase.TokenEndpoint):
|
|
64
64
|
self.get_check_token()
|
65
65
|
self.assertEqual(200, self.response.status_code)
|
66
66
|
self.assertEqual(0, self.response.json["valid"])
|
67
|
+
|
68
|
+
|
69
|
+
class TestUnexpiringToken(CustomTestCase):
|
70
|
+
def test_token_unexpiring(self):
|
71
|
+
auth = BIAuth()
|
72
|
+
|
73
|
+
token = auth.generate_token(1)
|
74
|
+
|
75
|
+
response = auth.decode_token(token)
|
76
|
+
self.assertEqual(response, {"user_id": 1})
|
77
|
+
|
78
|
+
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3MDM1OTI1OTIsInN1YiI6MX0.Plvmi02FMfZOTn6bxArELEmDeyuP-2X794c5VtAFgCg"
|
79
|
+
|
80
|
+
response = auth.decode_token(token)
|
81
|
+
self.assertEqual(response, {"user_id": 1})
|
82
|
+
|
83
|
+
def test_user_not_valid(self):
|
84
|
+
auth = BIAuth()
|
85
|
+
self.assertRaises(InvalidUsage, auth.generate_token, None)
|
86
|
+
|
87
|
+
auth = Auth()
|
88
|
+
self.assertRaises(InvalidUsage, auth.generate_token, None)
|
89
|
+
|
90
|
+
def test_token_not_valid(self):
|
91
|
+
auth = BIAuth()
|
92
|
+
self.assertRaises(InvalidUsage, auth.decode_token, None)
|
93
|
+
token = ""
|
94
|
+
self.assertRaises(InvalidUsage, auth.decode_token, token)
|
95
|
+
|
96
|
+
auth = Auth()
|
97
|
+
self.assertRaises(InvalidUsage, auth.decode_token, None)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 1.2
|
2
2
|
Name: cornflow
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.10a1
|
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
|
@@ -1,8 +1,8 @@
|
|
1
1
|
alembic==1.9.2
|
2
2
|
apispec<=6.2.0
|
3
3
|
click<=8.1.3
|
4
|
-
cornflow-client
|
5
|
-
cryptography<=
|
4
|
+
cornflow-client<=1.0.16
|
5
|
+
cryptography<=42.0.5
|
6
6
|
disposable-email-domains>=0.0.86
|
7
7
|
Flask==2.3.2
|
8
8
|
flask-apispec<=0.11.4
|
@@ -14,7 +14,7 @@ Flask-Migrate<=4.0.4
|
|
14
14
|
Flask-RESTful<=0.3.9
|
15
15
|
Flask-SQLAlchemy==2.5.1
|
16
16
|
gevent==23.9.1
|
17
|
-
gunicorn<=
|
17
|
+
gunicorn<=22.0.0
|
18
18
|
jsonpatch<=1.32
|
19
19
|
ldap3<=2.9.1
|
20
20
|
marshmallow<=3.19.0
|
@@ -22,10 +22,10 @@ PuLP<=2.7.0
|
|
22
22
|
psycopg2<=2.95
|
23
23
|
PyJWT<=2.6.0
|
24
24
|
pytups>=0.86.2
|
25
|
-
requests<=2.
|
25
|
+
requests<=2.31.0
|
26
26
|
SQLAlchemy==1.3.21
|
27
27
|
webargs<=8.2.0
|
28
|
-
Werkzeug<=2.3.
|
28
|
+
Werkzeug<=2.3.8
|
29
29
|
|
30
30
|
[:python_version < "3.11"]
|
31
31
|
greenlet<=2.0.2
|
@@ -9,7 +9,7 @@ with open("requirements.txt", "r") as fh:
|
|
9
9
|
|
10
10
|
setuptools.setup(
|
11
11
|
name="cornflow",
|
12
|
-
version="1.0.
|
12
|
+
version="1.0.10a1",
|
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.",
|
@@ -1,32 +0,0 @@
|
|
1
|
-
import click
|
2
|
-
from cornflow.cli.arguments import username, password, email, verbose
|
3
|
-
from cornflow.cli.utils import get_app
|
4
|
-
from cornflow.commands import create_user_with_role
|
5
|
-
from cornflow.shared.const import SERVICE_ROLE
|
6
|
-
|
7
|
-
|
8
|
-
@click.group(name="users", help="Commands to manage the users")
|
9
|
-
def users():
|
10
|
-
pass
|
11
|
-
|
12
|
-
|
13
|
-
@click.group(name="create", help="Create a user")
|
14
|
-
def create():
|
15
|
-
pass
|
16
|
-
|
17
|
-
|
18
|
-
users.add_command(create)
|
19
|
-
|
20
|
-
|
21
|
-
@create.command(name="service", help="Create a service user")
|
22
|
-
@username
|
23
|
-
@password
|
24
|
-
@email
|
25
|
-
@verbose
|
26
|
-
def create_service_user(username, password, email, verbose):
|
27
|
-
app = get_app()
|
28
|
-
with app.app_context():
|
29
|
-
|
30
|
-
create_user_with_role(
|
31
|
-
username, email, password, "service user", SERVICE_ROLE, verbose=verbose
|
32
|
-
)
|
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
|