Toggle navigation
Toggle navigation
This project
Loading...
Sign in
2020-1-CloudComputing-E
/
E_Team_KhuBox
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Authored by
서승완
2020-06-10 03:08:29 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
19cb4847d9755236815ae181e36bdffcecf9267e
19cb4847
1 parent
06379ad3
feat: implement files api
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
267 additions
and
22 deletions
khubox-api/config/settings.py
khubox-api/khubox/aws.py
khubox-api/khubox/controllers/__init__.py
khubox-api/khubox/controllers/files.py
khubox-api/khubox/migrations/0001_initial.py
khubox-api/khubox/models.py
khubox-api/khubox/services/files.py
khubox-api/config/settings.py
View file @
19cb484
...
...
@@ -125,6 +125,7 @@ STATIC_URL = '/static/'
# Custom Settings
S3_BUCKET
=
'khubox-files'
CDN_PATH
=
'https://khubox-files.khunet.net'
CLOUDFRONT_KEY_ID
=
'APKAJ3FOBWI34OZJTXJQ'
CLOUDFRONT_KEY_PRIVATE
=
'-----BEGIN RSA PRIVATE KEY-----
\n
MIIEowIBAAKCAQEA18VtzURs+fQev5L00LRwRbJaObQI4kfJCIsOE7eWSOqq4Akh
\n
A7fI6vs3z8orXBvgc+k6GgAHrIdNwckxoQuTsCxrTDm1104qy1T4JkVxkIBYHJgH
\n
GzKUloK5IqdmcYbOK7IQeHJ2gR9Mv/3oKUytJSsrbM9k4oLrsxGpyEuJeHIg28aP
\n
whoVWmBGcPu48l4aYAZEVY7LZRJSOQ9y7Lf8FS1u7Xtw1P91gEaqrqVXqRWY02C8
\n
sixpJJuiAPnM3rpcpVNlAaPdDkWmaWYJoJDOlce7Dmx1a9Ckr24krM//vpEljurC
\n
Gml0AsHpL8LE9msM5VA+miCxCz/K+wDgm2xvvQIDAQABAoIBAFmP3pLceyuJVBYK
\n
5smWjB+x91eKTkG2sFB2f8JZau0bUxApWeXULHa1DiaW8UaLX7BdN7vBFW5cvz7X
\n
x1zklEoFNghuz/btwD+kJlikbI4hZ/F+fTyh0yFiY3xp5dDrtrpWcBW+1UeleVMc
\n
DnjOFfSepajFsUeANlue0k2MZSRz34s2T2scV5ZkooqdXddYUF/wDhefYm6uvCgI
\n
PyvY/mbJTyhte/xagY/m6yzk5gxgad0qP2ZZrHhLLMlJ/GEZToWDxD2xUei61NQT
\n
FFc5ZutkAE6fVb3I4SJUBSX5fl0tTMz4Aak1GP2phMhjZyjYnQMq8kvL4BNFb7gp
\n
ary8W/UCgYEA+eKkfjjlPsEx6yHMhD7pAwy/MpUqJmF5LMxIG+qfd+GZMQ2oucn5
\n
pUAwBHP7BD6E9H7/7jdjnCiO+iPrzM9vNLfqsdCtPWzoFYJp/6Fv002uX8seNYvJ
\n
QyQqrM85LYIghhnkcmJMA8GR/Iu5ZEeE2BkAl9T2EKclzmB62d/ki6MCgYEA3Q0V
\n
z08IEwSJW+jEsOM+XGg2YkNqCVKGQD9n4CPx0TFVJxfqFl2nVwlN2hfrlJLUQ9+l
\n
fXnS5AW3tE88t9we+ea0saJZEqqlm/rGsfTV/twS9cWSgvG5fTzhUbu9/ElMU29L
\n
mydQfWTvCup7zCuQtgwM5ZRtPwuKsI8urUg6zR8CgYAt0coZvvMCI8i0dbkbkrGF
\n
NqQkcUeOTBc9CKQ8QjRFdh9x6DBFCOz2ySNE3cNsTs5wSo1BL/Ta4HD/GvEU2ABr
\n
KUImor3xYnPX5dbr4b0wgLD1rbf3V49q+Um98C1q086E6GCEPNP1aFwNc81lvtt0
\n
CHmcXZdVDGEZS4WbR7uPgwKBgBO/moY12lPQoPDsH75p3uVkjg9DVJLWo5XT1FTr
\n
ASyeSqw+b7Rl05BsDV+BqZNRdtNFhMRsANJMTHg4aAVJDh9nZBdGmMyZIEiKI/w8
\n
Em49fRgl+YvnSpoMuViS/EswxTfjBo8q+P7q6IxCHKNF9Ry+gNx14TizsEVL1XC3
\n
tkEjAoGBAMyp7wdPobJMXcclRVq6rqHs9OMcnZAveVKyxNgDbZu4OB5X4xTxGEYT
\n
NZQ0MFf/HcwlnH7797gVQeqF9dlqUJYe+Fc8lc/Rcwta/4R5uMgri9t8RKN91YKF
\n
UUFBsDEkWlkoAmfPkcrrq9cLJlmSNt3ehQj4p5iAJwoVBXXa++PO
\n
-----END RSA PRIVATE KEY-----'
...
...
khubox-api/khubox/aws.py
View file @
19cb484
import
boto3
import
datetime
from
botocore.signers
import
CloudFrontSigner
from
cryptography.hazmat.backends
import
default_backend
...
...
@@ -15,8 +16,39 @@ def rsa_signer(message):
return
private_key
.
sign
(
message
,
padding
.
PKCS1v15
(),
hashes
.
SHA1
())
def
sign
(
url
):
expire_date
=
datetime
.
datetime
(
2020
,
6
,
10
)
def
sign
_download
(
url
):
expire_date
=
datetime
.
datetime
.
utcnow
()
+
datetime
.
timedelta
(
hours
=
1
)
cloudfront_signer
=
CloudFrontSigner
(
settings
.
CLOUDFRONT_KEY_ID
,
rsa_signer
)
signed_url
=
cloudfront_signer
.
generate_presigned_url
(
url
,
date_less_than
=
expire_date
)
return
signed_url
def
sign_upload
(
file_id
):
s3
=
boto3
.
client
(
's3'
)
signed_url
=
s3
.
generate_presigned_url
(
'put_object'
,
Params
=
{
'Bucket'
:
settings
.
S3_BUCKET
,
'Key'
:
file_id
},
ExpiresIn
=
3600
,
HttpMethod
=
'PUT'
)
return
signed_url
def
s3_delete
(
del_list
):
s3
=
boto3
.
resource
(
's3'
)
bucket
=
s3
.
Bucket
(
settings
.
S3_BUCKET
)
del_s3_list
=
[]
for
key
in
del_list
:
del_s3_list
.
append
({
'Key'
:
key
})
bucket
.
delete_objects
(
Delete
=
{
'Objects'
:
del_s3_list
})
def
s3_copy
(
file_id
,
new_file_id
):
s3
=
boto3
.
resource
(
's3'
)
bucket
=
s3
.
Bucket
(
settings
.
S3_BUCKET
)
copy_source
=
{
'Bucket'
:
settings
.
S3_BUCKET
,
'Key'
:
file_id
}
obj
=
bucket
.
Object
(
str
(
new_file_id
))
obj
.
copy
(
copy_source
)
...
...
khubox-api/khubox/controllers/__init__.py
View file @
19cb484
...
...
@@ -5,7 +5,7 @@ from . import files, groups, users
urlpatterns
=
[
url
(
r'^files$'
,
files
.
index
),
# 폴더 생성, 파일 업로드, 폴더/파일 목록
url
(
r'^files/trash$'
,
files
.
trash
),
# 휴지통 비우기
url
(
r'^files/(?P<file_id>[-\w]+)$'
,
files
.
item
),
# 폴더/파일 조회,
파일 다운로드,
폴더/파일 수정
url
(
r'^files/(?P<file_id>[-\w]+)$'
,
files
.
item
),
# 폴더/파일 조회, 폴더/파일 수정
url
(
r'^files/(?P<file_id>[-\w]+)/copy$'
,
files
.
copy
),
# 파일 복제
url
(
r'^groups$'
,
groups
.
index
),
# 그룹 생성
url
(
r'^groups/invite/(?P<invite_code>[-\w]+)$'
,
groups
.
invite
),
# 그룹 초대장 조회, 그룹 초대장 사용
...
...
khubox-api/khubox/controllers/files.py
View file @
19cb484
...
...
@@ -20,7 +20,7 @@ def trash(request):
def
item
(
request
,
file_id
):
# 폴더/파일 조회
, 파일 다운로드
# 폴더/파일 조회
if
request
.
method
==
'GET'
:
return
JsonResponse
(
files
.
find_item
(
request
,
file_id
))
# 폴더/파일 수정
...
...
khubox-api/khubox/migrations/0001_initial.py
View file @
19cb484
...
...
@@ -26,7 +26,7 @@ class Migration(migrations.Migration):
(
'size'
,
models
.
BigIntegerField
()),
(
'is_public'
,
models
.
IntegerField
(
default
=
0
)),
(
'is_starred'
,
models
.
IntegerField
(
default
=
0
)),
(
'is_tra
hs
ed'
,
models
.
IntegerField
(
default
=
0
)),
(
'is_tra
sh
ed'
,
models
.
IntegerField
(
default
=
0
)),
(
'created_at'
,
models
.
DateTimeField
()),
(
'deleted_at'
,
models
.
DateTimeField
(
blank
=
True
,
null
=
True
)),
],
...
...
khubox-api/khubox/models.py
View file @
19cb484
...
...
@@ -12,7 +12,7 @@ class File(models.Model):
size
=
models
.
BigIntegerField
()
is_public
=
models
.
IntegerField
(
default
=
0
)
is_starred
=
models
.
IntegerField
(
default
=
0
)
is_tra
hs
ed
=
models
.
IntegerField
(
default
=
0
)
is_tra
sh
ed
=
models
.
IntegerField
(
default
=
0
)
created_at
=
models
.
DateTimeField
()
deleted_at
=
models
.
DateTimeField
(
blank
=
True
,
null
=
True
)
...
...
khubox-api/khubox/services/files.py
View file @
19cb484
import
json
import
uuid
from
django.conf
import
settings
from
django.utils
import
timezone
from
..aws
import
sign
from
..aws
import
sign
_upload
,
sign_download
,
s3_copy
,
s3_delete
from
..models
import
File
,
GroupUser
#
TODO:
폴더/파일 목록
# 폴더/파일 목록
def
list_item
(
request
):
return
{
'result'
:
True
}
# TODO: Auth
request
.
user_id
=
1
# Validate
if
request
.
GET
.
get
(
'is_public'
)
!=
'true'
\
and
request
.
GET
.
get
(
'is_starred'
)
!=
'true'
\
and
request
.
GET
.
get
(
'is_trashed'
)
!=
'true'
:
return
{
'result'
:
False
,
'error'
:
'입력이 누락되었습니다.'
}
# Query Files
files
=
None
if
request
.
GET
.
get
(
'is_public'
)
==
'true'
:
files
=
File
.
objects
.
filter
(
owner_user_id
=
request
.
user_id
,
is_public
=
1
,
deleted_at__isnull
=
True
)
elif
request
.
GET
.
get
(
'is_starred'
)
==
'true'
:
files
=
File
.
objects
.
filter
(
owner_user_id
=
request
.
user_id
,
is_starred
=
1
,
deleted_at__isnull
=
True
)
elif
request
.
GET
.
get
(
'is_trashed'
)
==
'true'
:
files
=
File
.
objects
.
filter
(
owner_user_id
=
request
.
user_id
,
is_trashed
=
1
,
deleted_at__isnull
=
True
)
# Structure
data
=
[]
for
file
in
files
:
data
.
append
({
'id'
:
file
.
id
,
'type'
:
file
.
type
,
'name'
:
file
.
name
,
'size'
:
file
.
size
,
'is_public'
:
file
.
is_public
,
'is_starred'
:
file
.
is_starred
,
'is_trashed'
:
file
.
is_trashed
,
'created_at'
:
file
.
created_at
,
})
return
{
'result'
:
True
,
'data'
:
data
}
# 폴더 생성, 파일 업로드
...
...
@@ -16,7 +49,10 @@ def create(request):
request
.
user_id
=
1
# Load
received
=
json
.
loads
(
request
.
body
.
decode
(
'utf-8'
))
try
:
received
=
json
.
loads
(
request
.
body
.
decode
(
'utf-8'
))
except
json
.
decoder
.
JSONDecodeError
:
return
{
'result'
:
False
,
'error'
:
'입력이 잘못되었습니다.'
}
# Validate
if
'parent_id'
not
in
received
\
...
...
@@ -28,7 +64,7 @@ def create(request):
return
{
'result'
:
False
,
'error'
:
'입력이 잘못되었습니다.'
}
# Get Parent
parent
=
File
.
objects
.
filter
(
id
=
received
[
'parent_id'
],
is_tra
hs
ed
=
0
,
deleted_at__isnull
=
True
)
parent
=
File
.
objects
.
filter
(
id
=
received
[
'parent_id'
],
is_tra
sh
ed
=
0
,
deleted_at__isnull
=
True
)
# Check Exists
if
len
(
parent
)
==
0
:
...
...
@@ -63,18 +99,17 @@ def create(request):
return
{
'result'
:
True
,
'file_id'
:
file_id
}
# Return File
upload_url
=
'https://khubox-files.khunet.net/
%
s'
%
file_id
upload_url
=
sign
(
upload_url
)
upload_url
=
sign_upload
(
str
(
file_id
))
return
{
'result'
:
True
,
'file_id'
:
file_id
,
'upload_url'
:
upload_url
}
#
TODO:
휴지통 비우기
# 휴지통 비우기
def
empty_trash
(
request
):
# TODO: Auth
request
.
user_id
=
1
# Query Files
files
=
File
.
objects
.
filter
(
owner_user_id
=
request
.
user_id
,
is_tra
hs
ed
=
1
,
deleted_at__isnull
=
True
)
files
=
File
.
objects
.
filter
(
owner_user_id
=
request
.
user_id
,
is_tra
sh
ed
=
1
,
deleted_at__isnull
=
True
)
# First Depth
del_list
=
[]
...
...
@@ -92,24 +127,201 @@ def empty_trash(request):
for
del_file
in
child_files
:
del_check
.
append
(
del_file
.
id
)
# TODO: S3 Delete
# S3 Delete
s3_delete
(
del_list
)
# Update
File
.
objects
.
filter
(
id__in
=
del_list
)
.
update
(
is_tra
hs
ed
=
1
,
deleted_at
=
timezone
.
now
())
File
.
objects
.
filter
(
id__in
=
del_list
)
.
update
(
is_tra
sh
ed
=
1
,
deleted_at
=
timezone
.
now
())
return
{
'result'
:
True
,
'affected'
:
del_list
}
#
TODO: 폴더/파일 조회, 파일 다운로드
#
폴더/파일 조회
def
find_item
(
request
,
file_id
):
return
{
'result'
:
True
}
# TODO: Auth
request
.
user_id
=
1
# Query
file
=
File
.
objects
.
filter
(
id
=
file_id
,
deleted_at__isnull
=
True
)
# Check Exists
if
len
(
file
)
==
0
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
# Check Owner
is_auth
=
False
if
file
[
0
]
.
owner_user_id
==
request
.
user_id
:
is_auth
=
True
is_my_group
=
GroupUser
.
objects
.
filter
(
group_id
=
file
[
0
]
.
owner_group_id
,
user_id
=
request
.
user_id
)
if
len
(
is_my_group
)
!=
0
:
is_auth
=
True
# Check Public
if
file
[
0
]
.
is_public
==
1
:
is_auth
=
True
parent_id
=
file
[
0
]
.
parent_id
while
True
:
if
parent_id
is
None
or
is_auth
:
break
parent_file
=
File
.
objects
.
filter
(
id
=
parent_id
)
if
parent_file
[
0
]
.
is_public
==
1
:
is_auth
=
True
parent_id
=
parent_file
[
0
]
.
parent_id
# Check Auth
if
is_auth
is
False
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
# Return File
if
file
[
0
]
.
type
==
'file'
:
download_url
=
'
%
s/
%
s'
%
(
settings
.
CDN_PATH
,
file
[
0
]
.
id
)
download_url
=
sign_download
(
download_url
)
data
=
{
'id'
:
file
[
0
]
.
id
,
'parent_id'
:
file
[
0
]
.
parent_id
,
'uploader_id'
:
file
[
0
]
.
uploader_id
,
'name'
:
file
[
0
]
.
name
,
'size'
:
file
[
0
]
.
size
,
'is_public'
:
file
[
0
]
.
is_public
,
'is_starred'
:
file
[
0
]
.
is_starred
,
'is_trashed'
:
file
[
0
]
.
is_trashed
,
'created_at'
:
file
[
0
]
.
created_at
,
'download_url'
:
download_url
,
}
return
{
'result'
:
True
,
'data'
:
data
}
# Query
files
=
File
.
objects
.
filter
(
parent_id
=
file
[
0
]
.
id
,
is_trashed
=
0
,
deleted_at__isnull
=
True
)
# Structure
data
=
[]
for
file
in
files
:
data
.
append
({
'id'
:
file
.
id
,
'type'
:
file
.
type
,
'name'
:
file
.
name
,
'size'
:
file
.
size
,
'is_public'
:
file
.
is_public
,
'is_starred'
:
file
.
is_starred
,
'is_trashed'
:
file
.
is_trashed
,
'created_at'
:
file
.
created_at
,
})
# Return Folder
return
{
'result'
:
True
,
'data'
:
data
}
#
TODO:
폴더/파일 수정
# 폴더/파일 수정
def
update_item
(
request
,
file_id
):
# TODO: Auth
request
.
user_id
=
1
# Load
try
:
received
=
json
.
loads
(
request
.
body
.
decode
(
'utf-8'
))
except
json
.
decoder
.
JSONDecodeError
:
return
{
'result'
:
False
,
'error'
:
'입력이 잘못되었습니다.'
}
# Validate
if
'name'
not
in
received
\
and
'parent_id'
not
in
received
\
and
'is_public'
not
in
received
\
and
'is_starred'
not
in
received
\
and
'is_trashed'
not
in
received
:
return
{
'result'
:
False
,
'error'
:
'입력이 누락되었습니다.'
}
# Query
file
=
File
.
objects
.
filter
(
id
=
file_id
,
deleted_at__isnull
=
True
)
# Check Exists
if
len
(
file
)
==
0
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
# Check Owner
is_auth
=
False
if
file
[
0
]
.
owner_user_id
==
request
.
user_id
:
is_auth
=
True
is_my_group
=
GroupUser
.
objects
.
filter
(
group_id
=
file
[
0
]
.
owner_group_id
,
user_id
=
request
.
user_id
)
if
len
(
is_my_group
)
!=
0
\
and
'is_public'
not
in
received
\
and
'is_starred'
not
in
received
\
and
'is_trashed'
not
in
received
:
is_auth
=
True
# Check Parent
if
'parent_id'
in
received
:
parent
=
File
.
objects
.
filter
(
id
=
received
[
'parent_id'
],
type
=
'folder'
,
deleted_at__isnull
=
True
)
if
len
(
parent
)
==
0
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
if
(
is_auth
is
True
or
len
(
is_my_group
)
!=
0
)
\
and
parent
[
0
]
.
owner_user_id
==
file
[
0
]
.
owner_user_id
\
and
parent
[
0
]
.
owner_group_id
==
file
[
0
]
.
owner_group_id
\
and
file_id
!=
received
[
'parent_id'
]:
is_auth
=
True
else
:
is_auth
=
False
# Check Auth
if
is_auth
is
False
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
# Update
if
'name'
in
received
:
file
[
0
]
.
name
=
received
[
'name'
]
if
'parent_id'
in
received
:
file
[
0
]
.
parent_id
=
received
[
'parent_id'
]
if
'is_public'
in
received
:
file
[
0
]
.
is_public
=
1
if
received
[
'is_public'
]
is
True
else
0
if
'is_starred'
in
received
:
file
[
0
]
.
is_starred
=
1
if
received
[
'is_starred'
]
is
True
else
0
if
'is_trashed'
in
received
:
if
file
[
0
]
.
parent_id
is
None
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
file
[
0
]
.
is_trashed
=
1
if
received
[
'is_trashed'
]
is
True
else
0
file
[
0
]
.
save
()
return
{
'result'
:
True
}
#
TODO:
파일 복제
# 파일 복제
def
copy
(
request
,
file_id
):
return
{
'result'
:
True
}
# TODO: Auth
request
.
user_id
=
1
# Get File
file
=
File
.
objects
.
filter
(
id
=
file_id
,
type
=
'file'
,
is_trashed
=
0
,
deleted_at__isnull
=
True
)
# Check Exists
if
len
(
file
)
==
0
:
return
{
'result'
:
False
,
'error'
:
'잘못된 요청입니다.'
}
# Check Owner
is_auth
=
False
if
file
[
0
]
.
owner_user_id
==
request
.
user_id
:
is_auth
=
True
is_my_group
=
GroupUser
.
objects
.
filter
(
group_id
=
file
[
0
]
.
owner_group_id
,
user_id
=
request
.
user_id
)
if
len
(
is_my_group
)
!=
0
:
is_auth
=
True
if
is_auth
is
False
:
return
{
'result'
:
False
,
'error'
:
'경로가 잘못되었습니다.'
}
# Create UUID
new_file_id
=
uuid
.
uuid4
()
# S3 Copy
s3_copy
(
file_id
,
new_file_id
)
# Create
File
.
objects
.
create
(
id
=
new_file_id
,
parent_id
=
file
[
0
]
.
parent_id
,
owner_user_id
=
file
[
0
]
.
owner_user_id
,
owner_group_id
=
file
[
0
]
.
owner_group_id
,
uploader_id
=
request
.
user_id
,
type
=
file
[
0
]
.
type
,
name
=
'
%
s의 사본'
%
file
[
0
]
.
name
,
size
=
file
[
0
]
.
size
,
created_at
=
timezone
.
now
()
)
return
{
'result'
:
True
,
'file_id'
:
file_id
}
...
...
Please
register
or
login
to post a comment