first commit
This commit is contained in:
93
service_app/.dockerignore
Normal file
93
service_app/.dockerignore
Normal file
@@ -0,0 +1,93 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
.gitattributes
|
||||
|
||||
|
||||
# CI
|
||||
.codeclimate.yml
|
||||
.travis.yml
|
||||
.taskcluster.yml
|
||||
|
||||
# Docker
|
||||
docker-compose.yml
|
||||
service_app/Dockerfile
|
||||
.docker
|
||||
.dockerignore
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
**/__pycache__/
|
||||
**/*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
service_app/env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Virtual environment
|
||||
service_app/.env
|
||||
.venv/
|
||||
venv/
|
||||
|
||||
# PyCharm
|
||||
.idea
|
||||
|
||||
# Python mode for VIM
|
||||
.ropeproject
|
||||
**/.ropeproject
|
||||
|
||||
# Vim swap files
|
||||
**/*.swp
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
|
||||
test_application/
|
||||
|
||||
|
||||
162
service_app/.gitignore
vendored
Normal file
162
service_app/.gitignore
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
# ---> Python
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.idea/
|
||||
.Python
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
service_app/.env
|
||||
.venv
|
||||
service_app/env/
|
||||
venv/
|
||||
service_app/env/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
32
service_app/Dockerfile
Normal file
32
service_app/Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
|
||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
||||
|
||||
COPY ../service_app/requirements.txt .
|
||||
|
||||
RUN uv venv
|
||||
RUN uv pip install -r requirements.txt
|
||||
|
||||
COPY ../service_app ./service_app
|
||||
|
||||
COPY ../databases ./service_app/databases
|
||||
COPY ../api_services ./service_app/api_services
|
||||
COPY ../api_objects ./service_app/api_objects
|
||||
COPY ../api_configs ./service_app/api_configs
|
||||
COPY ../api_events ./service_app/api_events
|
||||
COPY ../api_library ./service_app/api_library
|
||||
COPY ../api_validations ./service_app_init/api_validations
|
||||
|
||||
WORKDIR /service_app
|
||||
|
||||
CMD ["uv", "run", "app.py"]
|
||||
|
||||
# Old File
|
||||
#FROM python:3.10
|
||||
|
||||
#RUN pip install --upgrade pip
|
||||
#RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
||||
#CMD ["python", "-m", "app"]
|
||||
0
service_app/__init__.py
Normal file
0
service_app/__init__.py
Normal file
51
service_app/app.py
Normal file
51
service_app/app.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import uvicorn
|
||||
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.exceptions import HTTPException
|
||||
|
||||
from middlewares.token_middleware import AuthHeaderMiddleware
|
||||
from application.create_file import create_app
|
||||
from handlers_exception import (
|
||||
exception_handler_http,
|
||||
exception_handler_exception,
|
||||
)
|
||||
from prometheus_fastapi_instrumentator import Instrumentator
|
||||
from prometheus_client import Counter, Histogram
|
||||
|
||||
|
||||
app = create_app()
|
||||
Instrumentator().instrument(app=app).expose(app=app)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
**{
|
||||
"allow_origins": ["*"],
|
||||
"allow_credentials": True,
|
||||
"allow_methods": ["*"],
|
||||
"allow_headers": ["*"],
|
||||
}
|
||||
)
|
||||
app.add_middleware(AuthHeaderMiddleware)
|
||||
|
||||
app.add_exception_handler(HTTPException, exception_handler_http)
|
||||
app.add_exception_handler(Exception, exception_handler_exception)
|
||||
|
||||
# # Define a counter metric
|
||||
# REQUESTS_COUNT = Counter(
|
||||
# "requests_total", "Total number of requests", ["method", "endpoint", "status_code"]
|
||||
# )
|
||||
# # Define a histogram metric
|
||||
# REQUESTS_TIME = Histogram("requests_time", "Request processing time", ["method", "endpoint"])
|
||||
# api_request_summary = Histogram("api_request_summary", "Request processing time", ["method", "endpoint"])
|
||||
# api_request_counter = Counter("api_request_counter", "Request processing time", ["method", "endpoint", "http_status"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn_config = {
|
||||
"app": "app:app",
|
||||
"host": "0.0.0.0",
|
||||
"port": 41575,
|
||||
"log_level": "info",
|
||||
"reload": True,
|
||||
}
|
||||
uvicorn.Server(uvicorn.Config(**uvicorn_config)).run()
|
||||
0
service_app/application/__init__.py
Normal file
0
service_app/application/__init__.py
Normal file
66
service_app/application/create_file.py
Normal file
66
service_app/application/create_file.py
Normal file
@@ -0,0 +1,66 @@
|
||||
|
||||
|
||||
def create_app():
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from api_configs import Config
|
||||
import routers
|
||||
|
||||
|
||||
api_app = FastAPI(title=str(Config.TITLE), default_response_class=JSONResponse)
|
||||
|
||||
@api_app.get("/", include_in_schema=False, summary=str(Config.DESCRIPTION))
|
||||
async def home():
|
||||
return RedirectResponse(url="/docs")
|
||||
|
||||
for router in list(
|
||||
[
|
||||
getattr(routers, router)
|
||||
for router in routers.__all__
|
||||
if getattr(routers, router)
|
||||
]
|
||||
):
|
||||
api_app.include_router(router)
|
||||
|
||||
openapi_schema = get_openapi(
|
||||
title=Config.TITLE,
|
||||
description=Config.DESCRIPTION,
|
||||
version="0.0.1",
|
||||
routes=api_app.routes,
|
||||
)
|
||||
|
||||
if "components" in openapi_schema:
|
||||
openapi_schema["components"]["securitySchemes"] = {
|
||||
"Bearer Auth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "evyos-session-key",
|
||||
"description": "Enter: **'Bearer <JWT>'**, where JWT is the access token",
|
||||
}
|
||||
}
|
||||
|
||||
for route in api_app.routes:
|
||||
path = str(getattr(route, "path"))
|
||||
if route.include_in_schema:
|
||||
methods = [method.lower() for method in getattr(route, "methods")]
|
||||
for method in methods:
|
||||
if path not in Config.INSECURE_PATHS:
|
||||
openapi_schema["paths"][path][method]["security"] = [
|
||||
{"Bearer Auth": []}
|
||||
]
|
||||
openapi_schema["paths"][path][method]["responses"]["403"] = {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": "Returned if user is unauthorized.",
|
||||
}
|
||||
|
||||
api_app.openapi_schema = openapi_schema
|
||||
return api_app
|
||||
5
service_app/env
Normal file
5
service_app/env
Normal file
@@ -0,0 +1,5 @@
|
||||
DATABASE_URL=postgresql+psycopg2://berkay_wag_user:berkay_wag_user_password@postgres_commercial:5432/wag_database
|
||||
REDIS_HOST=commercial_memory_service
|
||||
REDIS_PASSWORD=commercial_redis_password
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=0
|
||||
9
service_app/handlers_exception/__init__.py
Normal file
9
service_app/handlers_exception/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from .api_exception_handlers.http_exception_handler import (
|
||||
exception_handler_http,
|
||||
exception_handler_exception,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"exception_handler_http",
|
||||
"exception_handler_exception",
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
from json import loads
|
||||
from fastapi import status
|
||||
|
||||
from fastapi.requests import Request
|
||||
from fastapi.exceptions import HTTPException
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
|
||||
def exception_handler_http(request: Request, exc: HTTPException):
|
||||
print('headers', request.headers)
|
||||
detail = loads(exc.detail)
|
||||
return JSONResponse(
|
||||
status_code=exc.status_code,
|
||||
content={
|
||||
"Data": detail.get('data', {}),
|
||||
"Error": detail.get('error_case', 'UNKNOWN'),
|
||||
"Message": detail.get('message', 'An error occurred while processing the request')
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def exception_handler_exception(request: Request, exc: Exception):
|
||||
print('headers', request.headers)
|
||||
return JSONResponse(
|
||||
status_code=status.HTTP_417_EXPECTATION_FAILED, content={"message": exc.__str__()}
|
||||
)
|
||||
|
||||
0
service_app/handlers_extensions/__init__.py
Normal file
0
service_app/handlers_extensions/__init__.py
Normal file
1
service_app/middlewares/__init__.py
Normal file
1
service_app/middlewares/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .token_middleware import AuthHeaderMiddleware
|
||||
115
service_app/middlewares/token_middleware.py
Normal file
115
service_app/middlewares/token_middleware.py
Normal file
@@ -0,0 +1,115 @@
|
||||
import json
|
||||
|
||||
from time import perf_counter
|
||||
from api_configs import Config
|
||||
from starlette import status
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
|
||||
class MiddlewareLogs:
|
||||
|
||||
@staticmethod
|
||||
def log_error(self, log_message):
|
||||
print(log_message)
|
||||
|
||||
|
||||
def log_middlewares_exception(endpoint, token_user, message, request):
|
||||
MiddlewareLogs.log_error(
|
||||
str(
|
||||
{
|
||||
"log_type": "Authentication",
|
||||
"log_message": message,
|
||||
"log_action": "User",
|
||||
"log_data": json.dumps(
|
||||
{
|
||||
"endpoint": endpoint,
|
||||
"user": str(token_user),
|
||||
"request": str(request.headers),
|
||||
}
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class AuthHeaderMiddleware(BaseHTTPMiddleware):
|
||||
|
||||
async def dispatch(self, request, call_next):
|
||||
start_time, token_user, endpoint = perf_counter(), None, None
|
||||
|
||||
if check_if_path_secure(request=request, insecure_paths=Config.INSECURE_PATHS):
|
||||
endpoint = str(getattr(getattr(request, "url", None), "path", None))
|
||||
if un_auth := check_if_token_is_not_valid(
|
||||
request=request, endpoint_name=endpoint
|
||||
):
|
||||
auth, token_user = un_auth
|
||||
if not auth == "valid":
|
||||
# log_middlewares_exception(endpoint, token_user, "auth", request)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail=auth
|
||||
)
|
||||
|
||||
response = await call_next(request)
|
||||
prepare_response_needs(response, start_time)
|
||||
# if endpoint and token_user:
|
||||
# log_middlewares_exception(endpoint, token_user, "Request is completed", request)
|
||||
return response
|
||||
|
||||
|
||||
def prepare_response_needs(response, start_time):
|
||||
end_time = perf_counter()
|
||||
response.headers["request-starts"], response.headers["request-ends"] = str(
|
||||
start_time
|
||||
), str(end_time)
|
||||
response.headers["elapsed-Time"] = str(float(end_time) - float(start_time)) + " ms"
|
||||
|
||||
|
||||
def check_if_path_secure(request, insecure_paths) -> bool:
|
||||
return str(getattr(getattr(request, "url", None), "path", None)) not in insecure_paths
|
||||
|
||||
|
||||
def check_if_token_is_not_valid(request, endpoint_name):
|
||||
from api_services.redis.functions import get_object_via_access_key
|
||||
|
||||
token_user = get_object_via_access_key(request)
|
||||
if not token_user:
|
||||
return "Session geçerli değil. Lütfen tekrar giriş yapınız.", token_user
|
||||
|
||||
return "valid", token_user
|
||||
|
||||
# on_token_user: Users = Users.find_one(uu_id=token_user["uu_id"])
|
||||
# on_token_people: People = on_token_user.person
|
||||
# #
|
||||
# # if on_token_people.priority == 78:
|
||||
# # return "valid", token_user
|
||||
#
|
||||
# if not token_user.get("duty_id", None):
|
||||
# return (
|
||||
# "Kullanıcı hiçbir yetki tanımlanmamıştır. Supervisor ile iletişime geçiniz.",
|
||||
# token_user,
|
||||
# )
|
||||
|
||||
# CompanyDutyApp.session.commit()
|
||||
# CompanyDutyApp.session.flush()
|
||||
#
|
||||
# if endpoint_name in release_endpoint:
|
||||
# return "valid", token_user
|
||||
#
|
||||
# if company_duty_app := CompanyDutyApp.find_one(
|
||||
# endpoint_name=str("".join(endpoint_name.split("/")[:-1])),
|
||||
# company_duty_id=int(token_user.get("duty_id")),
|
||||
# ):
|
||||
# if not company_duty_app.is_access_valid(
|
||||
# endpoint_ext=endpoint_name.split("/")[-1]
|
||||
# ):
|
||||
# return (
|
||||
# "Kullanıcı yetkili değildir. Supervisor ile iletişime geçiniz.",
|
||||
# token_user,
|
||||
# )
|
||||
# else:
|
||||
# return (
|
||||
# "Kullanıcıya yetki tanımlanmamıştır. Supervisor ile iletişime geçiniz.",
|
||||
# token_user,
|
||||
# )
|
||||
|
||||
# return "valid", token_user
|
||||
18
service_app/requirements.txt
Normal file
18
service_app/requirements.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
arrow
|
||||
Deprecated
|
||||
fastapi
|
||||
python-dotenv
|
||||
uvicorn
|
||||
pydantic
|
||||
sqlalchemy-mixins
|
||||
redis
|
||||
psycopg2-binary
|
||||
pymongo
|
||||
rsa
|
||||
redmail
|
||||
unidecode
|
||||
textdistance
|
||||
pandas
|
||||
cryptography
|
||||
prometheus-client
|
||||
prometheus-fastapi-instrumentator
|
||||
3
service_app/routers/__init__.py
Normal file
3
service_app/routers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
__all__ = []
|
||||
0
service_app/templates/__init__.py
Normal file
0
service_app/templates/__init__.py
Normal file
Reference in New Issue
Block a user