Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions API/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
API_APP_KEYCLOAK_URL=http://localhost:8080
API_APP_KEYCLOAK_REALM=reports-realm
API_APP_KEYCLOAK_CLIENT_ID=reports-api
2 changes: 2 additions & 0 deletions API/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
api_env
__pycache__
1 change: 1 addition & 0 deletions API/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.9.21
9 changes: 9 additions & 0 deletions API/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM python:3.9-slim

WORKDIR /API
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY main.py main.py

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
68 changes: 68 additions & 0 deletions API/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# from dotenv import load_dotenv
import csv
import io
import os

from fastapi import FastAPI, Depends, HTTPException, Security
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from keycloak import KeycloakOpenID

# load_dotenv()

KEYCLOAK_URL = os.environ.get("API_APP_KEYCLOAK_URL")
KEYCLOAK_REALM = os.environ.get("API_APP_KEYCLOAK_REALM")
KEYCLOAK_CLIENT_ID = os.environ.get("API_APP_KEYCLOAK_CLIENT_ID")

if not all([KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID]):
raise EnvironmentError("Не все обязательные переменные окружения установлены")

keycloak_openid = KeycloakOpenID(
server_url=KEYCLOAK_URL,
realm_name=KEYCLOAK_REALM,
client_id=KEYCLOAK_CLIENT_ID
)

app = FastAPI()

app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)

token_scheme = HTTPBearer()

async def verify_bearer_token(
token: HTTPAuthorizationCredentials = Security(token_scheme),
):
try:
payload = keycloak_openid.decode_token(token.credentials)
except Exception as e:
raise HTTPException(status_code=401, detail=f"Невалидный токен: {str(e)}")

all_user_roles = payload.get("realm_access", {}).get("roles", [])

if 'prothetic_user' not in all_user_roles:
raise HTTPException(status_code=403, detail="Недостаточно прав")

stub_report_data = [
["Name", "Age", "City"],
["Alice", 30, "New York"],
["Bob", 25, "Los Angeles"],
["Charlie", 35, "Chicago"]
]

@app.get("/reports")
def get_reports(_=Depends(verify_bearer_token)):
stream = io.StringIO()
writer = csv.writer(stream)
writer.writerows(stub_report_data)

response = StreamingResponse(iter([stream.getvalue()]), media_type="text/csv")
response.headers["Content-Disposition"] = "attachment; filename=report.csv"

return response
32 changes: 32 additions & 0 deletions API/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
aiofiles==24.1.0
annotated-types==0.7.0
anyio==4.9.0
async-property==0.2.2
certifi==2025.4.26
cffi==1.17.1
charset-normalizer==3.4.2
click==8.1.8
cryptography==45.0.3
deprecation==2.1.0
dotenv==0.9.9
exceptiongroup==1.3.0
fastapi==0.115.12
h11==0.16.0
httpcore==1.0.9
httpx==0.28.1
idna==3.10
jwcrypto==1.5.6
packaging==25.0
pycparser==2.22
pydantic==2.11.5
pydantic_core==2.33.2
python-dotenv==1.1.0
python-keycloak==5.5.1
requests==2.32.3
requests-toolbelt==1.0.0
sniffio==1.3.1
starlette==0.46.2
typing-inspection==0.4.1
typing_extensions==4.13.2
urllib3==2.4.0
uvicorn==0.34.2
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#### Как запустить проект

надо в корне репозитория выполнить команду:

```sh
docker-compose up -d --build
```

и когда все докер-контейнеры запустятся, открыть в браузере урл: http://localhost:3000
16 changes: 15 additions & 1 deletion docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ services:
KC_DB_URL: jdbc:postgresql://keycloak_db:5432/keycloak_db
KC_DB_USERNAME: keycloak_user
KC_DB_PASSWORD: keycloak_password
command:
command:
- start-dev
- --import-realm
volumes:
Expand All @@ -40,3 +40,17 @@ services:
REACT_APP_KEYCLOAK_URL: http://localhost:8080
REACT_APP_KEYCLOAK_REALM: reports-realm
REACT_APP_KEYCLOAK_CLIENT_ID: reports-frontend
depends_on:
- api
api:
build:
context: ./API
dockerfile: Dockerfile
ports:
- "8000:8000"
environment:
API_APP_KEYCLOAK_URL: http://keycloak:8080
API_APP_KEYCLOAK_REALM: reports-realm
API_APP_KEYCLOAK_CLIENT_ID: reports-api
depends_on:
- keycloak
11 changes: 11 additions & 0 deletions frontend/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": false,
"singleQuote": true,
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid"
}
Loading