ecodev-core 0.0.16__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.
Potentially problematic release.
This version of ecodev-core might be problematic. Click here for more details.
- ecodev_core-0.0.16/LICENSE.md +11 -0
- ecodev_core-0.0.16/PKG-INFO +79 -0
- ecodev_core-0.0.16/README.md +29 -0
- ecodev_core-0.0.16/ecodev_core/__init__.py +81 -0
- ecodev_core-0.0.16/ecodev_core/app_activity.py +108 -0
- ecodev_core-0.0.16/ecodev_core/app_rights.py +24 -0
- ecodev_core-0.0.16/ecodev_core/app_user.py +92 -0
- ecodev_core-0.0.16/ecodev_core/auth_configuration.py +18 -0
- ecodev_core-0.0.16/ecodev_core/authentication.py +265 -0
- ecodev_core-0.0.16/ecodev_core/backup.py +87 -0
- ecodev_core-0.0.16/ecodev_core/check_dependencies.py +179 -0
- ecodev_core-0.0.16/ecodev_core/custom_equal.py +27 -0
- ecodev_core-0.0.16/ecodev_core/db_connection.py +67 -0
- ecodev_core-0.0.16/ecodev_core/db_filters.py +142 -0
- ecodev_core-0.0.16/ecodev_core/db_insertion.py +108 -0
- ecodev_core-0.0.16/ecodev_core/db_retrieval.py +192 -0
- ecodev_core-0.0.16/ecodev_core/enum_utils.py +21 -0
- ecodev_core-0.0.16/ecodev_core/list_utils.py +81 -0
- ecodev_core-0.0.16/ecodev_core/logger.py +106 -0
- ecodev_core-0.0.16/ecodev_core/pandas_utils.py +40 -0
- ecodev_core-0.0.16/ecodev_core/permissions.py +15 -0
- ecodev_core-0.0.16/ecodev_core/pydantic_utils.py +33 -0
- ecodev_core-0.0.16/ecodev_core/read_write.py +40 -0
- ecodev_core-0.0.16/ecodev_core/safe_utils.py +197 -0
- ecodev_core-0.0.16/pyproject.toml +61 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Copyright 2024 Thomas EPELBAUM for EcoAct
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction,
|
|
4
|
+
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
5
|
+
subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
10
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
11
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ecodev-core
|
|
3
|
+
Version: 0.0.16
|
|
4
|
+
Summary: Low level sqlmodel/fastapi/pydantic building blocks
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Thomas Epelbaum
|
|
7
|
+
Author-email: tomepel@gmail.com
|
|
8
|
+
Requires-Python: >=3.11,<4.0
|
|
9
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
10
|
+
Classifier: Environment :: Web Environment
|
|
11
|
+
Classifier: Framework :: AsyncIO
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Framework :: Pydantic
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Information Technology
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Intended Audience :: System Administrators
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
26
|
+
Classifier: Topic :: Database
|
|
27
|
+
Classifier: Topic :: Database :: Database Engines/Servers
|
|
28
|
+
Classifier: Topic :: Internet
|
|
29
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
30
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
31
|
+
Classifier: Topic :: Software Development
|
|
32
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
33
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
34
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
35
|
+
Classifier: Typing :: Typed
|
|
36
|
+
Requires-Dist: fastapi (>=0,<1)
|
|
37
|
+
Requires-Dist: httpx (>=0,<1)
|
|
38
|
+
Requires-Dist: numpy (>=1,<2)
|
|
39
|
+
Requires-Dist: openpyxl (>=3,<4)
|
|
40
|
+
Requires-Dist: pandas (>=2,<3)
|
|
41
|
+
Requires-Dist: passlib[bcyrypt] (>=1,<2)
|
|
42
|
+
Requires-Dist: psycopg2-binary (>=2,<3)
|
|
43
|
+
Requires-Dist: pydantic-settings (>=2,<3)
|
|
44
|
+
Requires-Dist: pydantic[python-dotenv] (>=2,<3)
|
|
45
|
+
Requires-Dist: python-jose[cryptography] (>=3,<4)
|
|
46
|
+
Requires-Dist: sqladmin (==0.15.2)
|
|
47
|
+
Requires-Dist: sqlmodel (>=0,<1)
|
|
48
|
+
Description-Content-Type: text/markdown
|
|
49
|
+
|
|
50
|
+
# ecodev-core
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions" target="_blank">
|
|
54
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/blob/main/badges/coverage.svg" alt="Coverage">
|
|
55
|
+
</a>
|
|
56
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions" target="_blank">
|
|
57
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/blob/main/badges/pylint.svg" alt="Publish">
|
|
58
|
+
</a>
|
|
59
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions/workflows/code-quality.yml/badge.svg" target="_blank">
|
|
60
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/actions/workflows/code-quality.yml/badge.svg" alt="Package version">
|
|
61
|
+
</a>
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
Low level ecoact generic code. Aimed at being published in open source with poetry
|
|
65
|
+
|
|
66
|
+
## Installation of this package
|
|
67
|
+
|
|
68
|
+
You are strongly encouraged to install this package via Docker.
|
|
69
|
+
|
|
70
|
+
Starting from a project with a Docker file:
|
|
71
|
+
* add the module ecodev-core in the `requirements.txt` file
|
|
72
|
+
* make sure the `.env` file includes all required fields (see `BaseSettings` and `AuthenticationConfiguration`)
|
|
73
|
+
* build the new version of the Docker container (typically `docker build --tag xxx .`)
|
|
74
|
+
* run it with docker compose (`dc up -d`).
|
|
75
|
+
|
|
76
|
+
## Documentation
|
|
77
|
+
|
|
78
|
+
Please find it in the [associated mkdoc website!](https://ecodev-doc.lcabox.com/)
|
|
79
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# ecodev-core
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions" target="_blank">
|
|
5
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/blob/main/badges/coverage.svg" alt="Coverage">
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions" target="_blank">
|
|
8
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/blob/main/badges/pylint.svg" alt="Publish">
|
|
9
|
+
</a>
|
|
10
|
+
<a href="https://github.com/FR-PAR-ECOACT/ecodev-core/actions/workflows/code-quality.yml/badge.svg" target="_blank">
|
|
11
|
+
<img src="https://github.com/FR-PAR-ECOACT/ecodev-core/actions/workflows/code-quality.yml/badge.svg" alt="Package version">
|
|
12
|
+
</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
Low level ecoact generic code. Aimed at being published in open source with poetry
|
|
16
|
+
|
|
17
|
+
## Installation of this package
|
|
18
|
+
|
|
19
|
+
You are strongly encouraged to install this package via Docker.
|
|
20
|
+
|
|
21
|
+
Starting from a project with a Docker file:
|
|
22
|
+
* add the module ecodev-core in the `requirements.txt` file
|
|
23
|
+
* make sure the `.env` file includes all required fields (see `BaseSettings` and `AuthenticationConfiguration`)
|
|
24
|
+
* build the new version of the Docker container (typically `docker build --tag xxx .`)
|
|
25
|
+
* run it with docker compose (`dc up -d`).
|
|
26
|
+
|
|
27
|
+
## Documentation
|
|
28
|
+
|
|
29
|
+
Please find it in the [associated mkdoc website!](https://ecodev-doc.lcabox.com/)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module listing all public method from the ecodev_core modules
|
|
3
|
+
"""
|
|
4
|
+
from ecodev_core.app_activity import AppActivity
|
|
5
|
+
from ecodev_core.app_activity import dash_monitor
|
|
6
|
+
from ecodev_core.app_activity import fastapi_monitor
|
|
7
|
+
from ecodev_core.app_activity import get_method
|
|
8
|
+
from ecodev_core.app_activity import get_recent_activities
|
|
9
|
+
from ecodev_core.app_rights import AppRight
|
|
10
|
+
from ecodev_core.app_user import AppUser
|
|
11
|
+
from ecodev_core.app_user import select_user
|
|
12
|
+
from ecodev_core.app_user import upsert_app_users
|
|
13
|
+
from ecodev_core.auth_configuration import AUTH
|
|
14
|
+
from ecodev_core.authentication import attempt_to_log
|
|
15
|
+
from ecodev_core.authentication import get_access_token
|
|
16
|
+
from ecodev_core.authentication import get_app_services
|
|
17
|
+
from ecodev_core.authentication import get_current_user
|
|
18
|
+
from ecodev_core.authentication import get_user
|
|
19
|
+
from ecodev_core.authentication import is_admin_user
|
|
20
|
+
from ecodev_core.authentication import is_authorized_user
|
|
21
|
+
from ecodev_core.authentication import is_monitoring_user
|
|
22
|
+
from ecodev_core.authentication import JwtAuth
|
|
23
|
+
from ecodev_core.authentication import safe_get_user
|
|
24
|
+
from ecodev_core.authentication import SCHEME
|
|
25
|
+
from ecodev_core.authentication import Token
|
|
26
|
+
from ecodev_core.backup import backup
|
|
27
|
+
from ecodev_core.check_dependencies import check_dependencies
|
|
28
|
+
from ecodev_core.check_dependencies import compute_dependencies
|
|
29
|
+
from ecodev_core.custom_equal import custom_equal
|
|
30
|
+
from ecodev_core.db_connection import create_db_and_tables
|
|
31
|
+
from ecodev_core.db_connection import DB_URL
|
|
32
|
+
from ecodev_core.db_connection import delete_table
|
|
33
|
+
from ecodev_core.db_connection import engine
|
|
34
|
+
from ecodev_core.db_connection import get_session
|
|
35
|
+
from ecodev_core.db_connection import info_message
|
|
36
|
+
from ecodev_core.db_filters import ServerSideFilter
|
|
37
|
+
from ecodev_core.db_insertion import generic_insertion
|
|
38
|
+
from ecodev_core.db_insertion import get_raw_df
|
|
39
|
+
from ecodev_core.db_retrieval import count_rows
|
|
40
|
+
from ecodev_core.db_retrieval import get_rows
|
|
41
|
+
from ecodev_core.db_retrieval import ServerSideField
|
|
42
|
+
from ecodev_core.enum_utils import enum_converter
|
|
43
|
+
from ecodev_core.list_utils import first_or_default
|
|
44
|
+
from ecodev_core.list_utils import first_transformed_or_default
|
|
45
|
+
from ecodev_core.list_utils import group_by
|
|
46
|
+
from ecodev_core.list_utils import group_by_value
|
|
47
|
+
from ecodev_core.list_utils import lselect
|
|
48
|
+
from ecodev_core.list_utils import lselectfirst
|
|
49
|
+
from ecodev_core.logger import log_critical
|
|
50
|
+
from ecodev_core.logger import logger_get
|
|
51
|
+
from ecodev_core.pandas_utils import get_excelfile
|
|
52
|
+
from ecodev_core.pandas_utils import jsonify_series
|
|
53
|
+
from ecodev_core.pandas_utils import pd_equals
|
|
54
|
+
from ecodev_core.permissions import Permission
|
|
55
|
+
from ecodev_core.pydantic_utils import Basic
|
|
56
|
+
from ecodev_core.pydantic_utils import CustomFrozen
|
|
57
|
+
from ecodev_core.pydantic_utils import Frozen
|
|
58
|
+
from ecodev_core.pydantic_utils import OrmFrozen
|
|
59
|
+
from ecodev_core.read_write import load_json_file
|
|
60
|
+
from ecodev_core.read_write import make_dir
|
|
61
|
+
from ecodev_core.read_write import write_json_file
|
|
62
|
+
from ecodev_core.safe_utils import boolify
|
|
63
|
+
from ecodev_core.safe_utils import floatify
|
|
64
|
+
from ecodev_core.safe_utils import intify
|
|
65
|
+
from ecodev_core.safe_utils import safe_clt
|
|
66
|
+
from ecodev_core.safe_utils import SafeTestCase
|
|
67
|
+
from ecodev_core.safe_utils import SimpleReturn
|
|
68
|
+
from ecodev_core.safe_utils import stringify
|
|
69
|
+
|
|
70
|
+
__all__ = [
|
|
71
|
+
'AUTH', 'Token', 'get_app_services', 'attempt_to_log', 'get_current_user', 'is_admin_user',
|
|
72
|
+
'write_json_file', 'load_json_file', 'make_dir', 'check_dependencies', 'compute_dependencies',
|
|
73
|
+
'engine', 'create_db_and_tables', 'get_session', 'info_message', 'group_by_value', 'OrmFrozen',
|
|
74
|
+
'first_or_default', 'lselect', 'lselectfirst', 'first_transformed_or_default', 'log_critical',
|
|
75
|
+
'logger_get', 'Permission', 'AppUser', 'AppRight', 'Basic', 'Frozen', 'CustomFrozen', 'JwtAuth',
|
|
76
|
+
'SafeTestCase', 'SimpleReturn', 'safe_clt', 'stringify', 'boolify', 'get_user', 'floatify',
|
|
77
|
+
'delete_table', 'SCHEME', 'DB_URL', 'pd_equals', 'jsonify_series', 'upsert_app_users', 'intify',
|
|
78
|
+
'enum_converter', 'ServerSideFilter', 'get_rows', 'count_rows', 'ServerSideField', 'get_raw_df',
|
|
79
|
+
'generic_insertion', 'custom_equal', 'is_authorized_user', 'get_method', 'AppActivity',
|
|
80
|
+
'fastapi_monitor', 'dash_monitor', 'is_monitoring_user', 'get_recent_activities', 'select_user',
|
|
81
|
+
'get_access_token', 'safe_get_user', 'backup', 'group_by', 'get_excelfile']
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module implementing a simple monitoring table
|
|
3
|
+
"""
|
|
4
|
+
import inspect
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from typing import Dict
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from sqlmodel import col
|
|
10
|
+
from sqlmodel import Field
|
|
11
|
+
from sqlmodel import select
|
|
12
|
+
from sqlmodel import Session
|
|
13
|
+
from sqlmodel import SQLModel
|
|
14
|
+
|
|
15
|
+
from ecodev_core.app_user import AppUser
|
|
16
|
+
from ecodev_core.authentication import get_user
|
|
17
|
+
from ecodev_core.db_connection import engine
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
Simple helper to retrieve the method name in which this helper is called
|
|
22
|
+
|
|
23
|
+
NB: this is meant to stay a lambda, otherwise the name retrieved is get_method, not the caller
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_method(): return inspect.stack()[1][3]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AppActivityBase(SQLModel):
|
|
31
|
+
"""
|
|
32
|
+
Simple monitoring class
|
|
33
|
+
|
|
34
|
+
Attributes are:
|
|
35
|
+
- user: the name of the user that triggered the monitoring log
|
|
36
|
+
- application: the application in which the user triggered the monitoring log
|
|
37
|
+
- method: the method called by the user that triggered the monitoring log
|
|
38
|
+
- relevant_option: if filled, complementary information on method (num of treated lines...)
|
|
39
|
+
"""
|
|
40
|
+
user: str = Field(index=True)
|
|
41
|
+
application: str = Field(index=True)
|
|
42
|
+
method: str = Field(index=True)
|
|
43
|
+
relevant_option: Optional[str] = Field(index=True, default=None)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AppActivity(AppActivityBase, table=True): # type: ignore
|
|
47
|
+
"""
|
|
48
|
+
The table version of the AppActivityBase monitoring class
|
|
49
|
+
"""
|
|
50
|
+
__tablename__ = 'app_activity'
|
|
51
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
52
|
+
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def dash_monitor(method: str,
|
|
56
|
+
token: Dict,
|
|
57
|
+
application: str,
|
|
58
|
+
relevant_option: Optional[str] = None):
|
|
59
|
+
"""
|
|
60
|
+
Generic dash monitor.
|
|
61
|
+
|
|
62
|
+
Attributes are:
|
|
63
|
+
- method: the method called by the user that triggered the monitoring log
|
|
64
|
+
- token: contains the information on the user that triggered the monitoring log
|
|
65
|
+
- application: the application in which the user triggered the monitoring log
|
|
66
|
+
- relevant_option: if filled, complementary information on method (num of treated lines...)
|
|
67
|
+
"""
|
|
68
|
+
with Session(engine) as session:
|
|
69
|
+
user = get_user(token.get('token', {}).get('access_token'))
|
|
70
|
+
add_activity_to_db(method, user, application, session, relevant_option)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def fastapi_monitor(method: str,
|
|
74
|
+
user: AppUser,
|
|
75
|
+
application: str,
|
|
76
|
+
session: Session,
|
|
77
|
+
relevant_option: Optional[str] = None):
|
|
78
|
+
"""
|
|
79
|
+
Generic fastapi monitor.
|
|
80
|
+
|
|
81
|
+
Attributes are:
|
|
82
|
+
- method: the method called by the user that triggered the monitoring log
|
|
83
|
+
- user: the name of the user that triggered the monitoring log
|
|
84
|
+
- application: the application in which the user triggered the monitoring log
|
|
85
|
+
- session: db connection
|
|
86
|
+
- relevant_option: if filled, complementary information on method (num of treated lines...)
|
|
87
|
+
"""
|
|
88
|
+
add_activity_to_db(method, user, application, session, relevant_option)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def add_activity_to_db(method: str,
|
|
92
|
+
user: AppUser,
|
|
93
|
+
application: str,
|
|
94
|
+
session: Session,
|
|
95
|
+
relevant_option: Optional[str] = None):
|
|
96
|
+
"""
|
|
97
|
+
Add a new entry in AppActivity given the passed arguments
|
|
98
|
+
"""
|
|
99
|
+
session.add(AppActivity(user=user.user, application=application, method=method,
|
|
100
|
+
relevant_option=relevant_option))
|
|
101
|
+
session.commit()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_recent_activities(last_date: str, session: Session):
|
|
105
|
+
"""
|
|
106
|
+
Returns all activities that happened after last_date
|
|
107
|
+
"""
|
|
108
|
+
return session.exec(select(AppActivity).where(col(AppActivity.created_at) > last_date)).all()
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module implementing the sqlmodel orm part of the right table
|
|
3
|
+
"""
|
|
4
|
+
from typing import Optional
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Field
|
|
8
|
+
from sqlmodel import Relationship
|
|
9
|
+
from sqlmodel import SQLModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
13
|
+
from ecodev_core.app_user import AppUser
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AppRight(SQLModel, table=True): # type: ignore
|
|
17
|
+
"""
|
|
18
|
+
Simple right class: listing all app_services that a particular user can access to
|
|
19
|
+
"""
|
|
20
|
+
__tablename__ = 'app_right'
|
|
21
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
22
|
+
app_service: str
|
|
23
|
+
user_id: Optional[int] = Field(default=None, foreign_key='app_user.id')
|
|
24
|
+
user: Optional['AppUser'] = Relationship(back_populates='rights')
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module implementing the sqlmodel orm part of the user table
|
|
3
|
+
"""
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Dict
|
|
6
|
+
from typing import List
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from sqlmodel import col
|
|
12
|
+
from sqlmodel import Field
|
|
13
|
+
from sqlmodel import Relationship
|
|
14
|
+
from sqlmodel import select
|
|
15
|
+
from sqlmodel import Session
|
|
16
|
+
from sqlmodel import SQLModel
|
|
17
|
+
from sqlmodel.sql.expression import SelectOfScalar
|
|
18
|
+
|
|
19
|
+
from ecodev_core.db_insertion import create_or_update
|
|
20
|
+
from ecodev_core.db_insertion import Insertor
|
|
21
|
+
from ecodev_core.permissions import Permission
|
|
22
|
+
from ecodev_core.read_write import load_json_file
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
26
|
+
from ecodev_core.app_rights import AppRight
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AppUser(SQLModel, table=True): # type: ignore
|
|
30
|
+
"""
|
|
31
|
+
Simple user class: an id associate to a user with a password
|
|
32
|
+
"""
|
|
33
|
+
__tablename__ = 'app_user'
|
|
34
|
+
id: Optional[int] = Field(default=None, primary_key=True)
|
|
35
|
+
user: str = Field(index=True)
|
|
36
|
+
password: str
|
|
37
|
+
permission: Permission = Field(default=Permission.ADMIN)
|
|
38
|
+
client: Optional[str] = Field(default=None)
|
|
39
|
+
rights: List['AppRight'] = Relationship(back_populates='user')
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def user_convertor(df: pd.DataFrame) -> List[Dict]:
|
|
43
|
+
"""
|
|
44
|
+
Dummy user convertor
|
|
45
|
+
"""
|
|
46
|
+
return [x for _, x in df.iterrows()]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def user_reductor(in_db_row: AppUser, db_row: AppUser) -> AppUser:
|
|
50
|
+
"""
|
|
51
|
+
Update an existing in_db_row with new information coming from db_row
|
|
52
|
+
|
|
53
|
+
NB: in the future this will maybe handle the client as well
|
|
54
|
+
"""
|
|
55
|
+
in_db_row.permission = db_row.permission
|
|
56
|
+
in_db_row.password = db_row.password
|
|
57
|
+
return in_db_row
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def user_selector(db_row: AppUser) -> SelectOfScalar:
|
|
61
|
+
"""
|
|
62
|
+
Criteria on which to decide whether creating a new row or updating an existing one in db
|
|
63
|
+
"""
|
|
64
|
+
return select(AppUser).where(col(AppUser.user) == db_row.user)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
USER_INSERTOR = Insertor(convertor=user_convertor, selector=user_selector,
|
|
68
|
+
reductor=user_reductor, db_schema=AppUser, read_excel_file=False)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def upsert_app_users(file_path: Path, session: Session) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Upsert db users with a list of users provided in the file_path (json format)
|
|
74
|
+
"""
|
|
75
|
+
for user in load_json_file(file_path):
|
|
76
|
+
session.add(create_or_update(session, user, USER_INSERTOR))
|
|
77
|
+
session.commit()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def select_user(username: str, session: Session) -> AppUser:
|
|
81
|
+
"""
|
|
82
|
+
Helper function to (attempt to) retrieve AppUser from username.
|
|
83
|
+
|
|
84
|
+
NB: Used to check whether user exists, before resetting its password.
|
|
85
|
+
I.e. User does not yet have a token - we are simply checking if
|
|
86
|
+
an active account exists under that username.
|
|
87
|
+
|
|
88
|
+
Raises:
|
|
89
|
+
sqlalchemy.exc.NoResultFound: Typical error is no users are found.
|
|
90
|
+
sqlalchemy.exc.MultipleResultsFound: Should normally never be an issue.
|
|
91
|
+
"""
|
|
92
|
+
return session.exec(select(AppUser).where(col(AppUser.user) == username)).one()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module implementing authentication configuration.
|
|
3
|
+
"""
|
|
4
|
+
from pydantic_settings import BaseSettings
|
|
5
|
+
from pydantic_settings import SettingsConfigDict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AuthenticationConfiguration(BaseSettings):
|
|
9
|
+
"""
|
|
10
|
+
Simple authentication configuration class
|
|
11
|
+
"""
|
|
12
|
+
secret_key: str
|
|
13
|
+
algorithm: str
|
|
14
|
+
access_token_expire_minutes: int
|
|
15
|
+
model_config = SettingsConfigDict(env_file='.env')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
AUTH = AuthenticationConfiguration()
|