신은섭(Shin Eun Seop)

Merge branch 'develop' into feature/ui

...@@ -105,3 +105,9 @@ ENV/ ...@@ -105,3 +105,9 @@ ENV/
105 105
106 # mypy 106 # mypy
107 .mypy_cache/ 107 .mypy_cache/
108 +
109 +# aws configutation file
110 +aws_conf.py
111 +
112 +# media file
113 +**/media/*
...\ No newline at end of file ...\ No newline at end of file
......
1 -"""
2 -Django settings for dcloud project.
3 -
4 -Generated by 'django-admin startproject' using Django 2.0.4.
5 -
6 -For more information on this file, see
7 -https://docs.djangoproject.com/en/2.0/topics/settings/
8 -
9 -For the full list of settings and their values, see
10 -https://docs.djangoproject.com/en/2.0/ref/settings/
11 -"""
12 -
13 import os 1 import os
2 +from dcloud import aws_conf
14 3
15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 4 # 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__))) 5 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 6
18 -
19 -# Quick-start development settings - unsuitable for production
20 -# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
21 -
22 # SECURITY WARNING: keep the secret key used in production secret! 7 # SECURITY WARNING: keep the secret key used in production secret!
23 SECRET_KEY = '534f6m=i@*)=q3kuwlge1m3c+@^cabr3ttcx*omv^+dorydjfr' 8 SECRET_KEY = '534f6m=i@*)=q3kuwlge1m3c+@^cabr3ttcx*omv^+dorydjfr'
24 9
...@@ -27,9 +12,7 @@ DEBUG = True ...@@ -27,9 +12,7 @@ DEBUG = True
27 12
28 ALLOWED_HOSTS = [] 13 ALLOWED_HOSTS = []
29 14
30 -
31 # Application definition 15 # Application definition
32 -
33 INSTALLED_APPS = [ 16 INSTALLED_APPS = [
34 'django.contrib.admin', 17 'django.contrib.admin',
35 'django.contrib.auth', 18 'django.contrib.auth',
...@@ -39,7 +22,8 @@ INSTALLED_APPS = [ ...@@ -39,7 +22,8 @@ INSTALLED_APPS = [
39 'django.contrib.staticfiles', 22 'django.contrib.staticfiles',
40 'rest_framework', 23 'rest_framework',
41 'restful.apps.RestfulConfig', 24 'restful.apps.RestfulConfig',
42 - 'website' 25 + 'website',
26 + 's3direct',
43 ] 27 ]
44 28
45 MIDDLEWARE = [ 29 MIDDLEWARE = [
...@@ -123,6 +107,59 @@ USE_TZ = True ...@@ -123,6 +107,59 @@ USE_TZ = True
123 STATIC_URL = '/static/' 107 STATIC_URL = '/static/'
124 STATIC_ROOT = os.path.join(BASE_DIR, 'static') 108 STATIC_ROOT = os.path.join(BASE_DIR, 'static')
125 109
110 +MEDIA_URL = '/media/'
111 +MEDIA_ROOT = os.path.join(BASE_DIR, "media")
112 +
126 # Login redirect 113 # Login redirect
127 114
128 -LOGIN_REDIRECT_URL = '/'
...\ No newline at end of file ...\ No newline at end of file
115 +LOGIN_REDIRECT_URL = '/'
116 +
117 +# AWS
118 +
119 +# If these are not defined, the EC2 instance profile and IAM role are used.
120 +# This requires you to add boto3 (or botocore, which is a dependency of boto3)
121 +# to your project dependencies.
122 +AWS_ACCESS_KEY_ID = aws_conf.AWS_ACCESS_KEY_ID
123 +AWS_SECRET_ACCESS_KEY = aws_conf.AWS_SECRET_ACCESS_KEY
124 +
125 +AWS_STORAGE_BUCKET_NAME = aws_conf.AWS_STORAGE_BUCKET_NAME
126 +
127 +# The region of your bucket, more info:
128 +# http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
129 +S3DIRECT_REGION = 'ap-northeast-2'
130 +
131 +# Destinations, with the following keys:
132 +#
133 +# key [required] Where to upload the file to, can be either:
134 +# 1. '/' = Upload to root with the original filename.
135 +# 2. 'some/path' = Upload to some/path with the original filename.
136 +# 3. functionName = Pass a function and create your own path/filename.
137 +# key_args [optional] Arguments to be passed to 'key' if it's a function.
138 +# auth [optional] An ACL function to whether the current Django user can perform this action.
139 +# allowed [optional] List of allowed MIME types.
140 +# acl [optional] Give the object another ACL rather than 'public-read'.
141 +# cache_control [optional] Cache control headers, eg 'max-age=2592000'.
142 +# content_disposition [optional] Useful for sending files as attachments.
143 +# bucket [optional] Specify a different bucket for this particular object.
144 +# server_side_encryption [optional] Encryption headers for buckets that require it.
145 +
146 +S3DIRECT_DESTINATIONS = {
147 + 'example_destination': {
148 + # REQUIRED
149 + 'key': '/',
150 +
151 + # OPTIONAL
152 + #'auth': lambda u: u.is_staff, # Default allow anybody to upload
153 + #'allowed': ['image/jpeg', 'image/png', 'video/mp4'], # Default allow all mime types
154 + #'bucket': 'pdf-bucket', # Default is 'AWS_STORAGE_BUCKET_NAME'
155 + 'acl': 'private', # Defaults to 'public-read'
156 + 'cache_control': 'max-age=2592000', # Default no cache-control
157 + #'content_disposition': 'attachment', # Default no content disposition
158 + #'content_length_range': (5000, 20000000), # Default allow any size
159 + #'server_side_encryption': 'AES256', # Default no encryption
160 + },
161 + 'example_other': {
162 + 'key': lambda filename, args: args + '/' + filename,
163 + 'key_args': 'uploads/images', # Only if 'key' is a function
164 + }
165 +}
......
...@@ -10,5 +10,6 @@ urlpatterns = [ ...@@ -10,5 +10,6 @@ urlpatterns = [
10 url(r'^accounts/login/$', views.login, name='login'), 10 url(r'^accounts/login/$', views.login, name='login'),
11 url(r'^accounts/logout/$', views.logout, name='logout', kwargs={'next_page': '/'}), 11 url(r'^accounts/logout/$', views.logout, name='logout', kwargs={'next_page': '/'}),
12 12
13 + url(r'^s3direct/', include('s3direct.urls')),
13 ] 14 ]
14 15
......
...@@ -2,12 +2,13 @@ from django.db import models ...@@ -2,12 +2,13 @@ from django.db import models
2 2
3 # Create your models here. 3 # Create your models here.
4 class File(models.Model): 4 class File(models.Model):
5 + file = models.FileField(blank=False, null=False)
6 + # title = models.CharField(max_length=100)
5 created = models.DateTimeField(auto_now_add=True) 7 created = models.DateTimeField(auto_now_add=True)
6 - modified = models.DateTimeField(auto_now=True) 8 +
7 - title = models.CharField(max_length=100) 9 + # modified = models.DateTimeField(auto_now=True)
8 # file_name = models.CharField(max_length=100, primary_key=True) 10 # file_name = models.CharField(max_length=100, primary_key=True)
9 - 11 + # object_key = models.CharField(max_length=1025)
10 - object_key = models.CharField(max_length=1025)
11 # owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE) 12 # owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
12 13
13 class Meta: 14 class Meta:
......
...@@ -27,4 +27,24 @@ def list_path(bucket, user, path): ...@@ -27,4 +27,24 @@ def list_path(bucket, user, path):
27 27
28 return {'files':files} 28 return {'files':files}
29 29
30 -# print(list_path(BUCKET, 'test1', ''))
...\ No newline at end of file ...\ No newline at end of file
30 +def upload_file(bucket, user, local_path, key):
31 + return S3.upload_file(local_path, bucket, user+"/"+key)
32 +
33 +def download_file(bucket, user, local_path, key):
34 + return S3.download_file(bucket, user+"/"+key, local_path)
35 +
36 +def delete_path(bucket, user, path):
37 + return S3.delete_object(Bucket=bucket, Key=user+"/"+path)
38 +
39 +def make_directory(bucket, user, path):
40 + return S3.put_object(Bucket=BUCKET, Key=user+"/"+path)
41 +
42 +#
43 +def move_file(bucket, user, old_path, new_path):
44 + S3.copy_object(Bucket=bucket, CopySource=bucket+"/"+user+"/"+old_path, Key=user+"/"+new_path)
45 + S3.delete_object(Bucket=bucket, Key=user+"/"+old_path)
46 + return
47 +
48 +def copy_file(bucket, user, old_path, new_path):
49 + S3.copy_object(Bucket=bucket, CopySource=bucket+"/"+user+"/"+old_path, Key=user+"/"+new_path)
50 + return
......
...@@ -7,4 +7,4 @@ class FileSerializer(serializers.ModelSerializer): ...@@ -7,4 +7,4 @@ class FileSerializer(serializers.ModelSerializer):
7 7
8 class Meta: 8 class Meta:
9 model = File 9 model = File
10 - fields = ('created', 'updated', 'object_key') 10 + fields = ('file', 'created')
......
...@@ -3,9 +3,12 @@ from django.shortcuts import redirect ...@@ -3,9 +3,12 @@ from django.shortcuts import redirect
3 from rest_framework.urlpatterns import format_suffix_patterns 3 from rest_framework.urlpatterns import format_suffix_patterns
4 from restful import views 4 from restful import views
5 5
6 +file_regex = '[\w\s가-힣.\`\'\˜\=\+\#\ˆ\@\$\&\-\.\(\)\{\}\;\[\]]'
7 +
6 urlpatterns = [ 8 urlpatterns = [
7 - url(r'^files/(?P<path>([a-zA-z0-9가-힣._-]*/)*)$', views.FileList.as_view(), name='file-list'), 9 + url(r'^list/(?P<path>([\w\s가-힣.\`\'\˜\=\+\#\ˆ\@\$\&\-\.\(\)\{\}\;\[\]]*/)*)$', views.FileList.as_view(), name='file-list'),
8 - url(r'^files/(?P<pk>[0-9]+)/$', views.FileDetail.as_view()), 10 + url(r'^file/(?P<path>([\w\s가-힣.\`\'\˜\=\+\#\ˆ\@\$\&\-\.\(\)\{\}\;\[\]]*/*)*)$', views.FileDetail.as_view(), name='file-detail'),
11 + url(r'^file-mod/(?P<old_path>([\w\s가-힣.\`\'\˜\=\+\#\ˆ\@\$\&\-\.\(\)\{\}\;\[\]]*/*)*)&(?P<new_path>([\w\s가-힣.\`\'\˜\=\+\#\ˆ\@\$\&\-\.\(\)\{\}\;\[\]]]*/*)*)$', views.FileCopyMove.as_view(), name='file-copy-move')
9 ] 12 ]
10 13
11 urlpatterns = format_suffix_patterns(urlpatterns) 14 urlpatterns = format_suffix_patterns(urlpatterns)
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -13,48 +13,74 @@ class FileList(APIView): ...@@ -13,48 +13,74 @@ class FileList(APIView):
13 List all file, or create a new snippet. 13 List all file, or create a new snippet.
14 """ 14 """
15 15
16 - def get(self, request, path='/', format=None): 16 + """
17 - # file = File.objects.all() 17 + list files or view detail
18 - # serializer = FileSerializer(file, many=True) 18 + """
19 - # print(serializer.data) 19 + def get(self, request, path="/", format=None):
20 - # return Response(serializer.data) 20 + user = request.user
21 - data = s3_interface.list_path(s3_interface.BUCKET, 'test1', path) 21 + data = s3_interface.list_path(s3_interface.BUCKET, user.username, path)
22 return Response(data) 22 return Response(data)
23 23
24 + """
25 + upload file
26 + """
27 + def post(self, request, path="/", format=None):
28 + # file upload
29 + # upload to server
30 + file_serializer = FileSerializer(data=request.data)
31 + if file_serializer.is_valid():
32 + file_serializer.save()
33 + # upload to s3
34 + file_path = '.' + file_serializer.data.get('file')
35 + user = request.user
36 + data = s3_interface.upload_file(s3_interface.BUCKET, user.username, file_path, path+file_path.split('/')[-1])
37 + # TODO upload check
38 + # TODO remove local file
39 + return Response(file_serializer.data, status=status.HTTP_201_CREATED)
40 + else:
41 + return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
42 + return Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
43 +
44 + """
45 + make directory
46 + """
47 + def put(self, request, path="/", format=None):
48 + user = request.user
49 + data = s3_interface.make_directory(s3_interface.BUCKET, user.username, path)
50 + return Response(data, status=status.HTTP_201_CREATED)
24 51
25 - def post(self, request, format=None): 52 +class FileDetail(APIView):
26 - serializer = FileSerializer(data=request.data) 53 + """
27 - if serializer.is_valid(): 54 + Download or delete a file instance.
28 - serializer.save() 55 + """
29 - return Response(serializer.data, status=status.HTTP_201_CREATED)
30 - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
31 56
57 + def get(self, request, path="/", format=None):
58 + # download file from s3
59 + file = 'media/'+path.split('/')[-1]
60 + user = request.user
61 + s3_interface.download_file(s3_interface.BUCKET, user.username, file, path)
62 + # TODO error
63 + return Response({'file': file})
32 64
33 -class FileDetail(APIView): 65 + def delete(self, request, path="/", format=None):
66 + user = request.user
67 + result = s3_interface.delete_path(s3_interface.BUCKET, user.username, path)
68 + return Response(result)
69 +
70 +class FileCopyMove(APIView):
71 + """
72 + Download or delete a file instance.
34 """ 73 """
35 - Retrieve, update or delete a file instance. 74 + #TODO is folder move, copy well?
36 - """ 75 + # move
37 - def get_object(self, pk): 76 + def post(self, request, old_path, new_path, format=None):
38 - try: 77 + user = request.user
39 - return File.objects.get(pk=pk) 78 + if request.data.get('method') == 'mv':
40 - except File.DoesNotExist: 79 + s3_interface.move_file(s3_interface.BUCKET, user.username, old_path, new_path)
41 - raise Http404 80 + elif request.data.get('method') == 'cp':
42 - 81 + s3_interface.copy_file(s3_interface.BUCKET, user.username, old_path, new_path)
43 - def get(self, request, pk, format=None): 82 + else:
44 - file = self.get_object(pk) 83 + return Response({'stats': 'bad_request'}, status=status.HTTP_400_BAD_REQUEST)
45 - serializer = FileSerializer(file) 84 + return Response({'old_path': old_path, 'new_path': new_path})
46 - return Response(serializer.data, status=status.HTTP_200_OK) 85 +
47 -
48 - def put(self, request, pk, format=None):
49 - file = self.get_object(pk)
50 - serializer = FileSerializer(file, data=request.data)
51 - if serializer.is_valid():
52 - serializer.save()
53 - return Response(serializer.data, status=status.HTTP_204_NO_CONTENT)
54 - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
55 -
56 - def delete(self, request, pk, format=None):
57 - file = self.get_object(pk)
58 - file.delete()
59 - return Response(status=status.HTTP_204_NO_CONTENT)
60 86
......
...@@ -2,6 +2,7 @@ from django.contrib.auth import login, authenticate, logout ...@@ -2,6 +2,7 @@ from django.contrib.auth import login, authenticate, logout
2 from django.contrib.auth.forms import UserCreationForm 2 from django.contrib.auth.forms import UserCreationForm
3 from django.shortcuts import render, redirect 3 from django.shortcuts import render, redirect
4 from django.contrib.auth.decorators import login_required 4 from django.contrib.auth.decorators import login_required
5 +from django.contrib.auth.models import User
5 6
6 def signup(request): 7 def signup(request):
7 if request.method == 'POST': 8 if request.method == 'POST':
...@@ -31,7 +32,10 @@ def delete_account(request): ...@@ -31,7 +32,10 @@ def delete_account(request):
31 @login_required 32 @login_required
32 def delete_account_success(request): 33 def delete_account_success(request):
33 if request.method == 'GET': 34 if request.method == 'GET':
34 - # TODO Add delete account 35 + # delete account
36 + u = User.objects.get(username = request.user.username)
37 + u.delete()
38 + # logout
35 logout(request) 39 logout(request)
36 return render(request, 'registration/delete_account_success.html') 40 return render(request, 'registration/delete_account_success.html')
37 41
......
1 from django import forms 1 from django import forms
2 +from s3direct.widgets import S3DirectWidget
2 3
3 -# class PostForm(forms.ModelForm):
4 -# class Meta:
5 -# model = Post
6 -# fields = ('title', 'text')
...\ No newline at end of file ...\ No newline at end of file
4 +class S3DirectUploadForm(forms.Form):
5 + images = forms.URLField(widget=S3DirectWidget(dest='example_destination'))
......
1 from django.db import models 1 from django.db import models
2 -from django.utils import timezone 2 +from s3direct.fields import S3DirectField
3 3
4 +class Example(models.Model):
5 + video = S3DirectField(dest='example_destination')
...\ No newline at end of file ...\ No newline at end of file
......
1 from django.shortcuts import render, get_object_or_404, redirect, Http404 1 from django.shortcuts import render, get_object_or_404, redirect, Http404
2 from django.utils import timezone 2 from django.utils import timezone
3 from django.contrib.auth.decorators import login_required 3 from django.contrib.auth.decorators import login_required
4 +from django.views.generic import FormView
5 +from website.forms import S3DirectUploadForm
4 from restful.models import File 6 from restful.models import File
5 import requests 7 import requests
6 8
...@@ -11,6 +13,6 @@ def home(request): ...@@ -11,6 +13,6 @@ def home(request):
11 13
12 @login_required 14 @login_required
13 def file_list(request): 15 def file_list(request):
14 - files = requests.get('http://localhost:8000/restapi/files') 16 + files = requests.get('http://localhost:8000/restapi/list')
15 files = files.json() 17 files = files.json()
16 return render(request, 'website/file_list.html', files) 18 return render(request, 'website/file_list.html', files)
......