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.
@@ -0,0 +1,6 @@
1
+ # https://setuptools.pypa.io/en/latest/userguide/miscellaneous.html#using-manifest-in
2
+ prune .vscode
3
+ prune docs
4
+ prune Pipfile
5
+ prune Pipfile.lock
6
+ prune tests
@@ -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,3 @@
1
+ fastapi>=0.135.1
2
+ sqlmodel>=0.0.37
3
+ uvicorn>=0.41.0
@@ -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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,5 @@
1
+ from .routers import token as token_router
2
+
3
+ __all__ = [
4
+ 'token_router'
5
+ ]
@@ -0,0 +1,5 @@
1
+ from ._token import token
2
+
3
+ __all__ = [
4
+ "token"
5
+ ]
@@ -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
@@ -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()