서승완
Builds for 2 pipelines canceled in 15 minutes 31 seconds

Merge branch 'feature/upload' into 'master'

Feature/upload



See merge request !8
...@@ -23,7 +23,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ...@@ -23,7 +23,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
23 SECRET_KEY = 'wfs076redt^-5_*dw6!_dqz*2z!a_#()33y@r_q7&+4r_40h9$' 23 SECRET_KEY = 'wfs076redt^-5_*dw6!_dqz*2z!a_#()33y@r_q7&+4r_40h9$'
24 24
25 # SECURITY WARNING: don't run with debug turned on in production! 25 # SECURITY WARNING: don't run with debug turned on in production!
26 -DEBUG = True 26 +DEBUG = False
27 27
28 ALLOWED_HOSTS = ['127.0.0.1', 'khubox-api.khunet.net'] 28 ALLOWED_HOSTS = ['127.0.0.1', 'khubox-api.khunet.net']
29 29
...@@ -49,6 +49,7 @@ MIDDLEWARE = [ ...@@ -49,6 +49,7 @@ MIDDLEWARE = [
49 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 'django.contrib.auth.middleware.AuthenticationMiddleware',
50 'django.contrib.messages.middleware.MessageMiddleware', 50 'django.contrib.messages.middleware.MessageMiddleware',
51 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 'django.middleware.clickjacking.XFrameOptionsMiddleware',
52 + 'khubox.middlewares.auth.AuthMiddleware',
52 ] 53 ]
53 54
54 ROOT_URLCONF = 'config.urls' 55 ROOT_URLCONF = 'config.urls'
...@@ -128,9 +129,6 @@ STATIC_URL = '/static/' ...@@ -128,9 +129,6 @@ STATIC_URL = '/static/'
128 129
129 # Custom Settings 130 # Custom Settings
130 S3_BUCKET = 'khubox-files' 131 S3_BUCKET = 'khubox-files'
131 -CDN_PATH = 'https://khubox-files.khunet.net'
132 -CLOUDFRONT_KEY_ID = 'APKAJ3FOBWI34OZJTXJQ'
133 -CLOUDFRONT_KEY_PRIVATE = '-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA18VtzURs+fQev5L00LRwRbJaObQI4kfJCIsOE7eWSOqq4Akh\nA7fI6vs3z8orXBvgc+k6GgAHrIdNwckxoQuTsCxrTDm1104qy1T4JkVxkIBYHJgH\nGzKUloK5IqdmcYbOK7IQeHJ2gR9Mv/3oKUytJSsrbM9k4oLrsxGpyEuJeHIg28aP\nwhoVWmBGcPu48l4aYAZEVY7LZRJSOQ9y7Lf8FS1u7Xtw1P91gEaqrqVXqRWY02C8\nsixpJJuiAPnM3rpcpVNlAaPdDkWmaWYJoJDOlce7Dmx1a9Ckr24krM//vpEljurC\nGml0AsHpL8LE9msM5VA+miCxCz/K+wDgm2xvvQIDAQABAoIBAFmP3pLceyuJVBYK\n5smWjB+x91eKTkG2sFB2f8JZau0bUxApWeXULHa1DiaW8UaLX7BdN7vBFW5cvz7X\nx1zklEoFNghuz/btwD+kJlikbI4hZ/F+fTyh0yFiY3xp5dDrtrpWcBW+1UeleVMc\nDnjOFfSepajFsUeANlue0k2MZSRz34s2T2scV5ZkooqdXddYUF/wDhefYm6uvCgI\nPyvY/mbJTyhte/xagY/m6yzk5gxgad0qP2ZZrHhLLMlJ/GEZToWDxD2xUei61NQT\nFFc5ZutkAE6fVb3I4SJUBSX5fl0tTMz4Aak1GP2phMhjZyjYnQMq8kvL4BNFb7gp\nary8W/UCgYEA+eKkfjjlPsEx6yHMhD7pAwy/MpUqJmF5LMxIG+qfd+GZMQ2oucn5\npUAwBHP7BD6E9H7/7jdjnCiO+iPrzM9vNLfqsdCtPWzoFYJp/6Fv002uX8seNYvJ\nQyQqrM85LYIghhnkcmJMA8GR/Iu5ZEeE2BkAl9T2EKclzmB62d/ki6MCgYEA3Q0V\nz08IEwSJW+jEsOM+XGg2YkNqCVKGQD9n4CPx0TFVJxfqFl2nVwlN2hfrlJLUQ9+l\nfXnS5AW3tE88t9we+ea0saJZEqqlm/rGsfTV/twS9cWSgvG5fTzhUbu9/ElMU29L\nmydQfWTvCup7zCuQtgwM5ZRtPwuKsI8urUg6zR8CgYAt0coZvvMCI8i0dbkbkrGF\nNqQkcUeOTBc9CKQ8QjRFdh9x6DBFCOz2ySNE3cNsTs5wSo1BL/Ta4HD/GvEU2ABr\nKUImor3xYnPX5dbr4b0wgLD1rbf3V49q+Um98C1q086E6GCEPNP1aFwNc81lvtt0\nCHmcXZdVDGEZS4WbR7uPgwKBgBO/moY12lPQoPDsH75p3uVkjg9DVJLWo5XT1FTr\nASyeSqw+b7Rl05BsDV+BqZNRdtNFhMRsANJMTHg4aAVJDh9nZBdGmMyZIEiKI/w8\nEm49fRgl+YvnSpoMuViS/EswxTfjBo8q+P7q6IxCHKNF9Ry+gNx14TizsEVL1XC3\ntkEjAoGBAMyp7wdPobJMXcclRVq6rqHs9OMcnZAveVKyxNgDbZu4OB5X4xTxGEYT\nNZQ0MFf/HcwlnH7797gVQeqF9dlqUJYe+Fc8lc/Rcwta/4R5uMgri9t8RKN91YKF\nUUFBsDEkWlkoAmfPkcrrq9cLJlmSNt3ehQj4p5iAJwoVBXXa++PO\n-----END RSA PRIVATE KEY-----'
134 132
135 133
136 # Cors 134 # Cors
......
1 import boto3 1 import boto3
2 -import datetime
3 -from botocore.signers import CloudFrontSigner
4 -from cryptography.hazmat.backends import default_backend
5 -from cryptography.hazmat.primitives import hashes, serialization
6 -from cryptography.hazmat.primitives.asymmetric import padding
7 from django.conf import settings 2 from django.conf import settings
8 3
9 4
10 -def rsa_signer(message): 5 +def sign_download(file_id):
11 - private_key = serialization.load_pem_private_key( 6 + s3 = boto3.client('s3')
12 - settings.CLOUDFRONT_KEY_PRIVATE.encode('ascii'), 7 + signed_url = s3.generate_presigned_url(
13 - password=None, 8 + 'get_object',
14 - backend=default_backend() 9 + Params={'Bucket': settings.S3_BUCKET, 'Key': file_id},
10 + ExpiresIn=3600,
11 + HttpMethod='GET'
15 ) 12 )
16 - return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())
17 -
18 -
19 -def sign_download(url):
20 - expire_date = datetime.datetime.utcnow() + datetime.timedelta(hours=1)
21 - cloudfront_signer = CloudFrontSigner(settings.CLOUDFRONT_KEY_ID, rsa_signer)
22 - signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date)
23 return signed_url 13 return signed_url
24 14
25 15
...@@ -52,3 +42,13 @@ def s3_copy(file_id, new_file_id): ...@@ -52,3 +42,13 @@ def s3_copy(file_id, new_file_id):
52 } 42 }
53 obj = bucket.Object(str(new_file_id)) 43 obj = bucket.Object(str(new_file_id))
54 obj.copy(copy_source) 44 obj.copy(copy_source)
45 +
46 +
47 +def s3_update_and_return_size(file_id, name):
48 + s3 = boto3.resource('s3')
49 + s3_object = s3.Object(settings.S3_BUCKET, file_id)
50 + s3_object.copy_from(CopySource={'Bucket': settings.S3_BUCKET, 'Key': file_id},
51 + ContentType='application/octet-stream',
52 + ContentDisposition='attachment; filename=%s' % name,
53 + MetadataDirective='REPLACE')
54 + return s3_object.content_length
......
1 +import os
2 +import django
3 +from .aws import s3_delete, s3_update_and_return_size
4 +from .models import File
5 +
6 +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
7 +django.setup()
8 +
9 +
10 +def process_upload(event, context):
11 + file_id = event['Records'][0]['s3']['object']['key']
12 + file = File.objects.filter(id=file_id, deleted_at__isnull=True)
13 +
14 + # File Gone
15 + if len(file) == 0:
16 + s3_delete([file_id])
17 + return
18 +
19 + # Update
20 + file[0].size = s3_update_and_return_size(file_id, file[0].name)
21 + file[0].save()
1 +import jwt
2 +from django.conf import settings
3 +from django.http import JsonResponse
4 +
5 +
6 +class AuthMiddleware:
7 + def __init__(self, get_response):
8 + self.get_response = get_response
9 +
10 + def __call__(self, request):
11 + if 'HTTP_AUTHORIZATION' in request.META:
12 + token = str(request.META['HTTP_AUTHORIZATION'])[7:]
13 + try:
14 + decoded = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
15 + request.user_id = decoded['id']
16 + except jwt.exceptions.DecodeError:
17 + return JsonResponse({'result': False, 'error': '토큰이 잘못되었습니다.'})
18 + except jwt.exceptions.ExpiredSignatureError:
19 + return JsonResponse({'result': False, 'error': '토큰이 만료되었습니다.'})
20 + else:
21 + request.user_id = None
22 +
23 + response = self.get_response(request)
24 + return response
1 import json 1 import json
2 import uuid 2 import uuid
3 -from django.conf import settings
4 from django.utils import timezone 3 from django.utils import timezone
5 -from ..aws import sign_upload, sign_download, s3_copy, s3_delete 4 +from pathvalidate import sanitize_filename
5 +from ..aws import sign_upload, sign_download, s3_copy, s3_delete, s3_update_and_return_size
6 from ..models import File, GroupUser 6 from ..models import File, GroupUser
7 7
8 8
9 # 폴더/파일 목록 9 # 폴더/파일 목록
10 def list_item(request): 10 def list_item(request):
11 - # TODO: Auth 11 + # Check Login
12 - request.user_id = 1 12 + if request.user_id is None:
13 + return {'result': False, 'error': '로그인을 해주세요.'}
13 14
14 # Validate 15 # Validate
15 if request.GET.get('is_public') != 'true' \ 16 if request.GET.get('is_public') != 'true' \
16 and request.GET.get('is_starred') != 'true' \ 17 and request.GET.get('is_starred') != 'true' \
17 and request.GET.get('is_trashed') != 'true': 18 and request.GET.get('is_trashed') != 'true':
18 - return {'result': False, 'error': '입력이 누락되었습니다.'} 19 + return {'result': False, 'error': '잘못된 요청입니다.'}
19 20
20 # Query Files 21 # Query Files
21 files = None 22 files = None
...@@ -26,7 +27,7 @@ def list_item(request): ...@@ -26,7 +27,7 @@ def list_item(request):
26 elif request.GET.get('is_trashed') == 'true': 27 elif request.GET.get('is_trashed') == 'true':
27 files = File.objects.filter(owner_user_id=request.user_id, is_trashed=1, deleted_at__isnull=True) 28 files = File.objects.filter(owner_user_id=request.user_id, is_trashed=1, deleted_at__isnull=True)
28 29
29 - # Structure 30 + # Serialize
30 data = [] 31 data = []
31 for file in files: 32 for file in files:
32 data.append({ 33 data.append({
...@@ -45,23 +46,24 @@ def list_item(request): ...@@ -45,23 +46,24 @@ def list_item(request):
45 46
46 # 폴더 생성, 파일 업로드 47 # 폴더 생성, 파일 업로드
47 def create(request): 48 def create(request):
48 - # TODO: Auth 49 + # Check Login
49 - request.user_id = 1 50 + if request.user_id is None:
51 + return {'result': False, 'error': '로그인을 해주세요.'}
50 52
51 # Load 53 # Load
52 try: 54 try:
53 received = json.loads(request.body.decode('utf-8')) 55 received = json.loads(request.body.decode('utf-8'))
54 except json.decoder.JSONDecodeError: 56 except json.decoder.JSONDecodeError:
55 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 57 + return {'result': False, 'error': '잘못된 요청입니다.'}
56 58
57 # Validate 59 # Validate
58 if 'parent_id' not in received \ 60 if 'parent_id' not in received \
59 or 'type' not in received \ 61 or 'type' not in received \
60 or 'name' not in received: 62 or 'name' not in received:
61 - return {'result': False, 'error': '입력이 누락되었습니다.'} 63 + return {'result': False, 'error': '잘못된 요청입니다.'}
62 if (received['type'] != 'folder' and received['type'] != 'file') \ 64 if (received['type'] != 'folder' and received['type'] != 'file') \
63 or received['name'] == '': 65 or received['name'] == '':
64 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 66 + return {'result': False, 'error': '잘못된 요청입니다.'}
65 67
66 # Get Parent 68 # Get Parent
67 parent = File.objects.filter(id=received['parent_id'], is_trashed=0, deleted_at__isnull=True) 69 parent = File.objects.filter(id=received['parent_id'], is_trashed=0, deleted_at__isnull=True)
...@@ -89,7 +91,7 @@ def create(request): ...@@ -89,7 +91,7 @@ def create(request):
89 owner_group_id=parent[0].owner_group_id, 91 owner_group_id=parent[0].owner_group_id,
90 uploader_id=request.user_id, 92 uploader_id=request.user_id,
91 type=received['type'], 93 type=received['type'],
92 - name=received['name'], 94 + name=sanitize_filename(received['name']),
93 size=0, 95 size=0,
94 created_at=timezone.now() 96 created_at=timezone.now()
95 ) 97 )
...@@ -105,8 +107,9 @@ def create(request): ...@@ -105,8 +107,9 @@ def create(request):
105 107
106 # 휴지통 비우기 108 # 휴지통 비우기
107 def empty_trash(request): 109 def empty_trash(request):
108 - # TODO: Auth 110 + # Check Login
109 - request.user_id = 1 111 + if request.user_id is None:
112 + return {'result': False, 'error': '로그인을 해주세요.'}
110 113
111 # Query Files 114 # Query Files
112 files = File.objects.filter(owner_user_id=request.user_id, is_trashed=1, deleted_at__isnull=True) 115 files = File.objects.filter(owner_user_id=request.user_id, is_trashed=1, deleted_at__isnull=True)
...@@ -138,8 +141,9 @@ def empty_trash(request): ...@@ -138,8 +141,9 @@ def empty_trash(request):
138 141
139 # 폴더/파일 조회 142 # 폴더/파일 조회
140 def find_item(request, file_id): 143 def find_item(request, file_id):
141 - # TODO: Auth 144 + # Check Login
142 - request.user_id = 1 145 + if request.user_id is None:
146 + return {'result': False, 'error': '로그인을 해주세요.'}
143 147
144 # Query 148 # Query
145 file = File.objects.filter(id=file_id, deleted_at__isnull=True) 149 file = File.objects.filter(id=file_id, deleted_at__isnull=True)
...@@ -174,12 +178,10 @@ def find_item(request, file_id): ...@@ -174,12 +178,10 @@ def find_item(request, file_id):
174 178
175 # Return File 179 # Return File
176 if file[0].type == 'file': 180 if file[0].type == 'file':
177 - download_url = '%s/%s' % (settings.CDN_PATH, file[0].id) 181 + download_url = sign_download(file[0].id)
178 - download_url = sign_download(download_url)
179 data = { 182 data = {
180 'id': file[0].id, 183 'id': file[0].id,
181 'parent_id': file[0].parent_id, 184 'parent_id': file[0].parent_id,
182 - 'uploader_id': file[0].uploader_id,
183 'name': file[0].name, 185 'name': file[0].name,
184 'size': file[0].size, 186 'size': file[0].size,
185 'is_public': file[0].is_public, 187 'is_public': file[0].is_public,
...@@ -213,14 +215,15 @@ def find_item(request, file_id): ...@@ -213,14 +215,15 @@ def find_item(request, file_id):
213 215
214 # 폴더/파일 수정 216 # 폴더/파일 수정
215 def update_item(request, file_id): 217 def update_item(request, file_id):
216 - # TODO: Auth 218 + # Check Login
217 - request.user_id = 1 219 + if request.user_id is None:
220 + return {'result': False, 'error': '로그인을 해주세요.'}
218 221
219 # Load 222 # Load
220 try: 223 try:
221 received = json.loads(request.body.decode('utf-8')) 224 received = json.loads(request.body.decode('utf-8'))
222 except json.decoder.JSONDecodeError: 225 except json.decoder.JSONDecodeError:
223 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 226 + return {'result': False, 'error': '잘못된 요청입니다.'}
224 227
225 # Validate 228 # Validate
226 if 'name' not in received \ 229 if 'name' not in received \
...@@ -228,7 +231,7 @@ def update_item(request, file_id): ...@@ -228,7 +231,7 @@ def update_item(request, file_id):
228 and 'is_public' not in received \ 231 and 'is_public' not in received \
229 and 'is_starred' not in received \ 232 and 'is_starred' not in received \
230 and 'is_trashed' not in received: 233 and 'is_trashed' not in received:
231 - return {'result': False, 'error': '입력이 누락되었습니다.'} 234 + return {'result': False, 'error': '잘못된 요청입니다.'}
232 235
233 # Query 236 # Query
234 file = File.objects.filter(id=file_id, deleted_at__isnull=True) 237 file = File.objects.filter(id=file_id, deleted_at__isnull=True)
...@@ -267,7 +270,10 @@ def update_item(request, file_id): ...@@ -267,7 +270,10 @@ def update_item(request, file_id):
267 270
268 # Update 271 # Update
269 if 'name' in received: 272 if 'name' in received:
270 - file[0].name = received['name'] 273 + if received['name'] == '':
274 + return {'result': False, 'error': '이름을 제대로 입력해주세요.'}
275 + file[0].name = sanitize_filename(received['name'])
276 + s3_update_and_return_size(file_id, file[0].name)
271 if 'parent_id' in received: 277 if 'parent_id' in received:
272 file[0].parent_id = received['parent_id'] 278 file[0].parent_id = received['parent_id']
273 if 'is_public' in received: 279 if 'is_public' in received:
...@@ -285,8 +291,9 @@ def update_item(request, file_id): ...@@ -285,8 +291,9 @@ def update_item(request, file_id):
285 291
286 # 파일 복제 292 # 파일 복제
287 def copy(request, file_id): 293 def copy(request, file_id):
288 - # TODO: Auth 294 + # Check Login
289 - request.user_id = 1 295 + if request.user_id is None:
296 + return {'result': False, 'error': '로그인을 해주세요.'}
290 297
291 # Get File 298 # Get File
292 file = File.objects.filter(id=file_id, type='file', is_trashed=0, deleted_at__isnull=True) 299 file = File.objects.filter(id=file_id, type='file', is_trashed=0, deleted_at__isnull=True)
......
...@@ -7,18 +7,19 @@ from ..models import File, Group, GroupUser, User ...@@ -7,18 +7,19 @@ from ..models import File, Group, GroupUser, User
7 7
8 # 그룹 생성 8 # 그룹 생성
9 def create(request): 9 def create(request):
10 - # TODO: Auth 10 + # Check Login
11 - request.user_id = 1 11 + if request.user_id is None:
12 + return {'result': False, 'error': '로그인을 해주세요.'}
12 13
13 # Load 14 # Load
14 try: 15 try:
15 received = json.loads(request.body.decode('utf-8')) 16 received = json.loads(request.body.decode('utf-8'))
16 except json.decoder.JSONDecodeError: 17 except json.decoder.JSONDecodeError:
17 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 18 + return {'result': False, 'error': '잘못된 요청입니다.'}
18 19
19 # Validate 20 # Validate
20 if 'name' not in received or received['name'] == '': 21 if 'name' not in received or received['name'] == '':
21 - return {'result': False, 'error': '입력이 누락되었습니다.'} 22 + return {'result': False, 'error': '잘못된 요청입니다.'}
22 23
23 # Create 24 # Create
24 root_folder = uuid.uuid4() 25 root_folder = uuid.uuid4()
...@@ -44,24 +45,24 @@ def create(request): ...@@ -44,24 +45,24 @@ def create(request):
44 created_at=timezone.now() 45 created_at=timezone.now()
45 ) 46 )
46 47
47 - return {'result': True, 'group_id': group.id} 48 + return {'result': True}
48 49
49 50
50 # 그룹 초대장 조회 51 # 그룹 초대장 조회
51 def find_invite(request, invite_code): 52 def find_invite(request, invite_code):
52 - # TODO: Auth 53 + # Check Login
53 - request.user_id = 1 54 + if request.user_id is None:
55 + return {'result': False, 'error': '로그인을 해주세요.'}
54 56
55 # Query 57 # Query
56 group = Group.objects.filter(invite_code=invite_code) 58 group = Group.objects.filter(invite_code=invite_code)
57 59
58 # Check Exists 60 # Check Exists
59 if len(group) == 0: 61 if len(group) == 0:
60 - return {'result': False, 'error': '존재하지 않는 초대장입니다.'} 62 + return {'result': False, 'error': '잘못된 초대코드입니다.'}
61 63
62 - # Structure 64 + # Serialize
63 data = { 65 data = {
64 - 'id': group[0].id,
65 'name': group[0].name 66 'name': group[0].name
66 } 67 }
67 68
...@@ -77,15 +78,16 @@ def find_invite(request, invite_code): ...@@ -77,15 +78,16 @@ def find_invite(request, invite_code):
77 78
78 # 그룹 초대장 사용 79 # 그룹 초대장 사용
79 def use_invite(request, invite_code): 80 def use_invite(request, invite_code):
80 - # TODO: Auth 81 + # Check Login
81 - request.user_id = 1 82 + if request.user_id is None:
83 + return {'result': False, 'error': '로그인을 해주세요.'}
82 84
83 # Query 85 # Query
84 group = Group.objects.filter(invite_code=invite_code) 86 group = Group.objects.filter(invite_code=invite_code)
85 87
86 # Check Exists 88 # Check Exists
87 if len(group) == 0: 89 if len(group) == 0:
88 - return {'result': False, 'error': '존재하지 않는 초대장입니다.'} 90 + return {'result': False, 'error': '잘못된 초대코드입니다.'}
89 91
90 # Check Joined 92 # Check Joined
91 joined = GroupUser.objects.filter(group_id=group[0].id, user_id=request.user_id) 93 joined = GroupUser.objects.filter(group_id=group[0].id, user_id=request.user_id)
...@@ -104,18 +106,18 @@ def use_invite(request, invite_code): ...@@ -104,18 +106,18 @@ def use_invite(request, invite_code):
104 106
105 # 그룹 목록 107 # 그룹 목록
106 def list_me(request): 108 def list_me(request):
107 - # TODO: Auth 109 + # Check Login
108 - request.user_id = 1 110 + if request.user_id is None:
111 + return {'result': False, 'error': '로그인을 해주세요.'}
109 112
110 # Query 113 # Query
111 joined = GroupUser.objects.filter(user_id=request.user_id).values_list('group_id', flat=True) 114 joined = GroupUser.objects.filter(user_id=request.user_id).values_list('group_id', flat=True)
112 groups = Group.objects.filter(id__in=joined) 115 groups = Group.objects.filter(id__in=joined)
113 116
114 - # Structure 117 + # Serialize
115 data = [] 118 data = []
116 for group in groups: 119 for group in groups:
117 data.append({ 120 data.append({
118 - 'id': group.id,
119 'name': group.name, 121 'name': group.name,
120 'root_folder': group.root_folder, 122 'root_folder': group.root_folder,
121 }) 123 })
...@@ -125,24 +127,24 @@ def list_me(request): ...@@ -125,24 +127,24 @@ def list_me(request):
125 127
126 # 그룹 조회 128 # 그룹 조회
127 def find_item(request, group_id): 129 def find_item(request, group_id):
128 - # TODO: Auth 130 + # Check Login
129 - request.user_id = 1 131 + if request.user_id is None:
132 + return {'result': False, 'error': '로그인을 해주세요.'}
130 133
131 # Check Joined 134 # Check Joined
132 joined = GroupUser.objects.filter(group_id=group_id, user_id=request.user_id) 135 joined = GroupUser.objects.filter(group_id=group_id, user_id=request.user_id)
133 if len(joined) == 0: 136 if len(joined) == 0:
134 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 137 + return {'result': False, 'error': '잘못된 요청입니다.'}
135 138
136 # Query 139 # Query
137 group = Group.objects.filter(id=group_id) 140 group = Group.objects.filter(id=group_id)
138 141
139 # Check Exists 142 # Check Exists
140 if len(group) == 0: 143 if len(group) == 0:
141 - return {'result': False, 'error': '존재하지 않는 그룹입니다.'} 144 + return {'result': False, 'error': '잘못된 요청입니다.'}
142 145
143 - # Structure 146 + # Serialize
144 data = { 147 data = {
145 - 'id': group[0].id,
146 'name': group[0].name, 148 'name': group[0].name,
147 'root_folder': group[0].root_folder, 149 'root_folder': group[0].root_folder,
148 } 150 }
...@@ -157,9 +159,9 @@ def find_item(request, group_id): ...@@ -157,9 +159,9 @@ def find_item(request, group_id):
157 'id': user.id, 159 'id': user.id,
158 'name': user.name, 160 'name': user.name,
159 }) 161 })
160 - data['user'] = user_data 162 + data['id'] = group[0].id
163 + data['users'] = user_data
161 data['invite_code'] = group[0].invite_code 164 data['invite_code'] = group[0].invite_code
162 - data['created_at'] = group[0].created_at
163 data['is_owner'] = True 165 data['is_owner'] = True
164 166
165 return {'result': True, 'data': data} 167 return {'result': True, 'data': data}
...@@ -167,29 +169,30 @@ def find_item(request, group_id): ...@@ -167,29 +169,30 @@ def find_item(request, group_id):
167 169
168 # 그룹 수정 170 # 그룹 수정
169 def update_item(request, group_id): 171 def update_item(request, group_id):
170 - # TODO: Auth 172 + # Check Login
171 - request.user_id = 1 173 + if request.user_id is None:
174 + return {'result': False, 'error': '로그인을 해주세요.'}
172 175
173 # Load 176 # Load
174 try: 177 try:
175 received = json.loads(request.body.decode('utf-8')) 178 received = json.loads(request.body.decode('utf-8'))
176 except json.decoder.JSONDecodeError: 179 except json.decoder.JSONDecodeError:
177 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 180 + return {'result': False, 'error': '잘못된 요청입니다.'}
178 181
179 # Validate 182 # Validate
180 if 'name' not in received or received['name'] == '': 183 if 'name' not in received or received['name'] == '':
181 - return {'result': False, 'error': '입력이 누락되었습니다.'} 184 + return {'result': False, 'error': '잘못된 요청입니다.'}
182 185
183 # Query 186 # Query
184 group = Group.objects.filter(id=group_id) 187 group = Group.objects.filter(id=group_id)
185 188
186 # Check Exists 189 # Check Exists
187 if len(group) == 0: 190 if len(group) == 0:
188 - return {'result': False, 'error': '존재하지 않는 그룹입니다.'} 191 + return {'result': False, 'error': '잘못된 요청입니다.'}
189 192
190 # Check Owner 193 # Check Owner
191 if group[0].owner_id != request.user_id: 194 if group[0].owner_id != request.user_id:
192 - return {'result': False, 'error': '권한이 없습니다.'} 195 + return {'result': False, 'error': '잘못된 요청입니다.'}
193 196
194 # Update 197 # Update
195 group[0].name = received['name'] 198 group[0].name = received['name']
...@@ -200,19 +203,20 @@ def update_item(request, group_id): ...@@ -200,19 +203,20 @@ def update_item(request, group_id):
200 203
201 # 그룹 삭제 204 # 그룹 삭제
202 def delete_item(request, group_id): 205 def delete_item(request, group_id):
203 - # TODO: Auth 206 + # Check Login
204 - request.user_id = 1 207 + if request.user_id is None:
208 + return {'result': False, 'error': '로그인을 해주세요.'}
205 209
206 # Query 210 # Query
207 group = Group.objects.filter(id=group_id) 211 group = Group.objects.filter(id=group_id)
208 212
209 # Check Exists 213 # Check Exists
210 if len(group) == 0: 214 if len(group) == 0:
211 - return {'result': False, 'error': '존재하지 않는 그룹입니다.'} 215 + return {'result': False, 'error': '잘못된 요청입니다.'}
212 216
213 # Check Owner 217 # Check Owner
214 if group[0].owner_id != request.user_id: 218 if group[0].owner_id != request.user_id:
215 - return {'result': False, 'error': '권한이 없습니다.'} 219 + return {'result': False, 'error': '잘못된 요청입니다.'}
216 220
217 # S3 Delete 221 # S3 Delete
218 del_list = File.objects.filter(owner_group_id=group_id).values_list('id', flat=True) 222 del_list = File.objects.filter(owner_group_id=group_id).values_list('id', flat=True)
...@@ -228,15 +232,16 @@ def delete_item(request, group_id): ...@@ -228,15 +232,16 @@ def delete_item(request, group_id):
228 232
229 # 그룹 사용자 삭제 233 # 그룹 사용자 삭제
230 def remove_user(request, group_id, user_id): 234 def remove_user(request, group_id, user_id):
231 - # TODO: Auth 235 + # Check Login
232 - request.user_id = 1 236 + if request.user_id is None:
237 + return {'result': False, 'error': '로그인을 해주세요.'}
233 238
234 # Query 239 # Query
235 group = Group.objects.filter(id=group_id) 240 group = Group.objects.filter(id=group_id)
236 241
237 # Check Owner 242 # Check Owner
238 if group[0].owner_id != request.user_id: 243 if group[0].owner_id != request.user_id:
239 - return {'result': False, 'error': '권한이 없습니다.'} 244 + return {'result': False, 'error': '잘못된 요청입니다.'}
240 245
241 # Check Me 246 # Check Me
242 if int(user_id) == request.user_id: 247 if int(user_id) == request.user_id:
......
...@@ -16,32 +16,34 @@ def create(request): ...@@ -16,32 +16,34 @@ def create(request):
16 try: 16 try:
17 received = json.loads(request.body.decode('utf-8')) 17 received = json.loads(request.body.decode('utf-8'))
18 except json.decoder.JSONDecodeError: 18 except json.decoder.JSONDecodeError:
19 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 19 + return {'result': False, 'error': '잘못된 요청입니다.'}
20 20
21 # Validate 21 # Validate
22 if 'email' not in received \ 22 if 'email' not in received \
23 or 'password' not in received \ 23 or 'password' not in received \
24 or 'name' not in received: 24 or 'name' not in received:
25 - return {'result': False, 'error': '입력이 누락되었습니다.'} 25 + return {'result': False, 'error': '잘못된 요청입니다.'}
26 26
27 # Validate Email 27 # Validate Email
28 try: 28 try:
29 validate_email(received['email']) 29 validate_email(received['email'])
30 except ValidationError: 30 except ValidationError:
31 - return {'result': False, 'error': '이메일 형식이 잘못되었습니다.'} 31 + return {'result': False, 'error': '이메일을 제대로 입력해주세요.'}
32 32
33 # Validate Password 33 # Validate Password
34 if len(received['password']) < 8: 34 if len(received['password']) < 8:
35 - return {'result': False, 'error': '비밀번호는 최소 8글자 입니다.'} 35 + return {'result': False, 'error': '비밀번호를 8자리 이상으로 입력해주세요.'}
36 36
37 # Validate Name 37 # Validate Name
38 if len(received['name']) > 50: 38 if len(received['name']) > 50:
39 return {'result': False, 'error': '이름은 최대 50글자 입니다.'} 39 return {'result': False, 'error': '이름은 최대 50글자 입니다.'}
40 + elif len(received['name']) == 0:
41 + return {'result': False, 'error': '이름을 제대로 입력해주세요.'}
40 42
41 # Check Duplicates 43 # Check Duplicates
42 is_exists = User.objects.filter(email=received['email']) 44 is_exists = User.objects.filter(email=received['email'])
43 if len(is_exists) > 0: 45 if len(is_exists) > 0:
44 - return {'result': False, 'error': '이미 사용중인 이메일 주소 입니다.'} 46 + return {'result': False, 'error': '이미 사용 중인 이메일입니다.'}
45 47
46 # Insert 48 # Insert
47 root_folder = uuid.uuid4() 49 root_folder = uuid.uuid4()
...@@ -70,21 +72,21 @@ def login(request): ...@@ -70,21 +72,21 @@ def login(request):
70 try: 72 try:
71 received = json.loads(request.body.decode('utf-8')) 73 received = json.loads(request.body.decode('utf-8'))
72 except json.decoder.JSONDecodeError: 74 except json.decoder.JSONDecodeError:
73 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 75 + return {'result': False, 'error': '잘못된 요청입니다.'}
74 76
75 # Validate 77 # Validate
76 if 'email' not in received \ 78 if 'email' not in received \
77 or 'password' not in received: 79 or 'password' not in received:
78 - return {'result': False, 'error': '입력이 누락되었습니다.'} 80 + return {'result': False, 'error': '잘못된 요청입니다.'}
79 81
80 - # Select 82 + # Query
81 user = User.objects.filter(email=received['email']) 83 user = User.objects.filter(email=received['email'])
82 84
83 - # Not Exists 85 + # Check Exists
84 if len(user) != 1: 86 if len(user) != 1:
85 return {'result': False, 'error': '로그인에 실패하였습니다.'} 87 return {'result': False, 'error': '로그인에 실패하였습니다.'}
86 88
87 - # Check 89 + # Check Password
88 if check_password(received['password'], user[0].password) is False: 90 if check_password(received['password'], user[0].password) is False:
89 return {'result': False, 'error': '로그인에 실패하였습니다.'} 91 return {'result': False, 'error': '로그인에 실패하였습니다.'}
90 92
...@@ -97,8 +99,9 @@ def login(request): ...@@ -97,8 +99,9 @@ def login(request):
97 99
98 # 회원정보 조회 100 # 회원정보 조회
99 def find_me(request): 101 def find_me(request):
100 - # TODO: Auth 102 + # Check Login
101 - request.user_id = 1 103 + if request.user_id is None:
104 + return {'result': False, 'error': '로그인을 해주세요.'}
102 105
103 # Query 106 # Query
104 user = User.objects.filter(id=request.user_id) 107 user = User.objects.filter(id=request.user_id)
...@@ -121,19 +124,20 @@ def find_me(request): ...@@ -121,19 +124,20 @@ def find_me(request):
121 124
122 # 회원정보 수정 125 # 회원정보 수정
123 def update_me(request): 126 def update_me(request):
124 - # TODO: Auth 127 + # Check Login
125 - request.user_id = 1 128 + if request.user_id is None:
129 + return {'result': False, 'error': '로그인을 해주세요.'}
126 130
127 # Load 131 # Load
128 try: 132 try:
129 received = json.loads(request.body.decode('utf-8')) 133 received = json.loads(request.body.decode('utf-8'))
130 except json.decoder.JSONDecodeError: 134 except json.decoder.JSONDecodeError:
131 - return {'result': False, 'error': '입력이 잘못되었습니다.'} 135 + return {'result': False, 'error': '잘못된 요청입니다.'}
132 136
133 # Validate 137 # Validate
134 if 'name' not in received \ 138 if 'name' not in received \
135 and ('old_password' not in received and 'password' not in received): 139 and ('old_password' not in received and 'password' not in received):
136 - return {'result': False, 'error': '입력이 누락되었습니다.'} 140 + return {'result': False, 'error': '잘못된 요청입니다.'}
137 141
138 # Query 142 # Query
139 user = User.objects.filter(id=request.user_id) 143 user = User.objects.filter(id=request.user_id)
...@@ -144,14 +148,16 @@ def update_me(request): ...@@ -144,14 +148,16 @@ def update_me(request):
144 148
145 # Change Name 149 # Change Name
146 if 'name' in received: 150 if 'name' in received:
151 + if len(received['name']) == 0:
152 + return {'result': False, 'error': '이름을 제대로 입력해주세요.'}
147 user[0].name = received['name'] 153 user[0].name = received['name']
148 154
149 # Change Password 155 # Change Password
150 if 'old_password' in received and 'password' in received: 156 if 'old_password' in received and 'password' in received:
151 if check_password(received['old_password'], user[0].password) is False: 157 if check_password(received['old_password'], user[0].password) is False:
152 - return {'result': False, 'error': '이전 비밀번호가 잘못되었습니다.'} 158 + return {'result': False, 'error': '이전 비밀번호를 제대로 입력해주세요.'}
153 if len(received['password']) < 8: 159 if len(received['password']) < 8:
154 - return {'result': False, 'error': '비밀번호는 최소 8글자 입니다.'} 160 + return {'result': False, 'error': '비밀번호를 8자리 이상으로 입력해주세요.'}
155 user[0].password = make_password(received['password']) 161 user[0].password = make_password(received['password'])
156 162
157 # Save 163 # Save
......
...@@ -17,6 +17,7 @@ idna==2.9 ...@@ -17,6 +17,7 @@ idna==2.9
17 importlib-metadata==1.6.0 17 importlib-metadata==1.6.0
18 jmespath==0.10.0 18 jmespath==0.10.0
19 -e git+http://khuhub.khu.ac.kr/2016104129/kappa.git@1b0e17bb6da7460d9d494828c682a5ef66736aa3#egg=kappa 19 -e git+http://khuhub.khu.ac.kr/2016104129/kappa.git@1b0e17bb6da7460d9d494828c682a5ef66736aa3#egg=kappa
20 +pathvalidate==2.3.0
20 pip-tools==5.1.2 21 pip-tools==5.1.2
21 placebo==0.9.0 22 placebo==0.9.0
22 pycparser==2.20 23 pycparser==2.20
......
...@@ -10,6 +10,17 @@ ...@@ -10,6 +10,17 @@
10 "vpc_config": { 10 "vpc_config": {
11 "SubnetIds": ["subnet-02d51e69"], 11 "SubnetIds": ["subnet-02d51e69"],
12 "SecurityGroupIds": ["sg-09c30d37d6a504f5c"] 12 "SecurityGroupIds": ["sg-09c30d37d6a504f5c"]
13 - } 13 + },
14 + "events": [
15 + {
16 + "function": "khubox.lambda.process_upload",
17 + "event_source": {
18 + "arn": "arn:aws:s3:::khubox-files",
19 + "events": [
20 + "s3:ObjectCreated:Put"
21 + ]
22 + }
23 + }
24 + ]
14 } 25 }
15 } 26 }
......