|
1 | | -import asyncio |
2 | | -import json |
3 | | -from datetime import time |
4 | | -from asgiref.sync import sync_to_async |
5 | | -from aiohttp import ClientSession |
| 1 | +import time |
| 2 | + |
| 3 | +import requests |
6 | 4 | from django.db import transaction |
7 | | -from django.utils.decorators import classonlymethod |
8 | 5 | from rest_framework import permissions, status |
9 | 6 | from rest_framework.response import Response |
10 | 7 | from rest_framework.views import APIView |
11 | 8 |
|
| 9 | +from files.exceptions import SelectelUploadError |
12 | 10 | from files.models import UserFile |
13 | 11 | from procollab.settings import ( |
14 | 12 | DEBUG, |
|
22 | 20 | class FileUploadView(APIView): |
23 | 21 | permission_classes = [permissions.AllowAny] |
24 | 22 |
|
25 | | - @classonlymethod |
26 | | - def as_view(cls, **initkwargs): |
27 | | - view = super().as_view(**initkwargs) |
28 | | - view._is_coroutine = asyncio.coroutines._is_coroutine |
29 | | - return view |
30 | | - |
31 | 23 | @transaction.atomic |
32 | | - async def post(self, request): |
33 | | - file = request.FILES["file"] |
| 24 | + def post(self, request): |
34 | 25 | if DEBUG is True: |
35 | 26 | return Response( |
36 | 27 | {"message": "Files doesn't save in development mode, sorry <3"}, |
37 | 28 | status=status.HTTP_406_NOT_ACCEPTABLE, |
38 | 29 | ) |
39 | 30 |
|
| 31 | + file = request.FILES["file"] |
40 | 32 | link = f"https://api.selcdn.ru/v1/SEL_{SELECTEL_ACCOUNT_ID}/{SELECTEL_CONTAINER_NAME}/" |
41 | | - |
42 | 33 | user = request.user |
| 34 | + token = self._get_token() |
43 | 35 |
|
44 | | - # creates UserFile object in the database |
45 | | - self._save_to_db(user, link) |
46 | | - token = await self._get_token() |
47 | | - async with ClientSession(headers={"X-Auth-Token": token}) as server: |
48 | | - if len(file.split(".")) > 1: |
49 | | - extension = file.filename.split(".")[1] |
50 | | - else: |
51 | | - extension = "" |
52 | | - |
53 | | - # looks like /hashed_email/hashed_filename_hashed_time.extension |
54 | | - url = ( |
55 | | - link + f"/{SELECTEL_CONTAINER_NAME}/{abs(hash(user.email))}/" |
56 | | - f"{abs(hash(file.filename))}_{abs(hash(time.time()))}.{extension}" |
57 | | - ) |
| 36 | + if len(file.name.split(".")) > 1: |
| 37 | + extension = file.name.split(".")[1] |
| 38 | + else: |
| 39 | + extension = "" |
58 | 40 |
|
59 | | - async with server.put( |
| 41 | + # looks like /hashedEmail/hashedFilename_hashedTime.extension |
| 42 | + url = ( |
| 43 | + link + f"{SELECTEL_CONTAINER_NAME}/{abs(hash(user.email))}/" |
| 44 | + f"{abs(hash(file.name))}_{abs(hash(time.time()))}{'.' + extension if extension else ''}" |
| 45 | + ) |
| 46 | + with file.open(mode="rb") as file_object: |
| 47 | + r = requests.put( |
60 | 48 | url, |
61 | | - data=file.open(mode="rb").read(), |
62 | | - ) as response: |
63 | | - if response.status != 201: |
64 | | - return await Response( |
65 | | - "Failed to upload file", status_code=status.HTTP_409_CONFLICT |
66 | | - ) |
67 | | - return await Response({"url": url}, status=status.HTTP_201_CREATED) |
| 49 | + headers={ |
| 50 | + "X-Auth-Token": token, |
| 51 | + "X-Object-Meta-Content-Type": file_object.content_type, |
| 52 | + }, |
| 53 | + files={"file": (file.name, file_object, file.content_type)}, |
| 54 | + ) |
| 55 | + if r.status_code != 201: |
| 56 | + return Response("Failed to upload file", status=status.HTTP_409_CONFLICT) |
| 57 | + self._save_to_db(user, url) |
| 58 | + return Response({"url": url}, status=status.HTTP_201_CREATED) |
68 | 59 |
|
69 | | - @sync_to_async |
70 | | - def _save_to_db(self, user, link): |
| 60 | + @classmethod |
| 61 | + def _save_to_db(cls, user, url): |
71 | 62 | """creates userfile object for file uploads""" |
72 | | - return UserFile.objects.create(user=user, link=link) |
| 63 | + return UserFile.objects.create(user=user, link=url) |
73 | 64 |
|
74 | | - async def _get_token(self): |
| 65 | + @classmethod |
| 66 | + def _get_token(cls): |
75 | 67 | """returns auth token for sentry""" |
76 | | - async with ClientSession() as server: |
77 | | - data = { |
78 | | - "auth": { |
79 | | - "identity": { |
80 | | - "methods": ["password"], |
81 | | - "password": { |
82 | | - "user": { |
83 | | - "id": SELECTEL_CONTAINER_USERNAME, |
84 | | - "password": SELECTEL_CONTAINER_PASSWORD, |
85 | | - } |
86 | | - }, |
87 | | - } |
| 68 | + data = { |
| 69 | + "auth": { |
| 70 | + "identity": { |
| 71 | + "methods": ["password"], |
| 72 | + "password": { |
| 73 | + "user": { |
| 74 | + "id": SELECTEL_CONTAINER_USERNAME, |
| 75 | + "password": SELECTEL_CONTAINER_PASSWORD, |
| 76 | + } |
| 77 | + }, |
88 | 78 | } |
89 | 79 | } |
90 | | - async with server.post( |
91 | | - "https://api.selcdn.ru/v3/auth/tokens", |
92 | | - data=json.dumps(data), |
93 | | - ) as response: |
94 | | - if response.status != 201: |
95 | | - return Response( |
96 | | - "Failed to get token", status_code=status.HTTP_409_CONFLICT |
97 | | - ) |
98 | | - return response.json() |
| 80 | + } |
| 81 | + r = requests.post("https://api.selcdn.ru/v3/auth/tokens", json=data) |
| 82 | + if r.status_code not in [200, 201]: |
| 83 | + raise SelectelUploadError("couldn't generate a token for selcdn") |
| 84 | + return r.headers["x-subject-token"] |
| 85 | + # async with server.post( |
| 86 | + # "https://api.selcdn.ru/v3/auth/tokens", |
| 87 | + # data=json.dumps(data), |
| 88 | + # ) as response: |
| 89 | + # if response.status != 201: |
| 90 | + # return Response( |
| 91 | + # "Failed to get token", status_code=status.HTTP_409_CONFLICT |
| 92 | + # ) |
| 93 | + # return response.json() |
0 commit comments