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 | ||
155 | + | ||
156 | + #파일 객체 생성 | ||
157 | + object_name = request.GET.get('name', '') | ||
147 | 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