Init Commit
This commit is contained in:
commit
39446c49ca
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
|
||||
AUTH_SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
|
||||
AUTH_ALGORITHM = "HS256"
|
||||
AUTH_ACCESS_TOKEN_EXPIRE_MINUTES = 43201
|
||||
AUTH_REFRESH_TOKEN_EXPIRE_MINUTES = 43200
|
||||
|
||||
|
||||
TEST_VAR = 10
|
||||
|
||||
|
||||
# mongo
|
||||
MONGO_URL = "mongodb://bridge_user:ky2io8XRCI43vO8j@192.168.15.76:27270/bridge"
|
||||
MONGO_DB = 'bridge'
|
||||
AUTH_DB = 'auth'
|
||||
|
||||
PROD_MONGO_URL = "mongodb://bridge_user:ky2io8XRCI43vO8j@192.168.15.76:27270/bridge"
|
||||
PROD_MONGO_DB = 'bridge'
|
||||
PROD_AUTH_DB = 'auth'
|
||||
|
||||
IS_PROD = False
|
||||
PREFIX_API_URL = '/api/v1'
|
||||
FILE_SYSTEM_BASE_URL = 'https://testnet.hacoupian.net/api/scm/v1/file'
|
||||
|
||||
LINKER_URL = 'http://hcpn.ir/l'
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/poetry.lock
|
||||
/venv/
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="jdk" jdkName="Python 3.10 (fast)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
</module>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<option name="ignoredErrors">
|
||||
<list>
|
||||
<option value="N802" />
|
||||
<option value="N806" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="coding.models.const.UUID" />
|
||||
<option value="time.time.time" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (fast)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/badmin.iml" filepath="$PROJECT_DIR$/.idea/badmin.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="WebResourcesPaths">
|
||||
<contentEntries>
|
||||
<entry url="file://$PROJECT_DIR$">
|
||||
<entryData>
|
||||
<resourceRoots>
|
||||
<path value="file://$PROJECT_DIR$/venv" />
|
||||
</resourceRoots>
|
||||
</entryData>
|
||||
</entry>
|
||||
</contentEntries>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -0,0 +1 @@
|
|||
3.10.7
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
**Cross - site scripting**
|
||||
|
||||
**Birthday**
|
||||
|
||||
**Malware**
|
||||
- Macro viruses
|
||||
- File infectors
|
||||
- boot record infectors
|
||||
- Polymorphic viruses
|
||||
- Stealth viruses
|
||||
- Trojans
|
||||
- Logic bombs
|
||||
- Worms
|
||||
- Droppers
|
||||
- Ransomware
|
||||
- Cryptojacking
|
||||
- Wiper
|
||||
|
||||
**Denial of service**
|
||||
|
||||
**Distributed denial of service**
|
||||
|
||||
**Eavesdropping**
|
||||
|
||||
**Phishing**
|
||||
|
||||
**Password attack ** (Dictionary & Brute force)
|
||||
|
||||
**Code injection**
|
||||
|
||||
**SQL injection**
|
||||
|
||||
**Data scraping**
|
||||
|
||||
Hardware backdoors
|
||||
|
||||
Man-in-the-middle(MitM) attack
|
||||
|
||||
Crimeware
|
||||
|
||||
Adware
|
||||
|
||||
Click hijacking
|
||||
|
||||
Advanced persistent threat (APT)
|
||||
|
||||
Arbitrary code execution
|
||||
|
||||
Backdoors
|
||||
|
||||
Botnets
|
||||
|
||||
Data breach
|
||||
|
||||
Drive - by download
|
||||
|
||||
|
||||
Email
|
||||
- Email fraud(scam)
|
||||
- Email spoofing
|
||||
- Email Phishing
|
||||
- Lottery scam
|
||||
|
||||
Keyloggers
|
||||
|
||||
Bomb
|
||||
- Logic bombs
|
||||
- Time bombs
|
||||
- Email bombs
|
||||
- Fork bombs
|
||||
- Zip bombs
|
||||
|
||||
Scareware
|
||||
|
||||
Shellcode
|
||||
|
||||
Spamming
|
||||
|
||||
Screen scraping
|
||||
|
||||
Spyware
|
||||
|
||||
Hardware Trojans
|
||||
|
||||
Remote access trojans
|
||||
|
||||
Web shells
|
||||
|
||||
Worms
|
||||
|
||||
Rogue security software
|
||||
|
||||
Zombie
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import uvicorn
|
||||
from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from config import conf
|
||||
|
||||
app = FastAPI(debug=True)
|
||||
|
||||
|
||||
app.mount(
|
||||
conf.PREFIX_API_URL +
|
||||
"/storage",
|
||||
StaticFiles(
|
||||
directory="storage"),
|
||||
name="storage")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
uvicorn.run("main:app", port=5000, log_level="info")
|
||||
Binary file not shown.
|
|
@ -0,0 +1,71 @@
|
|||
from fastapi import HTTPException
|
||||
from sqlalchemy import update
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from badmin.models import model
|
||||
from badmin.models.model import Base
|
||||
from core.te import NewTableEngine
|
||||
from map import joins, search_cols
|
||||
import filter
|
||||
|
||||
|
||||
def model_name_to_class(__model: str) -> Base:
|
||||
try:
|
||||
return getattr(model, __model)
|
||||
except BaseException:
|
||||
raise HTTPException(status_code=400, detail=f'{__model} was not found')
|
||||
|
||||
|
||||
def model_name_to_table_name(__model: str) -> Base:
|
||||
m = model_name_to_class(__model)
|
||||
if m:
|
||||
return m.__tablename__
|
||||
raise HTTPException(status_code=400, detail='Model not Found')
|
||||
|
||||
|
||||
def get_join_cols(__model: str) -> Base:
|
||||
return joins.get(__model, [])
|
||||
|
||||
|
||||
class AutoController:
|
||||
@staticmethod
|
||||
def get_(db: Session, _model: str, _id: int):
|
||||
m = model_name_to_class(_model)
|
||||
row = db.query(m).filter(m.id == _id).one()
|
||||
for item in get_join_cols(_model):
|
||||
getattr(row, item)
|
||||
return row
|
||||
|
||||
@staticmethod
|
||||
async def list_(db: Session, _model: str, body: dict):
|
||||
m = model_name_to_class(_model)
|
||||
return await NewTableEngine.pgsql(
|
||||
query_class=db,
|
||||
model=m,
|
||||
extra_filter=getattr(filter.ExtraFilter, _model) if hasattr(filter.ExtraFilter, _model) else None,
|
||||
search_cols=search_cols.get(_model, []),
|
||||
inputs=body.get('te')) \
|
||||
.to_dict()
|
||||
|
||||
@staticmethod
|
||||
def update(db: Session, _model: str, _id: int, _input: dict):
|
||||
m = model_name_to_class(_model)
|
||||
db.query(m).filter(m.id == _id).update(_input)
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def create(db: Session, _model: str, _input: dict):
|
||||
m = model_name_to_class(_model)
|
||||
obj = m(**_input)
|
||||
db.add(obj)
|
||||
db.commit()
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def delete(db: Session, _model: str, _id: int):
|
||||
m = model_name_to_class(_model)
|
||||
obj = m.query.filter(m.id == _id).one()
|
||||
db.delete(obj)
|
||||
db.commit()
|
||||
return True
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,67 @@
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from fastapi import Depends, Body, Header, HTTPException, APIRouter
|
||||
from jose import jwt
|
||||
from sqlalchemy.orm import Session
|
||||
import app
|
||||
from badmin.controller import AutoController
|
||||
from config import conf
|
||||
from database import get_db
|
||||
from map import routes
|
||||
from utils import generateRouter
|
||||
|
||||
router = generateRouter("admin", auth_dependencies=True)
|
||||
|
||||
|
||||
def get_model_route(model: str):
|
||||
if routes.get(model, None):
|
||||
return routes.get(model, None)
|
||||
else:
|
||||
raise HTTPException(status_code=404, detail='Url Not Found')
|
||||
|
||||
|
||||
@app.app.post(f'{conf.PREFIX_API_URL}/auth/login')
|
||||
def login(body: dict = Body(...)):
|
||||
to_encode = body.copy()
|
||||
expire = datetime.utcnow() + timedelta(days=10)
|
||||
to_encode.update({"exp": expire})
|
||||
# TODO control User and Pass
|
||||
encoded_jwt = jwt.encode(
|
||||
to_encode,
|
||||
conf.AUTH_SECRET_KEY,
|
||||
algorithm=conf.AUTH_ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
@router.get('/{_model}/{_id}')
|
||||
def get(_model: str, _id: int, db: Session = Depends(get_db)):
|
||||
return AutoController.get_(db, get_model_route(_model), _id)
|
||||
|
||||
|
||||
@router.put('/{_model}/{_id}')
|
||||
def put(
|
||||
_model: str,
|
||||
_id: int,
|
||||
db: Session = Depends(get_db),
|
||||
payload=Body(...)):
|
||||
return AutoController.update(db, get_model_route(_model), _id, payload)
|
||||
|
||||
|
||||
@router.post('/list/{_model}')
|
||||
async def _list(_model: str, body: dict = Body(...), db: Session = Depends(get_db)):
|
||||
return AutoController.list_(db, get_model_route(_model), body=body)
|
||||
|
||||
|
||||
@router.post('/create/{_model}')
|
||||
async def _list(_model: str, body: dict = Body(...), db: Session = Depends(get_db)):
|
||||
return AutoController.create(db, get_model_route(_model), body)
|
||||
|
||||
|
||||
@router.delete('/{_model}/{_id}')
|
||||
async def delete(_model: str,
|
||||
_id: int,
|
||||
db: Session = Depends(get_db)):
|
||||
return AutoController.delete(db, get_model_route(_model), _id)
|
||||
|
||||
|
||||
app.app.include_router(router)
|
||||
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
from pydantic import BaseSettings
|
||||
|
||||
|
||||
class Base(BaseSettings):
|
||||
pass
|
||||
|
||||
|
||||
class AuthConf(Base):
|
||||
AUTH_ACCESS_TOKEN_EXPIRE_MINUTES: int
|
||||
AUTH_REFRESH_TOKEN_EXPIRE_MINUTES: int
|
||||
AUTH_ALGORITHM: str
|
||||
AUTH_SECRET_KEY: str
|
||||
|
||||
|
||||
class MongoConf(Base):
|
||||
MONGO_URL: str
|
||||
MONGO_DB: str
|
||||
AUTH_DB: str
|
||||
PROD_MONGO_URL: str
|
||||
PROD_MONGO_DB: str
|
||||
PROD_AUTH_DB: str
|
||||
|
||||
|
||||
class Conf(AuthConf, MongoConf):
|
||||
app_name: str = "Awesome API"
|
||||
admin_email: str
|
||||
items_per_user: int = 50
|
||||
TEST_VAR: int
|
||||
IS_PROD: bool = False
|
||||
PREFIX_API_URL: str
|
||||
FILE_SYSTEM_BASE_URL: str
|
||||
LINKER_URL: str
|
||||
|
||||
|
||||
|
||||
class Config:
|
||||
env_file = '.env'
|
||||
|
||||
def getMongoUrl(
|
||||
self): return conf.IS_PROD and conf.PROD_MONGO_URL or conf.MONGO_URL
|
||||
|
||||
def getMongoDb(
|
||||
self):
|
||||
return conf.IS_PROD and self.PROD_MONGO_DB or self.MONGO_DB
|
||||
|
||||
def getAuthDb(
|
||||
self):
|
||||
return conf.IS_PROD and self.PROD_AUTH_DB or self.AUTH_DB
|
||||
|
||||
def getLinkerDb(self):
|
||||
return 'linker'
|
||||
|
||||
|
||||
def getNamespaceApi(prefix):
|
||||
return f"{conf.PREFIX_API_URL}/{prefix}"
|
||||
|
||||
|
||||
conf = Conf(admin_email='ar.azizan@gmail.com')
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
from typing import List
|
||||
|
||||
from .engines import MsSqlEngine, MongoEngine, PgSqlEngine, AbstractEngine
|
||||
from .types import TableEngineExport
|
||||
from .utils.Models import TableEngineInput
|
||||
from .utils.Models import WorkingMode, JoinModel
|
||||
|
||||
|
||||
class NewTableEngine:
|
||||
def __init__(
|
||||
self,
|
||||
query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode,
|
||||
engine: AbstractEngine,
|
||||
extra_filter,
|
||||
default_sort_by,
|
||||
joins,
|
||||
search_cols,
|
||||
options=None,
|
||||
soft_deleted=False):
|
||||
self.model = model
|
||||
self.query_class = query_class
|
||||
self.mode = mode
|
||||
self.joins = False
|
||||
self.raw_input = inputs
|
||||
if isinstance(inputs, dict):
|
||||
self.input = TableEngineInput(**inputs if inputs else {})
|
||||
else:
|
||||
self.input = TableEngineInput(**inputs.dict() if inputs else {})
|
||||
self.input.extra_filter = extra_filter
|
||||
self.default_sort_by = default_sort_by
|
||||
self.joins = joins
|
||||
self.soft_deleted = soft_deleted
|
||||
self.options = options
|
||||
self.search_cols = search_cols
|
||||
self.engine = engine(self)
|
||||
|
||||
@staticmethod
|
||||
def mongo(query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode: WorkingMode = WorkingMode.Development,
|
||||
extra_filter=None,
|
||||
soft_deleted=False,
|
||||
default_sort_by=None, joins=None, search_cols=[]):
|
||||
return NewTableEngine(
|
||||
query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode,
|
||||
engine=MongoEngine,
|
||||
extra_filter=extra_filter,
|
||||
default_sort_by=default_sort_by,
|
||||
joins=joins,
|
||||
search_cols=search_cols,
|
||||
soft_deleted=soft_deleted)
|
||||
|
||||
@staticmethod
|
||||
def mssql(
|
||||
query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode: WorkingMode = WorkingMode.Development,
|
||||
extra_filter=None,
|
||||
default_sort_by=None,
|
||||
joins=None,
|
||||
search_cols=[],
|
||||
options=None):
|
||||
return NewTableEngine(
|
||||
query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode,
|
||||
engine=MsSqlEngine,
|
||||
extra_filter=extra_filter,
|
||||
default_sort_by=default_sort_by,
|
||||
joins=joins,
|
||||
search_cols=search_cols,
|
||||
options=options)
|
||||
|
||||
@staticmethod
|
||||
def pgsql(
|
||||
query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode: WorkingMode = WorkingMode.Development,
|
||||
extra_filter=None,
|
||||
default_sort_by=None,
|
||||
joins=None,
|
||||
search_cols=None,
|
||||
options=None):
|
||||
return NewTableEngine(
|
||||
query_class,
|
||||
model,
|
||||
inputs,
|
||||
mode,
|
||||
engine=PgSqlEngine,
|
||||
extra_filter=extra_filter,
|
||||
default_sort_by=default_sort_by,
|
||||
joins=joins,
|
||||
search_cols=search_cols,
|
||||
options=options)
|
||||
|
||||
async def exe(self):
|
||||
return await self.engine.exe()
|
||||
|
||||
async def to_dict(self) -> TableEngineExport:
|
||||
rows, count = await self.exe()
|
||||
self.input.extra_filter = None
|
||||
del self.engine
|
||||
return TableEngineExport(
|
||||
rows=rows,
|
||||
page=self.input.virtual_page(),
|
||||
total=count,
|
||||
te=self.input
|
||||
)
|
||||
|
||||
def add_extra_filter(self, filters):
|
||||
self.input = filters
|
||||
return self
|
||||
|
||||
def joins(self, joins: List[JoinModel]):
|
||||
self.joins = joins
|
||||
return self
|
||||
|
||||
def set_custom_entities(self, entities=None):
|
||||
self.engine.custom_entities = entities
|
||||
return self
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,51 @@
|
|||
import abc
|
||||
|
||||
__all__ = "AbstractEngine"
|
||||
|
||||
|
||||
class AbstractEngineClass(abc.ABC):
|
||||
def __init__(self, table_engine):
|
||||
self.model = table_engine.model
|
||||
self.query_class = table_engine.query_class
|
||||
self.input = table_engine.input
|
||||
self.filter = table_engine.input.f
|
||||
self.default_sort_by = table_engine.default_sort_by
|
||||
self.custom_entities = []
|
||||
self.joins = table_engine.joins
|
||||
self.options = table_engine.options
|
||||
self.search_cols = table_engine.search_cols
|
||||
self.soft_deleted = table_engine.soft_deleted
|
||||
|
||||
@abc.abstractmethod
|
||||
def exe(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_filters(self):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_sort(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def get_expression_filter(col=None, op: str = 'eq', val: str = '') -> dict:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def get_operator(op: str):
|
||||
pass
|
||||
|
||||
def count(self):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
@abc.abstractmethod
|
||||
def generate_scope_filter(filters: list, general=False):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_joins(self):
|
||||
pass
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
from uuid import UUID
|
||||
|
||||
from .AbstractEngine import AbstractEngineClass
|
||||
from ..utils.Models import FilterItem, FilterScope
|
||||
|
||||
|
||||
class MongoEngine(AbstractEngineClass):
|
||||
rows = []
|
||||
stack = []
|
||||
filters = {}
|
||||
|
||||
async def exe(self):
|
||||
_f = self.filters = self.set_filters()
|
||||
tmp = self.query_class.find(_f).sort(**self.set_sort())
|
||||
self.rows = tmp.limit(
|
||||
self.input.get_limit()).skip(self.input.skip())
|
||||
return [self.model(**document) async for document in self.rows], await self.count()
|
||||
|
||||
def query_generator(self):
|
||||
if not self.input.has_filter():
|
||||
return []
|
||||
filters = self.input.filters()
|
||||
query = self.generate_scope_filter(filters, general=True)
|
||||
return query
|
||||
|
||||
def set_filters(self):
|
||||
filters = []
|
||||
query = self.query_generator()
|
||||
if query:
|
||||
filters.append(query)
|
||||
if self.input.has_text_search():
|
||||
items = []
|
||||
_search_cols = self.input.get_search_cols() if (
|
||||
self.input.get_search_cols() and len(self.input.get_search_cols())) else self.search_cols
|
||||
if _search_cols:
|
||||
for col in _search_cols:
|
||||
items.append({col: {'$regex': self.input.get_text_search()}})
|
||||
filters.append({"$or": items})
|
||||
if self.input.extra_filter:
|
||||
filters.extend(self.input.extra_filter)
|
||||
if self.soft_deleted:
|
||||
filters.append({'deleted_at': {'$exists': False}})
|
||||
if not filters:
|
||||
return {}
|
||||
self.filters = {'$and': filters}
|
||||
return self.filters
|
||||
|
||||
def set_sort(self):
|
||||
if self.input.o.field:
|
||||
return {'key_or_list': self.input.o.field,
|
||||
'direction': 1 if self.input.o.direction == "asc" else -1}
|
||||
elif self.default_sort_by:
|
||||
return self.default_sort_by
|
||||
else:
|
||||
return {'key_or_list': 'created_at', 'direction': -1}
|
||||
|
||||
@staticmethod
|
||||
def filter_item_generator(item: FilterItem) -> dict:
|
||||
if MongoEngine.is_valid_uuid(str(item.col)):
|
||||
return {
|
||||
'data': {
|
||||
"$elemMatch": {
|
||||
'field_id': UUID(item.col),
|
||||
'value': {
|
||||
**MongoEngine.get_expression_filter(item.op, MongoEngine.cast_value(item.val, item.type), )}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {item.col: {
|
||||
**MongoEngine.get_expression_filter(col=item.col, op=item.op,
|
||||
val=MongoEngine.cast_value(item.val, item.type), )}}
|
||||
|
||||
@staticmethod
|
||||
def is_valid_uuid(uuid_to_test, version=4):
|
||||
try:
|
||||
uuid_obj = UUID(str(uuid_to_test), version=version)
|
||||
except ValueError:
|
||||
return False
|
||||
return str(uuid_obj) == str(uuid_to_test)
|
||||
|
||||
@staticmethod
|
||||
def cast_value(val: str, type: str) -> any:
|
||||
if type in ['NUMBER', 'STACK', 'FLOAT']:
|
||||
return float(val)
|
||||
if type == 'UUID':
|
||||
return UUID(str(val))
|
||||
return val
|
||||
|
||||
@staticmethod
|
||||
def get_expression_filter(col=None, op: str = 'eq', val: str = '') -> dict:
|
||||
_op = MongoEngine.get_operator(op)
|
||||
if _op == "sw":
|
||||
return {'$regex': f'^{val}'}
|
||||
elif _op == "ew":
|
||||
return {'$regex': f'{val}$'}
|
||||
elif _op == "n_ew":
|
||||
return {'$regex': f'(?<!{val})$'}
|
||||
elif _op == "n_sw":
|
||||
return {'$regex': f'^(?!{val})'}
|
||||
elif _op == "n_like":
|
||||
return {'$not': {'$regex': val}}
|
||||
elif _op == "bet":
|
||||
if isinstance(val, str):
|
||||
return {'$gte': val.split('-')[0], '$lte': val.split('-')[1]}
|
||||
return {'$gte': val[0], '$lte': val[1]}
|
||||
elif _op == "n_bet":
|
||||
if isinstance(val, str):
|
||||
return {'$gte': val.split('-')[0], '$lte': val.split('-')[1]}
|
||||
return {'$not': {'$gte': val[0], '$lte': val[1]}}
|
||||
elif _op == "exi":
|
||||
return {'$exists': True}
|
||||
elif _op == "n_exi":
|
||||
return {'$exists': False}
|
||||
elif _op == "in":
|
||||
return {'$exists': True}
|
||||
elif _op == "not_in":
|
||||
return {'$exists': False}
|
||||
return {_op: val}
|
||||
|
||||
@staticmethod
|
||||
def get_operator(op: str) -> str:
|
||||
ops = {
|
||||
"eq": "$eq",
|
||||
"n_eq": "$ne",
|
||||
"gt": "$gt",
|
||||
"ge": "$ge",
|
||||
"lt": "$lt",
|
||||
"le": "$le",
|
||||
"like": "$regex",
|
||||
"n_like": "n_like",
|
||||
"sw": "sw",
|
||||
"ew": "ew",
|
||||
'n_ew': 'n_ew',
|
||||
'n_sw': 'n_sw',
|
||||
'exi': 'exi',
|
||||
"n_exi": "n_exi",
|
||||
'lte': '$lte',
|
||||
'gte': '$gte',
|
||||
'in': 'in',
|
||||
'n_in': 'not_in',
|
||||
'bet': 'bet',
|
||||
'n_bet': 'n_bet',
|
||||
}
|
||||
return ops[op] if op in ops else '$eq'
|
||||
|
||||
async def count(self):
|
||||
return await self.query_class.count_documents(self.filters)
|
||||
|
||||
@staticmethod
|
||||
def generate_scope_filter(filters: list, general=False):
|
||||
if len(filters) == 1:
|
||||
_o = filters[0]
|
||||
if isinstance(_o, FilterItem):
|
||||
return MongoEngine.filter_item_generator(filters[0])
|
||||
elif isinstance(_o, FilterScope):
|
||||
return MongoEngine.generate_scope_filter(_o.items)
|
||||
else:
|
||||
return _o
|
||||
else:
|
||||
_a = filters.pop(0)
|
||||
_a = (MongoEngine.filter_item_generator(_a) if isinstance(_a,
|
||||
FilterItem) else _a) if not general else (
|
||||
MongoEngine.generate_scope_filter(_a.items) if isinstance(_a, FilterScope) else _a)
|
||||
_b = filters.pop(0)
|
||||
op = '$' + (_b.cr if not general else _b.op)
|
||||
_b = (MongoEngine.filter_item_generator(_b) if isinstance(_b,
|
||||
FilterItem) else _b) if not general else (
|
||||
MongoEngine.generate_scope_filter(_b.items) if isinstance(_b, FilterScope) else _b)
|
||||
filters = [{op: [
|
||||
_a, _b
|
||||
]}] + filters
|
||||
return MongoEngine.generate_scope_filter(filters, general)
|
||||
|
||||
def set_joins(self):
|
||||
pass
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
from sqlalchemy import or_, and_, desc, asc
|
||||
from sqlalchemy.sql.elements import BooleanClauseList, BinaryExpression, UnaryExpression
|
||||
|
||||
from .AbstractEngine import AbstractEngineClass
|
||||
from ..utils.Models import FilterItem, FilterScope
|
||||
|
||||
|
||||
class MsSqlEngine(AbstractEngineClass):
|
||||
|
||||
def set_joins(self):
|
||||
pass
|
||||
|
||||
filters = {}
|
||||
rows = []
|
||||
sort = None
|
||||
|
||||
async def exe(self):
|
||||
_f = self.set_filters()
|
||||
if not self.custom_entities:
|
||||
query = self.query_class.query(self.model)
|
||||
else:
|
||||
query = self.query_class.query(*self.custom_entities)
|
||||
if self.joins:
|
||||
for j in self.joins:
|
||||
if isinstance(j, list):
|
||||
query = query.join(*j)
|
||||
else:
|
||||
query = query.join(j)
|
||||
|
||||
if self.options:
|
||||
query = query.options(*self.options)
|
||||
tmp = query.filter(_f).order_by(self.set_sort())
|
||||
self.rows = tmp.limit(self.input.get_limit()).offset(self.input.skip()).all()
|
||||
return self.rows, tmp.count(), tmp
|
||||
|
||||
def query_generator(self):
|
||||
if not self.input.has_filter():
|
||||
return None
|
||||
filters = self.input.filters()
|
||||
query = self.generate_scope_filter(filters, general=True)
|
||||
return query
|
||||
|
||||
def set_sort(self):
|
||||
if self.input.o.field:
|
||||
self.sort = asc(getattr(self.model, self.input.o.field)) if self.input.o.direction == 'asc' else desc(
|
||||
getattr(self.model, self.input.o.field))
|
||||
return self.sort
|
||||
elif isinstance(self.default_sort_by, UnaryExpression):
|
||||
return self.default_sort_by
|
||||
else:
|
||||
return True
|
||||
|
||||
def set_filters(self):
|
||||
filters = []
|
||||
query = self.query_generator()
|
||||
if isinstance(query, BooleanClauseList) or isinstance(query, BinaryExpression):
|
||||
filters.append(query)
|
||||
if self.input.has_text_search():
|
||||
items = []
|
||||
_search_cols = self.input.get_search_cols() if (
|
||||
self.input.get_search_cols() and len(self.input.get_search_cols())) else self.search_cols
|
||||
if _search_cols:
|
||||
for col in _search_cols:
|
||||
has_join = len(col.split('.')) > 1
|
||||
if has_join:
|
||||
pass
|
||||
else:
|
||||
items.append(
|
||||
getattr(self.model, col).ilike("%{search}%".format(search=self.input.get_text_search())))
|
||||
filters.append(or_(*items))
|
||||
if self.input.extra_filter:
|
||||
for f in self.input.extra_filter:
|
||||
filters.append(f)
|
||||
if not filters:
|
||||
return True
|
||||
self.filters = and_(*filters)
|
||||
return self.filters
|
||||
|
||||
@staticmethod
|
||||
def get_expression_filter(col=None, op: str = '', val: str = '') -> dict:
|
||||
_op = MsSqlEngine.get_operator(op)
|
||||
return getattr(col, op)(val)
|
||||
|
||||
@staticmethod
|
||||
def get_operator(op: str):
|
||||
ops = {
|
||||
"eq": "__eq__",
|
||||
"n_eq": "__ne__",
|
||||
"gt": "__gt__",
|
||||
"gte": "__ge__",
|
||||
"lte": "__lt__",
|
||||
"le": "__le__",
|
||||
"like": "ilike",
|
||||
"n_like": "notlike",
|
||||
"in": "in_",
|
||||
"n_in": "not_in",
|
||||
"bet": "between",
|
||||
"n_bet": "not_between",
|
||||
"sw": "startswith",
|
||||
"ew": "endswith",
|
||||
'n_ew': 'not_endswith',
|
||||
'n_sw': 'not_startswith',
|
||||
'exi': 'exi',
|
||||
"n_exi": "n_exi",
|
||||
}
|
||||
return ops[op] if op in ops else '__eq__'
|
||||
|
||||
@staticmethod
|
||||
def get_and_or(op):
|
||||
return or_ if op == 'or' else and_
|
||||
|
||||
def count(self):
|
||||
pass
|
||||
|
||||
def filter_item_generator(self, item: FilterItem):
|
||||
has_join = len(item.col.split('.')) > 1
|
||||
if has_join:
|
||||
|
||||
pass
|
||||
else:
|
||||
return getattr(getattr(self.model, item.col), self.get_operator(item.op))(item.val)
|
||||
|
||||
def generate_scope_filter(self, filters: list, general=False):
|
||||
if len(filters) == 1:
|
||||
_o = filters[0]
|
||||
if isinstance(_o, FilterItem):
|
||||
return self.filter_item_generator(filters[0])
|
||||
elif isinstance(_o, FilterScope):
|
||||
return self.generate_scope_filter(_o.items)
|
||||
else:
|
||||
return _o
|
||||
else:
|
||||
_a = filters.pop(0)
|
||||
_a = (self.filter_item_generator(_a) if isinstance(_a,
|
||||
FilterItem) else _a) if not general else (
|
||||
self.generate_scope_filter(_a.items) if isinstance(_a, FilterScope) else _a)
|
||||
|
||||
_b = filters.pop(0)
|
||||
|
||||
_op = MsSqlEngine.get_and_or(_b.cr if not general else _b.op)
|
||||
_b = (self.filter_item_generator(_b) if isinstance(_b,
|
||||
FilterItem) else _b) if not general else (
|
||||
self.generate_scope_filter(_b.items) if isinstance(_b, FilterScope) else _b)
|
||||
|
||||
filters = [_op(_a, _b)] + filters
|
||||
return self.generate_scope_filter(filters, general)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
from .AbstractEngine import AbstractEngineClass
|
||||
|
||||
|
||||
class PgSqlEngine(AbstractEngineClass):
|
||||
|
||||
def exe(self):
|
||||
pass
|
||||
|
||||
def get_filters(self):
|
||||
pass
|
||||
|
||||
def pagination(self):
|
||||
pass
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
from enum import Enum
|
||||
from .Mssql import MsSqlEngine
|
||||
from .Pgsql import PgSqlEngine
|
||||
from .Mongo import MongoEngine
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,23 @@
|
|||
from typing import Generic, TypeVar, List, Optional
|
||||
|
||||
from pydantic.generics import GenericModel
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class TableEngineInputType(GenericModel, Generic[T]):
|
||||
f: Optional[List]
|
||||
o: Optional[dict] = {}
|
||||
p: Optional[dict] = {}
|
||||
s: Optional[dict] = {}
|
||||
|
||||
|
||||
class TableEngineExport(GenericModel, Generic[T]):
|
||||
rows: Optional[List[T]]
|
||||
total: Optional[int]
|
||||
page: Optional[int]
|
||||
te: Optional[TableEngineInputType]
|
||||
|
||||
|
||||
class TableEngineRequestType(GenericModel, Generic[T]):
|
||||
te: Optional[TableEngineInputType]
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import json
|
||||
|
||||
from sqlalchemy.orm import DeclarativeMeta
|
||||
|
||||
|
||||
class AlchemyEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj.__class__, DeclarativeMeta):
|
||||
fields = {}
|
||||
for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
|
||||
data = obj.__getattribute__(field)
|
||||
try:
|
||||
json.dumps(data)
|
||||
fields[field] = data
|
||||
except TypeError:
|
||||
fields[field] = None
|
||||
return fields
|
||||
|
||||
return json.JSONEncoder.default(self, obj)
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
from enum import Enum
|
||||
from typing import Optional, Any, List
|
||||
|
||||
import pydantic
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class FilterItem(BaseModel):
|
||||
col: Optional[str]
|
||||
cr: Optional[str]
|
||||
id: Optional[str]
|
||||
op: Optional[str]
|
||||
type: Optional[str]
|
||||
val: Optional[Any]
|
||||
|
||||
@staticmethod
|
||||
def ValidItem(item: dict):
|
||||
return item.get('col') and \
|
||||
item.get('id') and \
|
||||
item.get('op') and \
|
||||
item.get('type')
|
||||
|
||||
@staticmethod
|
||||
def ValidValue(item: dict):
|
||||
return len(str(item.get('val', '')).strip()) > 0
|
||||
|
||||
|
||||
class Cr(str, Enum):
|
||||
OR = 'or'
|
||||
AND = 'and'
|
||||
|
||||
|
||||
class FilterScope(BaseModel):
|
||||
id: str
|
||||
items: Optional[List[FilterItem]]
|
||||
op: Optional[Cr]
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
if kwargs.get('items'):
|
||||
self.items = [
|
||||
FilterItem(**item) for item in filter(lambda i: FilterItem.ValidItem(i), kwargs.get('items', []))]
|
||||
self.op = Cr(kwargs.get('op'))
|
||||
self.id = str(kwargs.get('id'))
|
||||
|
||||
@staticmethod
|
||||
def ValidScope(item: dict):
|
||||
return item.get('id') and item.get('items') and len(
|
||||
item.get('items')) > 0 and item.get('op')
|
||||
|
||||
@staticmethod
|
||||
def CleanItems(item):
|
||||
clone = item.dict()
|
||||
clone['items'] = list(filter(
|
||||
lambda i: FilterItem.ValidValue(i), clone.get(
|
||||
'items', [])))
|
||||
return FilterScope(**clone)
|
||||
|
||||
|
||||
class Page(BaseModel):
|
||||
c: int = 1
|
||||
s: int = 5
|
||||
|
||||
|
||||
class SearchModel(BaseModel):
|
||||
text: Optional[str]
|
||||
cols: Optional[List[Any]]
|
||||
|
||||
|
||||
class SortModel(BaseModel):
|
||||
field: Optional[str]
|
||||
direction: Optional[str]
|
||||
|
||||
|
||||
class JoinModel(BaseModel):
|
||||
model: BaseModel
|
||||
show: List[str]
|
||||
search: Optional[List[str]]
|
||||
|
||||
|
||||
class Config:
|
||||
extra = pydantic.Extra.ignore
|
||||
any_str_strip_whitespace = True # strip whitespaces from strings
|
||||
underscore_attrs_are_private = False
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
class TableEngineInput(BaseModel):
|
||||
f: Optional[List[FilterScope]]
|
||||
extra_filter: list = []
|
||||
o: Optional[SortModel]
|
||||
p: Optional[Page] = Page()
|
||||
s: Optional[SearchModel]
|
||||
is_deleted: Optional[bool]
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
_input = {**{'p': {'c': 1, 's': 5},
|
||||
'f': [], 's': {}, 'o': {}}, **(kwargs or {})}
|
||||
self.p = Page(**_input.get('p'))
|
||||
self.o = SortModel(**_input.get('o'))
|
||||
if _input.get('f'):
|
||||
self.f = [FilterScope(**f) for f in
|
||||
filter(lambda fs: FilterScope.ValidScope(fs), _input.get('f'))]
|
||||
self.f = list(map(lambda fs: FilterScope.CleanItems(fs), self.f))
|
||||
if _input.get('s'):
|
||||
self.s = SearchModel(**_input.get('s'))
|
||||
|
||||
def limit(self):
|
||||
return self.p.s
|
||||
|
||||
def order(self):
|
||||
return self.o
|
||||
|
||||
def filters(self) -> List[FilterScope]:
|
||||
return self.f
|
||||
|
||||
def has_filter(self) -> bool:
|
||||
return self.f is not None and \
|
||||
len(self.f) > 0 and \
|
||||
self.f[0].items is not None and \
|
||||
len(self.f[0].items) > 0
|
||||
|
||||
def has_extra_filter(self) -> bool:
|
||||
return self.extra_filter is not None and \
|
||||
len(self.extra_filter) > 0
|
||||
|
||||
def skip(self):
|
||||
return self.page() * self.p.s
|
||||
|
||||
def page(self):
|
||||
return self.p.c - 1
|
||||
|
||||
def virtual_page(self):
|
||||
return self.page() + 1
|
||||
|
||||
def get_limit(self):
|
||||
limit = self.p.s if self.p else 20
|
||||
return limit if limit < 100 else 100
|
||||
|
||||
def text_search_cols(self, cols: List[str]):
|
||||
if self.s:
|
||||
self.s.cols = cols
|
||||
|
||||
def has_text_search(self) -> bool:
|
||||
return self.s is not None and self.s.text is not None and len(self.s.text.strip()) > 0
|
||||
|
||||
def add_filter(self, _filter):
|
||||
self.extra_filter.append(_filter)
|
||||
|
||||
def get_search_cols(self) -> List[str]:
|
||||
return self.s.cols if self.s else []
|
||||
|
||||
def get_text_search(self) -> str:
|
||||
return self.s.text.strip() if self.s else None
|
||||
|
||||
|
||||
class WorkingMode(Enum):
|
||||
Development = "development"
|
||||
Production = "production"
|
||||
Binary file not shown.
|
|
@ -0,0 +1,34 @@
|
|||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.engine import URL
|
||||
|
||||
|
||||
connection_url = URL.create(
|
||||
"postgresql",
|
||||
username="iralex",
|
||||
password="thestrongpassword!!!!!2",
|
||||
host="ira-lex.postgres.database.azure.com",
|
||||
port=5432,
|
||||
database="iralex",
|
||||
)
|
||||
|
||||
|
||||
engine = create_engine(
|
||||
connection_url
|
||||
)
|
||||
|
||||
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from sqlalchemy.ext.declarative import declarative_base
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
class ExtraFilter:
|
||||
@staticmethod
|
||||
def AccountLawyeruser(model: Base):
|
||||
return None
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import uvicorn
|
||||
from app import app
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from config import conf
|
||||
import badmin.urls
|
||||
|
||||
|
||||
@app.get('/ping')
|
||||
def ping():
|
||||
return {"message": "pong", "production": conf.IS_PROD}
|
||||
|
||||
|
||||
origins = [
|
||||
"http://localhost",
|
||||
"http://172.30.10.2",
|
||||
"http://192.168.15.77:3300",
|
||||
"http://localhost:3100",
|
||||
"http://adapter.haco.dc",
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.router.redirect_slashes = False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(app, host="0.0.0.0", port=5000)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
joins = {
|
||||
'AccountLawyeruser': [
|
||||
'avatar',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
search_cols = {
|
||||
'AccountLawyeruser': ['last_name']
|
||||
}
|
||||
|
||||
|
||||
routes = {
|
||||
'account-lawyer-user': 'AccountLawyeruser',
|
||||
'auth-group': 'AuthGroup'
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
[tool.poetry]
|
||||
name = "badmin"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["ar.azizan <ar.azizan@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
fastapi = "^0.83.0"
|
||||
uvicorn = {extras = ["standard"], version = "^0.18.3"}
|
||||
SQLAlchemy = "^1.4.41"
|
||||
pycryptodome = "^3.15.0"
|
||||
ecdsa = "^0.18.0"
|
||||
psycopg2 = "^2.9.3"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from fastapi.security import OAuth2PasswordBearer
|
||||
|
||||
oauth2 = OAuth2PasswordBearer(
|
||||
tokenUrl="token",
|
||||
scopes={
|
||||
"account": "Read information about the current user.",
|
||||
},
|
||||
)
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
from fastapi import Security, APIRouter, HTTPException, Depends
|
||||
from fastapi.routing import APIRoute
|
||||
from fastapi.security import SecurityScopes
|
||||
from jose import jwt, JWTError
|
||||
from pydantic import ValidationError
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import Response
|
||||
from starlette.routing import BaseRoute
|
||||
|
||||
import schema
|
||||
from config import conf
|
||||
|
||||
|
||||
class BaseRoute(APIRoute):
|
||||
def get_route_handler(self):
|
||||
original_route_handler = super().get_route_handler()
|
||||
|
||||
async def custom_route_handler(request: Request) -> Response:
|
||||
response: Response = await original_route_handler(request)
|
||||
return response
|
||||
|
||||
return custom_route_handler
|
||||
|
||||
|
||||
async def current_user(security_scopes: SecurityScopes, token: str = Depends(schema.oauth2)):
|
||||
# if security_scopes.scopes:
|
||||
# authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
|
||||
# else:
|
||||
authenticate_value = f"Bearer"
|
||||
credentials_exception = HTTPException(
|
||||
status_code=401,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": authenticate_value},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
token, conf.AUTH_SECRET_KEY, algorithms=[
|
||||
conf.AUTH_ALGORITHM])
|
||||
username: str = payload.get("username")
|
||||
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
except (JWTError, ValidationError):
|
||||
raise credentials_exception
|
||||
return username
|
||||
|
||||
|
||||
async def get_current_active_user(username=Security(current_user, scopes=["account"]), ):
|
||||
return username
|
||||
|
||||
|
||||
def generateRouter(
|
||||
prefix,
|
||||
dependencies=None,
|
||||
auth_dependencies=False
|
||||
):
|
||||
if auth_dependencies:
|
||||
dependencies = dependencies or []
|
||||
dependencies.extend([Security(get_current_active_user)])
|
||||
return APIRouter(
|
||||
prefix=f"{conf.PREFIX_API_URL}/{prefix}",
|
||||
route_class=BaseRoute,
|
||||
dependencies=dependencies if dependencies else []
|
||||
)
|
||||
Loading…
Reference in New Issue