This commit is contained in:
Untone 2024-05-06 11:33:53 +03:00
commit 3242758817
6 changed files with 70 additions and 54 deletions

View File

@ -1,8 +1,5 @@
name: 'deploy'
on:
push:
branches:
- main
name: 'Deploy on Push'
on: [push]
jobs:
deploy:
@ -21,10 +18,19 @@ jobs:
id: branch_name
run: echo "::set-output name=branch::$(echo ${GITHUB_REF##*/})"
- name: Push to dokku
- name: Push to dokku for main branch
if: github.ref == 'refs/heads/main'
uses: dokku/github-action@master
with:
branch: 'main'
git_remote_url: 'ssh://dokku@staging.discours.io:22/${{ steps.repo_name.outputs.repo }}'
git_remote_url: 'ssh://dokku@v2.discours.io:22/uploader'
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
git_push_flags: '--force'
- name: Push to dokku for staging branch
if: github.ref == 'refs/heads/dev'
uses: dokku/github-action@master
with:
branch: 'main'
git_remote_url: 'ssh://dokku@staging.discours.io:22/uploader'
ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}

1
.gitignore vendored
View File

@ -8,3 +8,4 @@ __pycache__
.pytest_cache
.venv
*.gz.tar
DELETEME

View File

@ -25,3 +25,18 @@ poetry env use .venv/bin/python3.12
poetry update
poetry run python main.py
```
### Интеграция в Core
Добавить в nginx.conf.sigil ссылку на /upload
```
# Custom location block for /upload
location /connect/ {
http://upload-8080/;
{{ $proxy_settings }}
{{ $gzip_settings }}
{{ $cors_headers_options }}
{{ $cors_headers_post }}
{{ $cors_headers_get }}
}
```
при такой структуре ссылка будет core.domain.com/upload

34
auth.py
View File

@ -1,22 +1,18 @@
from functools import wraps
from starlette.responses import JSONResponse
import aiohttp
from aiohttp import web
AUTH_URL = 'https://auth.discours.io'
async def check_auth(req):
token = req.headers.get("Authorization")
headers = {"Authorization": token, "Content-Type": "application/json"} # "Bearer " + removed
headers = {"Authorization": token, "Content-Type": "application/json"}
print(f"[services.auth] checking auth token: {token}")
query_name = "session"
query_type = "query"
operation = "GetUserId"
gql = {
"query": query_type + " " + operation + " { " + query_name + " { user { id } } }",
"operationName": operation,
"query": "query GetUserId { session { user { id } } }",
"operationName": "GetUserId",
"variables": None,
}
@ -27,25 +23,19 @@ async def check_auth(req):
return False, None
r = await response.json()
if r:
user_id = r.get("data", {}).get(query_name, {}).get("user", {}).get("id", None)
user_id = r.get("data", {}).get("session", {}).get("user", {}).get("id", None)
is_authenticated = user_id is not None
return is_authenticated, user_id
return False, None
def login_required(f):
@wraps(f)
async def decorated_function(*args, **kwargs):
info = args[1]
context = info.context
req = context.get("request")
is_authenticated, user_id = await check_auth(req)
async def decorated_function(request, *args, **kwargs):
is_authenticated, user_id = await check_auth(request)
if not is_authenticated:
raise web.HTTPUnauthorized(text="You are not logged in") # Return HTTP 401 Unauthorized
else:
context["user_id"] = user_id
# If the user is authenticated, execute the resolver
return await f(*args, **kwargs)
return JSONResponse({'error': 'Unauthorized'}, status_code=401)
# Make user_id available to the route handler, if needed
request.state.user_id = user_id
return await f(request, *args, **kwargs)
return decorated_function

46
main.py
View File

@ -1,14 +1,16 @@
import logging
import os
import tempfile
import uuid
import boto3
from botocore.exceptions import BotoCoreError, ClientError
import aioboto3
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from starlette.requests import Request
from auth import check_auth
# Logging configuration
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
STORJ_ACCESS_KEY = os.environ.get('STORJ_ACCESS_KEY')
STORJ_SECRET_KEY = os.environ.get('STORJ_SECRET_KEY')
@ -16,54 +18,56 @@ STORJ_END_POINT = os.environ.get('STORJ_END_POINT')
STORJ_BUCKET_NAME = os.environ.get('STORJ_BUCKET_NAME')
CDN_DOMAIN = os.environ.get('CDN_DOMAIN')
@check_auth
async def upload_handler(request: Request):
logging.debug("Received upload request")
form = await request.form()
file = form.get('file')
if file is None:
logging.error("No file uploaded")
return JSONResponse({'error': 'No file uploaded'}, status_code=400)
file_name, file_extension = os.path.splitext(file.filename)
key = str(uuid.uuid4()) + file_extension
logging.debug(f"Generated file key: {key}")
s3 = boto3.client('s3',
aws_access_key_id=STORJ_ACCESS_KEY,
aws_secret_access_key=STORJ_SECRET_KEY,
endpoint_url=STORJ_END_POINT)
try:
async with aioboto3.client('s3',
aws_access_key_id=STORJ_ACCESS_KEY,
aws_secret_access_key=STORJ_SECRET_KEY,
endpoint_url=STORJ_END_POINT) as s3:
with tempfile.NamedTemporaryFile() as tmp_file:
while True:
chunk = await file.read(8192) # 8192 bytes by default.
chunk = await file.read(8192)
if not chunk:
break
tmp_file.write(chunk)
tmp_file.flush()
s3.upload_file(
logging.debug("Starting file upload to S3")
await s3.upload_file(
Filename=tmp_file.name,
Bucket=STORJ_BUCKET_NAME,
Key=key,
ExtraArgs={
"ContentType": file.content_type
}
ExtraArgs={"ContentType": file.content_type}
)
logging.debug("File upload completed")
url = 'http://' + CDN_DOMAIN + '/' + key
url = f'http://{CDN_DOMAIN}/{key}'
logging.info(f"File uploaded successfully: {url}")
return JSONResponse({'url': url, 'originalFilename': file.filename})
except (BotoCoreError, ClientError) as e:
print(e)
return JSONResponse({'error': 'Failed to upload file'}, status_code=500)
async def home(request: Request):
logging.debug("Home route called")
return JSONResponse({'message': 'Hello World!'})
routes = [
Route('/upload', upload_handler, methods=['POST']),
Route('/test', home, methods=['GET']),
Route('/', upload_handler, methods=['POST'])
]
app = Starlette(debug=True, routes=routes)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host='0.0.0.0', port=80)
uvicorn.run(app, host='0.0.0.0', port=8080)

View File

@ -11,8 +11,8 @@ python = "^3.12"
aiohttp = "^3.9.1"
uvicorn = "^0.24.0.post1"
starlette = "^0.33.0"
boto3 = "^1.33.6"
botocore = "^1.33.6"
aioboto3 = "^9.0.0"
python-multipart = "^0.0.5"
[tool.poetry.dev-dependencies]
black = "^23.10.1"