권주희

Merge branch 'feature/item_api+folder_api' into develop

...@@ -27,3 +27,4 @@ npm-debug.log* ...@@ -27,3 +27,4 @@ npm-debug.log*
27 yarn-debug.log* 27 yarn-debug.log*
28 yarn-error.log* 28 yarn-error.log*
29 .idea 29 .idea
30 +secrets.json
......
...@@ -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 ]
......