Merge branch 'feature/item_api+folder_api' into develop
Showing
5 changed files
with
117 additions
and
6 deletions
| ... | @@ -14,7 +14,7 @@ class Item(models.Model): | ... | @@ -14,7 +14,7 @@ class Item(models.Model): |
| 14 | is_deleted = models.BooleanField(default = False) | 14 | is_deleted = models.BooleanField(default = False) |
| 15 | created_time = models.DateTimeField(auto_now=True) | 15 | created_time = models.DateTimeField(auto_now=True) |
| 16 | updated_time = models.DateTimeField(null=True) | 16 | updated_time = models.DateTimeField(null=True) |
| 17 | - status = models.BooleanField() | 17 | + status = models.BooleanField(default=False) |
| 18 | 18 | ||
| 19 | #file = models.FileField(upload_to = \path) | 19 | #file = models.FileField(upload_to = \path) |
| 20 | 20 | ... | ... |
| ... | @@ -4,6 +4,7 @@ import os | ... | @@ -4,6 +4,7 @@ import os |
| 4 | from datetime import datetime, timedelta | 4 | from datetime import datetime, timedelta |
| 5 | 5 | ||
| 6 | import boto3 | 6 | import boto3 |
| 7 | +from botocore.client import Config | ||
| 7 | 8 | ||
| 8 | from django.core import serializers | 9 | from django.core import serializers |
| 9 | from django.views.decorators.csrf import csrf_exempt | 10 | from django.views.decorators.csrf import csrf_exempt |
| ... | @@ -20,7 +21,7 @@ from annoying.functions import get_object_or_None | ... | @@ -20,7 +21,7 @@ from annoying.functions import get_object_or_None |
| 20 | from django.conf import settings | 21 | from django.conf import settings |
| 21 | import jwt | 22 | import jwt |
| 22 | from django.http import HttpResponse, JsonResponse | 23 | from django.http import HttpResponse, JsonResponse |
| 23 | - | 24 | +from khudrive.settings import AWS_SESSION_TOKEN, AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, AWS_REGION, AWS_STORAGE_BUCKET_NAME |
| 24 | 25 | ||
| 25 | class UserViewSet(viewsets.ModelViewSet): | 26 | class UserViewSet(viewsets.ModelViewSet): |
| 26 | """ | 27 | """ |
| ... | @@ -144,15 +145,51 @@ class ItemViewSet(viewsets.ViewSet): | ... | @@ -144,15 +145,51 @@ class ItemViewSet(viewsets.ViewSet): |
| 144 | t['id'] = i['pk'] | 145 | t['id'] = i['pk'] |
| 145 | res.append(t) | 146 | res.append(t) |
| 146 | return Response({'data': {'list' : res}}, status=status.HTTP_200_OK) | 147 | return Response({'data': {'list' : res}}, status=status.HTTP_200_OK) |
| 148 | + """ | ||
| 149 | + # url: items/11/ | ||
| 150 | + # 마지막 slash도 써주어야함 | ||
| 151 | + def get(self, request, pk): | ||
| 152 | + #print(pk) | ||
| 153 | + s3 = boto3.client('s3') | ||
| 154 | + s3_bucket = AWS_STORAGE_BUCKET_NAME | ||
| 147 | 155 | ||
| 156 | + #파일 객체 생성 | ||
| 157 | + object_name = request.GET.get('name', '') | ||
| 158 | + | ||
| 159 | + presigned_url = s3.generate_presigned_url( | ||
| 160 | + 'get_object', | ||
| 161 | + Params={'Bucket': s3_bucket, | ||
| 162 | + 'Key': object_name}, | ||
| 163 | + ExpiresIn = 3600 | ||
| 164 | + ) | ||
| 165 | + | ||
| 166 | + return Response({'message': presigned_url}, status=status.HTTP_200_OK) | ||
| 167 | + """ | ||
| 148 | # url: items/11/ | 168 | # url: items/11/ |
| 149 | # 마지막 slash도 써주어야함 | 169 | # 마지막 slash도 써주어야함 |
| 150 | def get(self, request, pk): | 170 | def get(self, request, pk): |
| 171 | + s3 = boto3.client('s3', | ||
| 172 | + aws_access_key_id=AWS_ACCESS_KEY_ID, | ||
| 173 | + aws_secret_access_key=AWS_SECRET_ACCESS_KEY, | ||
| 174 | + aws_session_token=AWS_SESSION_TOKEN, | ||
| 175 | + config=Config(signature_version='s3v4')) | ||
| 176 | + s3_bucket = AWS_STORAGE_BUCKET_NAME | ||
| 177 | + | ||
| 151 | item = Item.objects.filter(item_id=pk) | 178 | item = Item.objects.filter(item_id=pk) |
| 179 | + object_name = item.get().name | ||
| 152 | data = serializers.serialize("json", item) | 180 | data = serializers.serialize("json", item) |
| 153 | json_data = json.loads(data) | 181 | json_data = json.loads(data) |
| 182 | + | ||
| 183 | + presigned_url = s3.generate_presigned_url( | ||
| 184 | + 'get_object', | ||
| 185 | + Params={'Bucket': s3_bucket, | ||
| 186 | + 'Key': object_name}, | ||
| 187 | + ExpiresIn = 3600 | ||
| 188 | + ) | ||
| 189 | + | ||
| 154 | res = json_data[0]['fields'] | 190 | res = json_data[0]['fields'] |
| 155 | res['id']=json_data[0]['pk'] | 191 | res['id']=json_data[0]['pk'] |
| 192 | + res['signed_url']=presigned_url | ||
| 156 | return Response({'data': res}, status=status.HTTP_200_OK) | 193 | return Response({'data': res}, status=status.HTTP_200_OK) |
| 157 | 194 | ||
| 158 | # url: items/11/ | 195 | # url: items/11/ |
| ... | @@ -273,6 +310,63 @@ class ItemViewSet(viewsets.ViewSet): | ... | @@ -273,6 +310,63 @@ class ItemViewSet(viewsets.ViewSet): |
| 273 | res['inside_file_list'] = [] | 310 | res['inside_file_list'] = [] |
| 274 | return Response({'data': res}, status=status.HTTP_200_OK) | 311 | return Response({'data': res}, status=status.HTTP_200_OK) |
| 275 | 312 | ||
| 313 | + # url: /upload/ | ||
| 314 | + @action(methods=['POST'], detail=True, permission_classes=[AllowAny], | ||
| 315 | + url_path='upload', url_name='upload') | ||
| 316 | + def upload(self, request, pk): | ||
| 317 | + if request.method == 'POST': | ||
| 318 | + s3 = boto3.client('s3') | ||
| 319 | + s3_bucket = AWS_STORAGE_BUCKET_NAME | ||
| 320 | + | ||
| 321 | + #파일 객체 생성 | ||
| 322 | + file_name = request.POST.get('name', '') | ||
| 323 | + file_size = request.POST.get('size', '') | ||
| 324 | + file_parent = pk | ||
| 325 | + file_type = mimetypes.guess_type(file_name)[0] | ||
| 326 | + upload_item = Item(name=file_name, size=file_size, user_id=1, file_type=file_type, parent=file_parent) | ||
| 327 | + upload_item.save() | ||
| 328 | + | ||
| 329 | + date_long = datetime.utcnow().strftime('%Y%m%dT000000Z') | ||
| 330 | + | ||
| 331 | + presigned_post = s3.generate_presigned_post( | ||
| 332 | + s3_bucket, | ||
| 333 | + file_name, | ||
| 334 | + { | ||
| 335 | + "acl": "private", | ||
| 336 | + "Content-Type": file_type, | ||
| 337 | + 'region': AWS_REGION, | ||
| 338 | + 'x-amz-algorithm': 'AWS4-HMAC-SHA256', | ||
| 339 | + 'x-amz-date': date_long | ||
| 340 | + }, | ||
| 341 | + [ | ||
| 342 | + {"acl": "private"}, | ||
| 343 | + {"Content-Type": file_type}, | ||
| 344 | + {'x-amz-algorithm': 'AWS4-HMAC-SHA256'}, | ||
| 345 | + {'x-amz-date': date_long} | ||
| 346 | + ], | ||
| 347 | + 3600 | ||
| 348 | + ) | ||
| 349 | + | ||
| 350 | + data = { | ||
| 351 | + "signed_url": presigned_post, | ||
| 352 | + 'url': 'https://%s.s3.amazonaws.com/%s' % (s3_bucket, file_name) | ||
| 353 | + } | ||
| 354 | + | ||
| 355 | + return Response({'presigned_post':presigned_post, 'proc_data':data}, status=status.HTTP_200_OK) | ||
| 356 | + | ||
| 357 | + # url: /status/ | ||
| 358 | + @action(methods=['POST'], detail=True, permission_classes=[AllowAny], | ||
| 359 | + url_path='status', url_name='status') | ||
| 360 | + def status(self, request, *args, **kwargs): | ||
| 361 | + if request.method == 'POST': | ||
| 362 | + pk = request.POST.get('item_id', '') | ||
| 363 | + queryset = Item.objects.filter(item_id = pk) | ||
| 364 | + for cand in queryset: | ||
| 365 | + cand.status = True | ||
| 366 | + cand.save() | ||
| 367 | + return Response({'Message': 'File Upload Successful'}, status=status.HTTP_200_OK) | ||
| 368 | + return Response({'Error': 'No such item found in queryset'}, status=status.HTTP_400_BAD_REQUEST) | ||
| 369 | + | ||
| 276 | 370 | ||
| 277 | class SharedItemViewSet(viewsets.ModelViewSet): | 371 | class SharedItemViewSet(viewsets.ModelViewSet): |
| 278 | 372 | ... | ... |
| ... | @@ -11,10 +11,17 @@ https://docs.djangoproject.com/en/3.0/ref/settings/ | ... | @@ -11,10 +11,17 @@ https://docs.djangoproject.com/en/3.0/ref/settings/ |
| 11 | """ | 11 | """ |
| 12 | 12 | ||
| 13 | import os | 13 | import os |
| 14 | +import sys | ||
| 15 | +import json | ||
| 14 | 16 | ||
| 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) | 17 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) |
| 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 18 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 17 | 19 | ||
| 20 | +ROOT_DIR = os.path.dirname(BASE_DIR) | ||
| 21 | +# secrets.json의 경로 | ||
| 22 | +SECRETS_PATH = os.path.join(ROOT_DIR, 'secrets.json') | ||
| 23 | +# json파일을 파이썬 객체로 변환 | ||
| 24 | +secrets = json.loads(open(SECRETS_PATH).read()) | ||
| 18 | 25 | ||
| 19 | # Quick-start development settings - unsuitable for production | 26 | # Quick-start development settings - unsuitable for production |
| 20 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ | 27 | # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/ |
| ... | @@ -82,8 +89,8 @@ DATABASES = { | ... | @@ -82,8 +89,8 @@ DATABASES = { |
| 82 | 'default': { | 89 | 'default': { |
| 83 | 'ENGINE': 'django.db.backends.postgresql', | 90 | 'ENGINE': 'django.db.backends.postgresql', |
| 84 | 'NAME': 'khuDrive', | 91 | 'NAME': 'khuDrive', |
| 85 | - 'USER': 'jooheekwon', | 92 | + 'USER': 'root', |
| 86 | - 'PASSWORD': '', | 93 | + 'PASSWORD': '1234', |
| 87 | 'HOST': 'localhost', | 94 | 'HOST': 'localhost', |
| 88 | 'PORT': '', | 95 | 'PORT': '', |
| 89 | } | 96 | } |
| ... | @@ -127,3 +134,11 @@ USE_TZ = True | ... | @@ -127,3 +134,11 @@ USE_TZ = True |
| 127 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ | 134 | # https://docs.djangoproject.com/en/3.0/howto/static-files/ |
| 128 | 135 | ||
| 129 | STATIC_URL = '/static/' | 136 | STATIC_URL = '/static/' |
| 137 | + | ||
| 138 | + | ||
| 139 | +#S3 | ||
| 140 | +DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' | ||
| 141 | +STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage' | ||
| 142 | + | ||
| 143 | +for key, value in secrets.items(): | ||
| 144 | + setattr(sys.modules[__name__], key, value) | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -33,8 +33,9 @@ urlpatterns = [ | ... | @@ -33,8 +33,9 @@ urlpatterns = [ |
| 33 | url(r'^<int:pk>/share/$', views.SharedItemViewSet.share, name='share'), | 33 | url(r'^<int:pk>/share/$', views.SharedItemViewSet.share, name='share'), |
| 34 | url(r'^<int:pk>/move/$', views.ItemViewSet.move, name='move'), | 34 | url(r'^<int:pk>/move/$', views.ItemViewSet.move, name='move'), |
| 35 | url(r'^<int:pk>/copy/$', views.ItemViewSet.copy, name='copy'), | 35 | url(r'^<int:pk>/copy/$', views.ItemViewSet.copy, name='copy'), |
| 36 | - url(r'^<int:pk>/children/$', views.ItemViewSet.children, name='copy'), | 36 | + url(r'^<int:pk>/children/$', views.ItemViewSet.children, name='children'), |
| 37 | url(r'^signup/$', views.UserViewSet.signup, name='signup'), | 37 | url(r'^signup/$', views.UserViewSet.signup, name='signup'), |
| 38 | url(r'^login/$', views.UserViewSet.login, name='login'), | 38 | url(r'^login/$', views.UserViewSet.login, name='login'), |
| 39 | - | 39 | + url(r'^upload/$', views.ItemViewSet.upload, name='upload'), |
| 40 | + url(r'^status/$', views.ItemViewSet.status, name='status'), | ||
| 40 | ] | 41 | ] | ... | ... |
-
Please register or login to post a comment