meca-restapi-managers-token 1.0.0__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.
- meca_restapi_managers_token-1.0.0/MANIFEST.in +6 -0
- meca_restapi_managers_token-1.0.0/PKG-INFO +12 -0
- meca_restapi_managers_token-1.0.0/README.md +1 -0
- meca_restapi_managers_token-1.0.0/meca_restapi_managers_token.egg-info/PKG-INFO +12 -0
- meca_restapi_managers_token-1.0.0/meca_restapi_managers_token.egg-info/SOURCES.txt +14 -0
- meca_restapi_managers_token-1.0.0/meca_restapi_managers_token.egg-info/dependency_links.txt +1 -0
- meca_restapi_managers_token-1.0.0/meca_restapi_managers_token.egg-info/requires.txt +3 -0
- meca_restapi_managers_token-1.0.0/meca_restapi_managers_token.egg-info/top_level.txt +1 -0
- meca_restapi_managers_token-1.0.0/pyproject.toml +21 -0
- meca_restapi_managers_token-1.0.0/setup.cfg +4 -0
- meca_restapi_managers_token-1.0.0/src/__init__.py +5 -0
- meca_restapi_managers_token-1.0.0/src/routers/__init__.py +5 -0
- meca_restapi_managers_token-1.0.0/src/routers/_token.py +29 -0
- meca_restapi_managers_token-1.0.0/src/tables/__init__.py +0 -0
- meca_restapi_managers_token-1.0.0/src/tables/db.py +70 -0
- meca_restapi_managers_token-1.0.0/src/tables/token.py +18 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: meca-restapi-managers-token
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: 令牌管理接口
|
|
5
|
+
Author: dqlr
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: fastapi>=0.135.1
|
|
9
|
+
Requires-Dist: sqlmodel>=0.0.37
|
|
10
|
+
Requires-Dist: uvicorn>=0.41.0
|
|
11
|
+
|
|
12
|
+
#
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: meca-restapi-managers-token
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: 令牌管理接口
|
|
5
|
+
Author: dqlr
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: fastapi>=0.135.1
|
|
9
|
+
Requires-Dist: sqlmodel>=0.0.37
|
|
10
|
+
Requires-Dist: uvicorn>=0.41.0
|
|
11
|
+
|
|
12
|
+
#
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
meca_restapi_managers_token.egg-info/PKG-INFO
|
|
5
|
+
meca_restapi_managers_token.egg-info/SOURCES.txt
|
|
6
|
+
meca_restapi_managers_token.egg-info/dependency_links.txt
|
|
7
|
+
meca_restapi_managers_token.egg-info/requires.txt
|
|
8
|
+
meca_restapi_managers_token.egg-info/top_level.txt
|
|
9
|
+
src/__init__.py
|
|
10
|
+
src/routers/__init__.py
|
|
11
|
+
src/routers/_token.py
|
|
12
|
+
src/tables/__init__.py
|
|
13
|
+
src/tables/db.py
|
|
14
|
+
src/tables/token.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
meca
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ['setuptools>=70.0']
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "meca-restapi-managers-token"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "dqlr" }
|
|
10
|
+
]
|
|
11
|
+
description = "令牌管理接口"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
readme = 'README.md'
|
|
14
|
+
dependencies = [
|
|
15
|
+
"fastapi >=0.135.1",
|
|
16
|
+
"sqlmodel >=0.0.37",
|
|
17
|
+
"uvicorn >=0.41.0"
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[tool.setuptools.package-dir]
|
|
21
|
+
"meca.restapi.managers.token" = "src"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from ..tables.db import SqlDB
|
|
2
|
+
from ..tables.token import Token
|
|
3
|
+
|
|
4
|
+
from fastapi import APIRouter
|
|
5
|
+
|
|
6
|
+
db = SqlDB('home#token.db').wal().check_same_thread(False)
|
|
7
|
+
SessionAnnotated = db.SessionAnnotated
|
|
8
|
+
token = APIRouter(lifespan=db.init)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@token.post('/update')
|
|
12
|
+
async def update(token: Token, session: SessionAnnotated) -> Token:
|
|
13
|
+
existing = session.get(Token, (token.app, token.user))
|
|
14
|
+
if existing:
|
|
15
|
+
session.merge(token)
|
|
16
|
+
session.commit()
|
|
17
|
+
session.refresh(existing)
|
|
18
|
+
return existing
|
|
19
|
+
else:
|
|
20
|
+
session.add(token)
|
|
21
|
+
session.commit()
|
|
22
|
+
session.refresh(token)
|
|
23
|
+
return token
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@token.post('/get')
|
|
27
|
+
def get(token: Token, session: SessionAnnotated) -> Token:
|
|
28
|
+
token = session.get(Token, (token.app, token.user))
|
|
29
|
+
return token
|
|
File without changes
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from contextlib import asynccontextmanager
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Annotated, List
|
|
4
|
+
from typing_extensions import Self # 兼容Python3.10
|
|
5
|
+
|
|
6
|
+
from sqlalchemy import Engine
|
|
7
|
+
from sqlmodel import Session, SQLModel, create_engine
|
|
8
|
+
|
|
9
|
+
from fastapi import Depends, FastAPI
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SqlDB:
|
|
13
|
+
path: Path | str
|
|
14
|
+
connect_args: dict = {}
|
|
15
|
+
uri: str
|
|
16
|
+
query: List[str] = []
|
|
17
|
+
db: str
|
|
18
|
+
|
|
19
|
+
_engine: Engine = None
|
|
20
|
+
|
|
21
|
+
def _parse_path(self, path: str | Path):
|
|
22
|
+
if isinstance(path, Path):
|
|
23
|
+
path = path.absolute()
|
|
24
|
+
elif isinstance(path, str) and path.startswith('home#'):
|
|
25
|
+
path = (Path('~')/'databases'/path.split('#')[1]).expanduser().absolute()
|
|
26
|
+
else:
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
if not path.parent.is_dir():
|
|
30
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
31
|
+
self.uri = f'sqlite:///{path.as_posix()}'
|
|
32
|
+
self.path = path
|
|
33
|
+
|
|
34
|
+
def __init__(self, path: str | Path) -> Self:
|
|
35
|
+
self._parse_path(path=path)
|
|
36
|
+
|
|
37
|
+
def __str__(self):
|
|
38
|
+
if self.query:
|
|
39
|
+
return f'{self.uri}?{"&".join(self.query)}'
|
|
40
|
+
else:
|
|
41
|
+
return f'{self.uri}'
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return str(self)
|
|
45
|
+
|
|
46
|
+
def wal(self) -> Self:
|
|
47
|
+
self.query.append('journal_mode=WAL')
|
|
48
|
+
return self
|
|
49
|
+
|
|
50
|
+
def check_same_thread(self, value: bool) -> Self:
|
|
51
|
+
self.connect_args['check_same_thread'] = value
|
|
52
|
+
return self
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def engine(self) -> Engine:
|
|
56
|
+
if self._engine is None:
|
|
57
|
+
self._engine = create_engine(str(self), connect_args=self.connect_args)
|
|
58
|
+
return self._engine
|
|
59
|
+
|
|
60
|
+
@asynccontextmanager
|
|
61
|
+
async def init(self, _app: FastAPI):
|
|
62
|
+
SQLModel.metadata.create_all(self.engine)
|
|
63
|
+
yield
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def SessionAnnotated(self) -> Annotated:
|
|
67
|
+
def _session():
|
|
68
|
+
with Session(self.engine) as __session:
|
|
69
|
+
yield __session
|
|
70
|
+
return Annotated[Session, Depends(_session)]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from sqlmodel import Field, SQLModel
|
|
2
|
+
from time import time
|
|
3
|
+
|
|
4
|
+
class Token(SQLModel, table=True):
|
|
5
|
+
app: str = Field(primary_key=True)
|
|
6
|
+
user: str = Field(primary_key=True)
|
|
7
|
+
access_token: str
|
|
8
|
+
refresh_token: str
|
|
9
|
+
access_exp: int
|
|
10
|
+
refresh_exp: int
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def access_valid(self) -> bool:
|
|
14
|
+
return self.access_exp > time.time()
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def refresh_valid(self) -> bool:
|
|
18
|
+
return self.refresh_exp > time.time()
|