Showing
7 changed files
with
267 additions
and
22 deletions
... | @@ -125,6 +125,7 @@ STATIC_URL = '/static/' | ... | @@ -125,6 +125,7 @@ STATIC_URL = '/static/' |
125 | 125 | ||
126 | 126 | ||
127 | # Custom Settings | 127 | # Custom Settings |
128 | +S3_BUCKET = 'khubox-files' | ||
128 | CDN_PATH = 'https://khubox-files.khunet.net' | 129 | CDN_PATH = 'https://khubox-files.khunet.net' |
129 | CLOUDFRONT_KEY_ID = 'APKAJ3FOBWI34OZJTXJQ' | 130 | CLOUDFRONT_KEY_ID = 'APKAJ3FOBWI34OZJTXJQ' |
130 | 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-----' | 131 | 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-----' | ... | ... |
1 | +import boto3 | ||
1 | import datetime | 2 | import datetime |
2 | from botocore.signers import CloudFrontSigner | 3 | from botocore.signers import CloudFrontSigner |
3 | from cryptography.hazmat.backends import default_backend | 4 | from cryptography.hazmat.backends import default_backend |
... | @@ -15,8 +16,39 @@ def rsa_signer(message): | ... | @@ -15,8 +16,39 @@ def rsa_signer(message): |
15 | return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1()) | 16 | return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1()) |
16 | 17 | ||
17 | 18 | ||
18 | -def sign(url): | 19 | +def sign_download(url): |
19 | - expire_date = datetime.datetime(2020, 6, 10) | 20 | + expire_date = datetime.datetime.utcnow() + datetime.timedelta(hours=1) |
20 | cloudfront_signer = CloudFrontSigner(settings.CLOUDFRONT_KEY_ID, rsa_signer) | 21 | cloudfront_signer = CloudFrontSigner(settings.CLOUDFRONT_KEY_ID, rsa_signer) |
21 | signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date) | 22 | signed_url = cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date) |
22 | return signed_url | 23 | return signed_url |
24 | + | ||
25 | + | ||
26 | +def sign_upload(file_id): | ||
27 | + s3 = boto3.client('s3') | ||
28 | + signed_url = s3.generate_presigned_url( | ||
29 | + 'put_object', | ||
30 | + Params={'Bucket': settings.S3_BUCKET, 'Key': file_id}, | ||
31 | + ExpiresIn=3600, | ||
32 | + HttpMethod='PUT' | ||
33 | + ) | ||
34 | + return signed_url | ||
35 | + | ||
36 | + | ||
37 | +def s3_delete(del_list): | ||
38 | + s3 = boto3.resource('s3') | ||
39 | + bucket = s3.Bucket(settings.S3_BUCKET) | ||
40 | + del_s3_list = [] | ||
41 | + for key in del_list: | ||
42 | + del_s3_list.append({'Key': key}) | ||
43 | + bucket.delete_objects(Delete={'Objects': del_s3_list}) | ||
44 | + | ||
45 | + | ||
46 | +def s3_copy(file_id, new_file_id): | ||
47 | + s3 = boto3.resource('s3') | ||
48 | + bucket = s3.Bucket(settings.S3_BUCKET) | ||
49 | + copy_source = { | ||
50 | + 'Bucket': settings.S3_BUCKET, | ||
51 | + 'Key': file_id | ||
52 | + } | ||
53 | + obj = bucket.Object(str(new_file_id)) | ||
54 | + obj.copy(copy_source) | ... | ... |
... | @@ -5,7 +5,7 @@ from . import files, groups, users | ... | @@ -5,7 +5,7 @@ from . import files, groups, users |
5 | urlpatterns = [ | 5 | urlpatterns = [ |
6 | url(r'^files$', files.index), # 폴더 생성, 파일 업로드, 폴더/파일 목록 | 6 | url(r'^files$', files.index), # 폴더 생성, 파일 업로드, 폴더/파일 목록 |
7 | url(r'^files/trash$', files.trash), # 휴지통 비우기 | 7 | url(r'^files/trash$', files.trash), # 휴지통 비우기 |
8 | - url(r'^files/(?P<file_id>[-\w]+)$', files.item), # 폴더/파일 조회, 파일 다운로드, 폴더/파일 수정 | 8 | + url(r'^files/(?P<file_id>[-\w]+)$', files.item), # 폴더/파일 조회, 폴더/파일 수정 |
9 | url(r'^files/(?P<file_id>[-\w]+)/copy$', files.copy), # 파일 복제 | 9 | url(r'^files/(?P<file_id>[-\w]+)/copy$', files.copy), # 파일 복제 |
10 | url(r'^groups$', groups.index), # 그룹 생성 | 10 | url(r'^groups$', groups.index), # 그룹 생성 |
11 | url(r'^groups/invite/(?P<invite_code>[-\w]+)$', groups.invite), # 그룹 초대장 조회, 그룹 초대장 사용 | 11 | url(r'^groups/invite/(?P<invite_code>[-\w]+)$', groups.invite), # 그룹 초대장 조회, 그룹 초대장 사용 | ... | ... |
... | @@ -20,7 +20,7 @@ def trash(request): | ... | @@ -20,7 +20,7 @@ def trash(request): |
20 | 20 | ||
21 | 21 | ||
22 | def item(request, file_id): | 22 | def item(request, file_id): |
23 | - # 폴더/파일 조회, 파일 다운로드 | 23 | + # 폴더/파일 조회 |
24 | if request.method == 'GET': | 24 | if request.method == 'GET': |
25 | return JsonResponse(files.find_item(request, file_id)) | 25 | return JsonResponse(files.find_item(request, file_id)) |
26 | # 폴더/파일 수정 | 26 | # 폴더/파일 수정 | ... | ... |
... | @@ -26,7 +26,7 @@ class Migration(migrations.Migration): | ... | @@ -26,7 +26,7 @@ class Migration(migrations.Migration): |
26 | ('size', models.BigIntegerField()), | 26 | ('size', models.BigIntegerField()), |
27 | ('is_public', models.IntegerField(default=0)), | 27 | ('is_public', models.IntegerField(default=0)), |
28 | ('is_starred', models.IntegerField(default=0)), | 28 | ('is_starred', models.IntegerField(default=0)), |
29 | - ('is_trahsed', models.IntegerField(default=0)), | 29 | + ('is_trashed', models.IntegerField(default=0)), |
30 | ('created_at', models.DateTimeField()), | 30 | ('created_at', models.DateTimeField()), |
31 | ('deleted_at', models.DateTimeField(blank=True, null=True)), | 31 | ('deleted_at', models.DateTimeField(blank=True, null=True)), |
32 | ], | 32 | ], | ... | ... |
... | @@ -12,7 +12,7 @@ class File(models.Model): | ... | @@ -12,7 +12,7 @@ class File(models.Model): |
12 | size = models.BigIntegerField() | 12 | size = models.BigIntegerField() |
13 | is_public = models.IntegerField(default=0) | 13 | is_public = models.IntegerField(default=0) |
14 | is_starred = models.IntegerField(default=0) | 14 | is_starred = models.IntegerField(default=0) |
15 | - is_trahsed = models.IntegerField(default=0) | 15 | + is_trashed = models.IntegerField(default=0) |
16 | created_at = models.DateTimeField() | 16 | created_at = models.DateTimeField() |
17 | deleted_at = models.DateTimeField(blank=True, null=True) | 17 | deleted_at = models.DateTimeField(blank=True, null=True) |
18 | 18 | ... | ... |
1 | import json | 1 | import json |
2 | import uuid | 2 | import uuid |
3 | +from django.conf import settings | ||
3 | from django.utils import timezone | 4 | from django.utils import timezone |
4 | -from ..aws import sign | 5 | +from ..aws import sign_upload, sign_download, s3_copy, s3_delete |
5 | from ..models import File, GroupUser | 6 | from ..models import File, GroupUser |
6 | 7 | ||
7 | 8 | ||
8 | -# TODO: 폴더/파일 목록 | 9 | +# 폴더/파일 목록 |
9 | def list_item(request): | 10 | def list_item(request): |
10 | - return {'result': True} | 11 | + # TODO: Auth |
12 | + request.user_id = 1 | ||
13 | + | ||
14 | + # Validate | ||
15 | + if request.GET.get('is_public') != 'true' \ | ||
16 | + and request.GET.get('is_starred') != 'true' \ | ||
17 | + and request.GET.get('is_trashed') != 'true': | ||
18 | + return {'result': False, 'error': '입력이 누락되었습니다.'} | ||
19 | + | ||
20 | + # Query Files | ||
21 | + files = None | ||
22 | + if request.GET.get('is_public') == 'true': | ||
23 | + files = File.objects.filter(owner_user_id=request.user_id, is_public=1, deleted_at__isnull=True) | ||
24 | + elif request.GET.get('is_starred') == 'true': | ||
25 | + files = File.objects.filter(owner_user_id=request.user_id, is_starred=1, deleted_at__isnull=True) | ||
26 | + 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 | + | ||
29 | + # Structure | ||
30 | + data = [] | ||
31 | + for file in files: | ||
32 | + data.append({ | ||
33 | + 'id': file.id, | ||
34 | + 'type': file.type, | ||
35 | + 'name': file.name, | ||
36 | + 'size': file.size, | ||
37 | + 'is_public': file.is_public, | ||
38 | + 'is_starred': file.is_starred, | ||
39 | + 'is_trashed': file.is_trashed, | ||
40 | + 'created_at': file.created_at, | ||
41 | + }) | ||
42 | + | ||
43 | + return {'result': True, 'data': data} | ||
11 | 44 | ||
12 | 45 | ||
13 | # 폴더 생성, 파일 업로드 | 46 | # 폴더 생성, 파일 업로드 |
... | @@ -16,7 +49,10 @@ def create(request): | ... | @@ -16,7 +49,10 @@ def create(request): |
16 | request.user_id = 1 | 49 | request.user_id = 1 |
17 | 50 | ||
18 | # Load | 51 | # Load |
19 | - received = json.loads(request.body.decode('utf-8')) | 52 | + try: |
53 | + received = json.loads(request.body.decode('utf-8')) | ||
54 | + except json.decoder.JSONDecodeError: | ||
55 | + return {'result': False, 'error': '입력이 잘못되었습니다.'} | ||
20 | 56 | ||
21 | # Validate | 57 | # Validate |
22 | if 'parent_id' not in received \ | 58 | if 'parent_id' not in received \ |
... | @@ -28,7 +64,7 @@ def create(request): | ... | @@ -28,7 +64,7 @@ def create(request): |
28 | return {'result': False, 'error': '입력이 잘못되었습니다.'} | 64 | return {'result': False, 'error': '입력이 잘못되었습니다.'} |
29 | 65 | ||
30 | # Get Parent | 66 | # Get Parent |
31 | - parent = File.objects.filter(id=received['parent_id'], is_trahsed=0, deleted_at__isnull=True) | 67 | + parent = File.objects.filter(id=received['parent_id'], is_trashed=0, deleted_at__isnull=True) |
32 | 68 | ||
33 | # Check Exists | 69 | # Check Exists |
34 | if len(parent) == 0: | 70 | if len(parent) == 0: |
... | @@ -63,18 +99,17 @@ def create(request): | ... | @@ -63,18 +99,17 @@ def create(request): |
63 | return {'result': True, 'file_id': file_id} | 99 | return {'result': True, 'file_id': file_id} |
64 | 100 | ||
65 | # Return File | 101 | # Return File |
66 | - upload_url = 'https://khubox-files.khunet.net/%s' % file_id | 102 | + upload_url = sign_upload(str(file_id)) |
67 | - upload_url = sign(upload_url) | ||
68 | return {'result': True, 'file_id': file_id, 'upload_url': upload_url} | 103 | return {'result': True, 'file_id': file_id, 'upload_url': upload_url} |
69 | 104 | ||
70 | 105 | ||
71 | -# TODO: 휴지통 비우기 | 106 | +# 휴지통 비우기 |
72 | def empty_trash(request): | 107 | def empty_trash(request): |
73 | # TODO: Auth | 108 | # TODO: Auth |
74 | request.user_id = 1 | 109 | request.user_id = 1 |
75 | 110 | ||
76 | # Query Files | 111 | # Query Files |
77 | - files = File.objects.filter(owner_user_id=request.user_id, is_trahsed=1, deleted_at__isnull=True) | 112 | + files = File.objects.filter(owner_user_id=request.user_id, is_trashed=1, deleted_at__isnull=True) |
78 | 113 | ||
79 | # First Depth | 114 | # First Depth |
80 | del_list = [] | 115 | del_list = [] |
... | @@ -92,24 +127,201 @@ def empty_trash(request): | ... | @@ -92,24 +127,201 @@ def empty_trash(request): |
92 | for del_file in child_files: | 127 | for del_file in child_files: |
93 | del_check.append(del_file.id) | 128 | del_check.append(del_file.id) |
94 | 129 | ||
95 | - # TODO: S3 Delete | 130 | + # S3 Delete |
131 | + s3_delete(del_list) | ||
96 | 132 | ||
97 | # Update | 133 | # Update |
98 | - File.objects.filter(id__in=del_list).update(is_trahsed=1, deleted_at=timezone.now()) | 134 | + File.objects.filter(id__in=del_list).update(is_trashed=1, deleted_at=timezone.now()) |
99 | 135 | ||
100 | return {'result': True, 'affected': del_list} | 136 | return {'result': True, 'affected': del_list} |
101 | 137 | ||
102 | 138 | ||
103 | -# TODO: 폴더/파일 조회, 파일 다운로드 | 139 | +# 폴더/파일 조회 |
104 | def find_item(request, file_id): | 140 | def find_item(request, file_id): |
105 | - return {'result': True} | 141 | + # TODO: Auth |
142 | + request.user_id = 1 | ||
143 | + | ||
144 | + # Query | ||
145 | + file = File.objects.filter(id=file_id, deleted_at__isnull=True) | ||
146 | + | ||
147 | + # Check Exists | ||
148 | + if len(file) == 0: | ||
149 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
150 | + | ||
151 | + # Check Owner | ||
152 | + is_auth = False | ||
153 | + if file[0].owner_user_id == request.user_id: | ||
154 | + is_auth = True | ||
155 | + is_my_group = GroupUser.objects.filter(group_id=file[0].owner_group_id, user_id=request.user_id) | ||
156 | + if len(is_my_group) != 0: | ||
157 | + is_auth = True | ||
158 | + | ||
159 | + # Check Public | ||
160 | + if file[0].is_public == 1: | ||
161 | + is_auth = True | ||
162 | + parent_id = file[0].parent_id | ||
163 | + while True: | ||
164 | + if parent_id is None or is_auth: | ||
165 | + break | ||
166 | + parent_file = File.objects.filter(id=parent_id) | ||
167 | + if parent_file[0].is_public == 1: | ||
168 | + is_auth = True | ||
169 | + parent_id = parent_file[0].parent_id | ||
170 | + | ||
171 | + # Check Auth | ||
172 | + if is_auth is False: | ||
173 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
174 | + | ||
175 | + # Return File | ||
176 | + if file[0].type == 'file': | ||
177 | + download_url = '%s/%s' % (settings.CDN_PATH, file[0].id) | ||
178 | + download_url = sign_download(download_url) | ||
179 | + data = { | ||
180 | + 'id': file[0].id, | ||
181 | + 'parent_id': file[0].parent_id, | ||
182 | + 'uploader_id': file[0].uploader_id, | ||
183 | + 'name': file[0].name, | ||
184 | + 'size': file[0].size, | ||
185 | + 'is_public': file[0].is_public, | ||
186 | + 'is_starred': file[0].is_starred, | ||
187 | + 'is_trashed': file[0].is_trashed, | ||
188 | + 'created_at': file[0].created_at, | ||
189 | + 'download_url': download_url, | ||
190 | + } | ||
191 | + return {'result': True, 'data': data} | ||
192 | + | ||
193 | + # Query | ||
194 | + files = File.objects.filter(parent_id=file[0].id, is_trashed=0, deleted_at__isnull=True) | ||
195 | + | ||
196 | + # Structure | ||
197 | + data = [] | ||
198 | + for file in files: | ||
199 | + data.append({ | ||
200 | + 'id': file.id, | ||
201 | + 'type': file.type, | ||
202 | + 'name': file.name, | ||
203 | + 'size': file.size, | ||
204 | + 'is_public': file.is_public, | ||
205 | + 'is_starred': file.is_starred, | ||
206 | + 'is_trashed': file.is_trashed, | ||
207 | + 'created_at': file.created_at, | ||
208 | + }) | ||
209 | + | ||
210 | + # Return Folder | ||
211 | + return {'result': True, 'data': data} | ||
106 | 212 | ||
107 | 213 | ||
108 | -# TODO: 폴더/파일 수정 | 214 | +# 폴더/파일 수정 |
109 | def update_item(request, file_id): | 215 | def update_item(request, file_id): |
216 | + # TODO: Auth | ||
217 | + request.user_id = 1 | ||
218 | + | ||
219 | + # Load | ||
220 | + try: | ||
221 | + received = json.loads(request.body.decode('utf-8')) | ||
222 | + except json.decoder.JSONDecodeError: | ||
223 | + return {'result': False, 'error': '입력이 잘못되었습니다.'} | ||
224 | + | ||
225 | + # Validate | ||
226 | + if 'name' not in received \ | ||
227 | + and 'parent_id' not in received \ | ||
228 | + and 'is_public' not in received \ | ||
229 | + and 'is_starred' not in received \ | ||
230 | + and 'is_trashed' not in received: | ||
231 | + return {'result': False, 'error': '입력이 누락되었습니다.'} | ||
232 | + | ||
233 | + # Query | ||
234 | + file = File.objects.filter(id=file_id, deleted_at__isnull=True) | ||
235 | + | ||
236 | + # Check Exists | ||
237 | + if len(file) == 0: | ||
238 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
239 | + | ||
240 | + # Check Owner | ||
241 | + is_auth = False | ||
242 | + if file[0].owner_user_id == request.user_id: | ||
243 | + is_auth = True | ||
244 | + is_my_group = GroupUser.objects.filter(group_id=file[0].owner_group_id, user_id=request.user_id) | ||
245 | + if len(is_my_group) != 0 \ | ||
246 | + and 'is_public' not in received \ | ||
247 | + and 'is_starred' not in received \ | ||
248 | + and 'is_trashed' not in received: | ||
249 | + is_auth = True | ||
250 | + | ||
251 | + # Check Parent | ||
252 | + if 'parent_id' in received: | ||
253 | + parent = File.objects.filter(id=received['parent_id'], type='folder', deleted_at__isnull=True) | ||
254 | + if len(parent) == 0: | ||
255 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
256 | + if (is_auth is True or len(is_my_group) != 0) \ | ||
257 | + and parent[0].owner_user_id == file[0].owner_user_id \ | ||
258 | + and parent[0].owner_group_id == file[0].owner_group_id \ | ||
259 | + and file_id != received['parent_id']: | ||
260 | + is_auth = True | ||
261 | + else: | ||
262 | + is_auth = False | ||
263 | + | ||
264 | + # Check Auth | ||
265 | + if is_auth is False: | ||
266 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
267 | + | ||
268 | + # Update | ||
269 | + if 'name' in received: | ||
270 | + file[0].name = received['name'] | ||
271 | + if 'parent_id' in received: | ||
272 | + file[0].parent_id = received['parent_id'] | ||
273 | + if 'is_public' in received: | ||
274 | + file[0].is_public = 1 if received['is_public'] is True else 0 | ||
275 | + if 'is_starred' in received: | ||
276 | + file[0].is_starred = 1 if received['is_starred'] is True else 0 | ||
277 | + if 'is_trashed' in received: | ||
278 | + if file[0].parent_id is None: | ||
279 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
280 | + file[0].is_trashed = 1 if received['is_trashed'] is True else 0 | ||
281 | + file[0].save() | ||
282 | + | ||
110 | return {'result': True} | 283 | return {'result': True} |
111 | 284 | ||
112 | 285 | ||
113 | -# TODO: 파일 복제 | 286 | +# 파일 복제 |
114 | def copy(request, file_id): | 287 | def copy(request, file_id): |
115 | - return {'result': True} | 288 | + # TODO: Auth |
289 | + request.user_id = 1 | ||
290 | + | ||
291 | + # Get File | ||
292 | + file = File.objects.filter(id=file_id, type='file', is_trashed=0, deleted_at__isnull=True) | ||
293 | + | ||
294 | + # Check Exists | ||
295 | + if len(file) == 0: | ||
296 | + return {'result': False, 'error': '잘못된 요청입니다.'} | ||
297 | + | ||
298 | + # Check Owner | ||
299 | + is_auth = False | ||
300 | + if file[0].owner_user_id == request.user_id: | ||
301 | + is_auth = True | ||
302 | + is_my_group = GroupUser.objects.filter(group_id=file[0].owner_group_id, user_id=request.user_id) | ||
303 | + if len(is_my_group) != 0: | ||
304 | + is_auth = True | ||
305 | + if is_auth is False: | ||
306 | + return {'result': False, 'error': '경로가 잘못되었습니다.'} | ||
307 | + | ||
308 | + # Create UUID | ||
309 | + new_file_id = uuid.uuid4() | ||
310 | + | ||
311 | + # S3 Copy | ||
312 | + s3_copy(file_id, new_file_id) | ||
313 | + | ||
314 | + # Create | ||
315 | + File.objects.create( | ||
316 | + id=new_file_id, | ||
317 | + parent_id=file[0].parent_id, | ||
318 | + owner_user_id=file[0].owner_user_id, | ||
319 | + owner_group_id=file[0].owner_group_id, | ||
320 | + uploader_id=request.user_id, | ||
321 | + type=file[0].type, | ||
322 | + name='%s의 사본' % file[0].name, | ||
323 | + size=file[0].size, | ||
324 | + created_at=timezone.now() | ||
325 | + ) | ||
326 | + | ||
327 | + return {'result': True, 'file_id': file_id} | ... | ... |
-
Please register or login to post a comment