Init Commit

This commit is contained in:
ar.azizan 2022-09-13 18:38:41 +04:30
commit 39446c49ca
55 changed files with 3753 additions and 0 deletions

25
.env Normal file
View File

@ -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'

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/poetry.lock
/venv/

8
.idea/.gitignore vendored Normal file
View File

@ -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/

12
.idea/badmin.iml Normal file
View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml Normal file
View File

@ -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>

8
.idea/modules.xml Normal file
View File

@ -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>

14
.idea/webResources.xml Normal file
View File

@ -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>

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.10.7

0
README.md Normal file
View File

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.

94
a.md Normal file
View File

@ -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

19
app.py Normal file
View File

@ -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")

0
badmin/__init__.py Normal file
View File

Binary file not shown.

View File

@ -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.

2439
badmin/models/model.py Normal file

File diff suppressed because it is too large Load Diff

67
badmin/urls/__init__.py Normal file
View File

@ -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.

58
config.py Normal file
View File

@ -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')

130
core/te/__init__.py Normal file
View File

@ -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.

View File

@ -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

175
core/te/engines/Mongo.py Normal file
View File

@ -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

146
core/te/engines/Mssql.py Normal file
View File

@ -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)

13
core/te/engines/Pgsql.py Normal file
View File

@ -0,0 +1,13 @@
from .AbstractEngine import AbstractEngineClass
class PgSqlEngine(AbstractEngineClass):
def exe(self):
pass
def get_filters(self):
pass
def pagination(self):
pass

View File

@ -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.

23
core/te/types.py Normal file
View File

@ -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]

19
core/te/utils/Encoder.py Normal file
View File

@ -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)

160
core/te/utils/Models.py Normal file
View File

@ -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.

34
database.py Normal file
View File

@ -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()

8
filter.py Normal file
View File

@ -0,0 +1,8 @@
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class ExtraFilter:
@staticmethod
def AccountLawyeruser(model: Base):
return None

33
main.py Normal file
View File

@ -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)

16
map.py Normal file
View File

@ -0,0 +1,16 @@
joins = {
'AccountLawyeruser': [
'avatar',
]
}
search_cols = {
'AccountLawyeruser': ['last_name']
}
routes = {
'account-lawyer-user': 'AccountLawyeruser',
'auth-group': 'AuthGroup'
}

20
pyproject.toml Normal file
View File

@ -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"

8
schema.py Normal file
View File

@ -0,0 +1,8 @@
from fastapi.security import OAuth2PasswordBearer
oauth2 = OAuth2PasswordBearer(
tokenUrl="token",
scopes={
"account": "Read information about the current user.",
},
)

0
tests/__init__.py Normal file
View File

64
utils.py Normal file
View File

@ -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 []
)