윤창목

Merge branch 'feature/item_api+folder_api' of http://khuhub.khu.ac.kr/2020-1-Clo…

…udComputing/C_Team_KhuDrive into feature/item_api+folder_api

# Conflicts:
#	backend/api/views.py
1 +<<<<<<< HEAD
1 import mimetypes 2 import mimetypes
2 import json 3 import json
3 import os 4 import os
...@@ -493,3 +494,500 @@ class SharedItemViewSet(viewsets.ModelViewSet): ...@@ -493,3 +494,500 @@ class SharedItemViewSet(viewsets.ModelViewSet):
493 item = ItemViewSet.as_view({ 494 item = ItemViewSet.as_view({
494 'delete': 'destroy', 495 'delete': 'destroy',
495 }) 496 })
497 +=======
498 +import mimetypes
499 +import json
500 +import os
501 +from datetime import datetime, timedelta
502 +
503 +import boto3
504 +from botocore.client import Config
505 +
506 +from django.core import serializers
507 +from django.views.decorators.csrf import csrf_exempt
508 +from rest_framework import viewsets
509 +from rest_framework import permissions
510 +from rest_framework.response import Response
511 +from rest_framework.decorators import action
512 +from rest_framework.permissions import IsAuthenticated, AllowAny
513 +
514 +from .models import Item, SharedItem, User
515 +from .serializers import UserSerializer, GroupSerializer, ItemSerializer
516 +from rest_framework import status
517 +from annoying.functions import get_object_or_None
518 +from django.conf import settings
519 +import jwt
520 +from django.http import HttpResponse, JsonResponse
521 +from khudrive.settings import AWS_SESSION_TOKEN, AWS_SECRET_ACCESS_KEY, AWS_ACCESS_KEY_ID, AWS_REGION, \
522 + AWS_STORAGE_BUCKET_NAME, AWS_ENDPOINT_URL
523 +
524 +
525 +class UserViewSet(viewsets.ModelViewSet):
526 + """
527 + API endpoint that allows users to be viewed or edited.
528 + """
529 + queryset = User.objects.all().order_by('-date_joined')
530 + serializer_class = UserSerializer
531 + permission_classes = [permissions.IsAuthenticatedOrReadOnly, permissions.AllowAny,
532 + # IsOwnerOrReadOnly
533 + ]
534 + permission_classes_by_action = {'get': [permissions.AllowAny],
535 + 'destroy': [permissions.AllowAny]}
536 +
537 + @csrf_exempt
538 + @action(detail=False, methods=['POST'], permission_classes=[permissions.AllowAny], url_path='signup',
539 + url_name='singup')
540 + def signup(self, request):
541 + user_id = request.POST.get('user_id', '')
542 + name = request.POST.get('name', '')
543 + password = request.POST.get('password', '')
544 + user = get_object_or_None(User, user_id=user_id)
545 + if user == None:
546 + user = User(user_id=user_id, name=name, password=password, total_size=100000, current_size=0)
547 + user.save()
548 + root = Item(is_folder=True, name="root", file_type="folder", path="", user_id=user.int_id, size=0,
549 + status=True)
550 + root.save()
551 + user.root_folder = root.item_id
552 + user.save()
553 + return Response({
554 + 'message': 'user created',
555 + 'int_id': user.int_id,
556 + 'user_id': user.user_id,
557 + 'name': user.name,
558 + 'root_folder': root.item_id,
559 + 'total_size': user.total_size,
560 + 'current_size': user.current_size,
561 + 'created_time': user.created_time
562 + },
563 + status=status.HTTP_200_OK,
564 + )
565 + else:
566 + return Response({'message': 'user is already exist.'}, status=status.HTTP_204_NO_CONTENT)
567 +
568 + @csrf_exempt
569 + @action(methods=['post'], detail=False, permission_classes=[permissions.AllowAny],
570 + url_path='login', url_name='login')
571 + def login(self, request):
572 + if not request.data:
573 + return Response({'Error': "Please provide user_id/password"}, status=status.HTTP_400_BAD_REQUEST)
574 + user_id = request.POST['user_id']
575 + password = request.POST['password']
576 + try:
577 + user = User.objects.get(user_id=user_id, password=password)
578 + except User.DoesNotExist:
579 + return Response({'Error': "Invalid user_id/password"}, status=status.HTTP_400_BAD_REQUEST)
580 + if user:
581 + payload1 = {
582 + 'int_id': user.int_id,
583 + 'user_id': user.user_id,
584 + 'exp': datetime.utcnow() + timedelta(seconds=300)
585 + }
586 + payload2 = {
587 + 'int_id': user.int_id,
588 + 'user_id': user.user_id,
589 + 'exp': datetime.utcnow() + timedelta(days=5)
590 + }
591 + access = jwt.encode(payload1, settings.SECRET_KEY, algorithm='HS256').decode('utf-8')
592 + refresh = jwt.encode(payload2, settings.SECRET_KEY, algorithm='HS256').decode('utf-8')
593 + exp = jwt.decode(access, settings.SECRET_KEY, algorithm='HS256')['exp']
594 + token = {'access': access,
595 + 'refresh': refresh,
596 + 'exp': exp,
597 + 'user': {
598 + 'int_id': user.int_id,
599 + 'user_id': user.user_id,
600 + 'name': user.name,
601 + 'total_size': user.total_size,
602 + 'current_size': user.current_size,
603 + 'root_folder': user.root_folder
604 + }}
605 + return JsonResponse(
606 + token,
607 + status=status.HTTP_200_OK,
608 + )
609 + else:
610 + return JsonResponse(
611 + {'Error': "Invalid credentials"},
612 + status=status.HTTP_400_BAD_REQUEST,
613 + )
614 + return JsonResponse(status=status.HTTP_405_METHOD_NOT_ALLOWED)
615 +
616 + def get(self, request, pk):
617 + user = User.objects.filter(int_id=pk)
618 + data = serializers.serialize("json", user)
619 + json_data = json.loads(data)
620 + res = json_data[0]['fields']
621 + res['id'] = json_data[0]['pk']
622 + return Response({'data': res}, status=status.HTTP_200_OK)
623 +
624 + def get_permissions(self):
625 + try:
626 + # return permission_classes depending on `action`
627 + return [permission() for permission in self.permission_classes_by_action[self.action]]
628 + except KeyError:
629 + # action is not set return default permission_classes
630 + return [permission() for permission in self.permission_classes]
631 +
632 +
633 +class ItemViewSet(viewsets.ViewSet):
634 + queryset = Item.objects.all()
635 + serializer_class = ItemSerializer
636 + permission_classes = [permissions.IsAuthenticatedOrReadOnly, permissions.AllowAny,
637 + # IsOwnerOrReadOnly
638 + ]
639 + permission_classes_by_action = {'get': [permissions.AllowAny],
640 + 'destroy': [permissions.AllowAny]}
641 +
642 + # url: items/search
643 + @action(methods=['GET'], detail=False, permission_classes=[AllowAny], url_path='search', url_name='search')
644 + def search(self, request):
645 + if request.method == 'GET':
646 + keyword = request.GET.get('keyword', '')
647 + # user_id = request.GET.get('user_id', '')
648 + item_list = Item.objects.filter(name__icontains=keyword)
649 +
650 + data = serializers.serialize("json", item_list)
651 + json_data = json.loads(data)
652 + res = []
653 + for i in json_data:
654 + t = i['fields']
655 + t['id'] = i['pk']
656 + res.append(t)
657 + return Response({'data': {'list': res}}, status=status.HTTP_200_OK)
658 +
659 + """
660 + # url: items/11/
661 + # 마지막 slash도 써주어야함
662 + def get(self, request, pk):
663 + #print(pk)
664 + s3 = boto3.client('s3')
665 + s3_bucket = AWS_STORAGE_BUCKET_NAME
666 +
667 + #파일 객체 생성
668 + object_name = request.GET.get('name', '')
669 +
670 + presigned_url = s3.generate_presigned_url(
671 + 'get_object',
672 + Params={'Bucket': s3_bucket,
673 + 'Key': object_name},
674 + ExpiresIn = 3600
675 + )
676 +
677 + return Response({'message': presigned_url}, status=status.HTTP_200_OK)
678 + """
679 +
680 + # url: items/11/
681 + # 마지막 slash도 써주어야함
682 + def get(self, request, pk):
683 + s3 = boto3.client(
684 + 's3',
685 + region_name=AWS_REGION,
686 + aws_access_key_id=AWS_ACCESS_KEY_ID,
687 + aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
688 + aws_session_token=AWS_SESSION_TOKEN,
689 + endpoint_url=AWS_ENDPOINT_URL or None,
690 + config=Config(s3={'addressing_style': 'path'})
691 + )
692 + s3_bucket = AWS_STORAGE_BUCKET_NAME
693 +
694 + item = Item.objects.filter(item_id=pk)
695 + object_name = item.get().name
696 + data = serializers.serialize("json", item)
697 + json_data = json.loads(data)
698 +
699 + presigned_url = s3.generate_presigned_url(
700 + 'get_object',
701 + Params={'Bucket': s3_bucket,
702 + 'Key': object_name},
703 + ExpiresIn=3600
704 + )
705 +
706 + res = json_data[0]['fields']
707 + res['id'] = json_data[0]['pk']
708 + res['signed_url'] = presigned_url
709 + return Response({'data': res}, status=status.HTTP_200_OK)
710 +
711 + # url: items/11/
712 + # 마지막 slash도 써주어야함
713 + def destroy(self, request, pk):
714 + if request.method == 'DELETE':
715 + item = get_object_or_None(Item, item_id=pk)
716 + if item != None:
717 + if item.is_folder == True: # 폴더는 삭제 안되도록 처리
718 + return Response({'message': 'This item is folder.'}, status=status.HTTP_200_OK)
719 + item.is_deleted = True
720 + item.save()
721 + # item.delete() 이거 하면 완전 삭제되어버림 is deleted True 면 휴지통에서 리스트 조회할 수 있도록!
722 + return Response({'message': 'destroy complete'}, status=status.HTTP_200_OK)
723 + return Response({'message': 'item is not existed.'}, status=status.HTTP_204_NO_CONTENT)
724 +
725 + @action(methods=['POST'], detail=True, permission_classes=[AllowAny], url_path='restore', url_name='restore')
726 + def restore(self, request, pk):
727 + if request.method == 'POST':
728 + item = get_object_or_None(Item, item_id=pk)
729 + if item != None:
730 + item.is_deleted = False
731 + item.save()
732 + return Response({'message': 'restore complete'}, status=status.HTTP_200_OK)
733 + return Response({'message': 'item is not existed.'}, status=status.HTTP_204_NO_CONTENT)
734 +
735 + @action(methods=['DELETE'], detail=True, permission_classes=[AllowAny], url_path='delete', url_name='delete')
736 + def delete(self, request, pk):
737 + if request.method == 'DELETE':
738 + item = get_object_or_None(Item, item_id=pk)
739 + if item != None:
740 + if item.is_folder == True: # 폴더는 삭제 안되도록 처리
741 + return Response({'message': 'This item is folder.'}, status=status.HTTP_200_OK)
742 + item.delete()
743 + return Response({'message': 'delete permanently complete'}, status=status.HTTP_200_OK)
744 + return Response({'message': 'item is not existed.'}, status=status.HTTP_204_NO_CONTENT)
745 +
746 +
747 + # url: items/11/move
748 + # 마지막 slash도 써주어야함
749 + @action(methods=['POST'], detail=True, permission_classes=[AllowAny], url_path='move', url_name='move')
750 + def move(self, request, pk):
751 + if request.method == 'POST':
752 + parent_id = request.POST.get('parent', '')
753 + name = request.POST.get('name','')
754 + child = get_object_or_None(Item, item_id=pk)
755 +
756 + if child == None:
757 + return Response({'message': 'item is not existed.'}, status=status.HTTP_204_NO_CONTENT)
758 +
759 + if parent_id != '':
760 + parent = get_object_or_None(Item, item_id=parent_id)
761 +
762 + if parent == None:
763 + return Response({'message': 'parent is not existed.'}, status=status.HTTP_200_OK)
764 + if parent.is_folder == False:
765 + return Response({'message': 'parent is not folder.'}, status=status.HTTP_200_OK)
766 +
767 + if parent != None and parent.is_folder == True:
768 + child.parent = parent_id
769 + else:
770 + parent_id = child.parent
771 +
772 + if name != '':
773 + child.name = name;
774 +
775 + child.save()
776 + child = Item.objects.filter(item_id = pk)
777 + child_data = serializers.serialize("json", child)
778 + json_child = json.loads(child_data)
779 + res = json_child[0]['fields']
780 + res['id'] = pk
781 + parent = Item.objects.filter(item_id = parent_id)
782 + parent_data = serializers.serialize("json", parent)
783 + json_parent = json.loads(parent_data)[0]['fields']
784 + res['parentInfo'] = json_parent
785 +
786 + return Response({'data': res}, status=status.HTTP_200_OK)
787 +
788 + @action(methods=['POST'], detail=True, permission_classes=[AllowAny], url_path='copy', url_name='copy')
789 + def copy(self, request, pk):
790 + if request.method == 'POST':
791 + parent_id = request.POST.get('parent', '')
792 + parent = get_object_or_None(Item, item_id=parent_id)
793 + if parent != None and parent.is_folder == True:
794 + child = get_object_or_None(Item, item_id=pk)
795 + if child == None:
796 + return Response({'message': 'item is not existed.'}, status=status.HTTP_204_NO_CONTENT)
797 + if child.is_folder == True:
798 + return Response({'message': 'item is folder'}, status=status.HTTP_204_NO_CONTENT)
799 + copiedName = child.name + "_복사본_" + str(datetime.now().strftime('%Y-%m-%d %H:%M'))
800 + copiedItem = Item(is_folder=False, name=copiedName, path=child.path, parent=parent_id,
801 + user_id=child.user_id, size=child.size, status=child.status)
802 + copiedItem.save()
803 +
804 + copiedItem = Item.objects.filter(name=copiedName)
805 + copied_data = serializers.serialize("json", copiedItem)
806 + json_data = json.loads(copied_data)
807 + res = json_data[0]['fields']
808 + res['id'] = json_data[0]['pk']
809 + parent = Item.objects.filter(item_id=parent_id)
810 + parent_data = serializers.serialize("json", parent)
811 + json_parent = json.loads(parent_data)[0]['fields']
812 + res['parentInfo'] = json_parent
813 + return Response({'data': res}, status=status.HTTP_200_OK)
814 + if parent == None:
815 + return Response({'message': 'parent is not existed.'}, status=status.HTTP_200_OK)
816 + if parent.is_folder == False:
817 + return Response({'message': 'parent is not folder.'}, status=status.HTTP_200_OK)
818 + return Response({'message': 'item is not existed.'}, status=status.HTTP_204_NO_CONTENT)
819 +
820 + def get_permissions(self):
821 + try:
822 + # return permission_classes depending on `action`
823 + return [permission() for permission in self.permission_classes_by_action[self.action]]
824 + except KeyError:
825 + # action is not set return default permission_classes
826 + return [permission() for permission in self.permission_classes]
827 +
828 + # url: items/{key}/children/
829 + @action(methods=['GET', 'POST'], detail=True, permission_classes=[AllowAny],
830 + url_path='children', url_name='children')
831 + def children(self, request, pk):
832 + if request.method == 'GET':
833 + children = Item.objects.filter(parent=pk, is_deleted=False, status=True)
834 + children_data = serializers.serialize("json", children)
835 + json_children = json.loads(children_data)
836 + parent = Item.objects.filter(item_id=pk) # item
837 + parent_data = serializers.serialize("json", parent)
838 + json_parent = json.loads(parent_data)[0]['fields']
839 + res = json_parent
840 + res['id'] = pk
841 + children_list = []
842 + for i in json_children:
843 + t = i['fields']
844 + t['id'] = i['pk']
845 + children_list.append(t)
846 + res['list'] = children_list
847 + return Response({'data': res}, status=status.HTTP_200_OK)
848 + if request.method == 'POST':
849 + name = request.POST.get('name', '')
850 + user_id = request.GET.get('user_id', '')
851 + item = Item(is_folder=True, name=name, file_type="folder", path="", parent=pk, user_id=user_id, size=0,
852 + status=True)
853 + item.save()
854 + item = Item.objects.filter(item_id=item.item_id)
855 + item_data = serializers.serialize("json", item)
856 + json_item = json.loads(item_data)
857 + res = json_item[0]['fields']
858 + res['id'] = json_item[0]['pk']
859 + res['inside_folder_list'] = []
860 + res['inside_file_list'] = []
861 + return Response({'data': res}, status=status.HTTP_200_OK)
862 +
863 + @action(methods=['GET'], detail=False, permission_classes=[AllowAny],
864 + url_path='trash', url_name='trash')
865 + def trash(self, request):
866 + if request.method == 'GET':
867 + children = Item.objects.filter(is_deleted = True)
868 + children_data = serializers.serialize("json", children)
869 + json_children = json.loads(children_data)
870 + res = {}
871 + children_list = []
872 + for i in json_children:
873 + t = i['fields']
874 + t['id'] = i['pk']
875 + children_list.append(t)
876 + res['list'] = children_list
877 + return Response({'data': res}, status=status.HTTP_200_OK)
878 +
879 + # url: /upload/
880 + @action(methods=['POST'], detail=True, permission_classes=[AllowAny],
881 + url_path='upload', url_name='upload')
882 + def upload(self, request, pk):
883 + if request.method == 'POST':
884 + s3 = boto3.client(
885 + 's3',
886 + region_name=AWS_REGION,
887 + aws_access_key_id=AWS_ACCESS_KEY_ID,
888 + aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
889 + aws_session_token=AWS_SESSION_TOKEN,
890 + endpoint_url=AWS_ENDPOINT_URL or None,
891 + config=Config(s3={'addressing_style': 'path'})
892 + )
893 + s3_bucket = AWS_STORAGE_BUCKET_NAME
894 +
895 + # 파일 객체 생성
896 + file_name = request.POST.get('name', '')
897 + file_size = request.POST.get('size', '')
898 + file_id = request.POST.get('item_id', '')
899 + file_parent = pk
900 + file_type = mimetypes.guess_type(file_name)[0]
901 + upload_item = Item(name=file_name, size=file_size, user_id=1, file_type=file_type, parent=file_parent)
902 + upload_item.save()
903 +
904 + date_long = datetime.utcnow().strftime('%Y%m%dT000000Z')
905 +
906 + presigned_post = s3.generate_presigned_post(
907 + s3_bucket,
908 + file_id,
909 + {
910 + "acl": "private",
911 + "Content-Type": file_type,
912 + "Content-Disposition": "attachment",
913 + 'region': AWS_REGION,
914 + 'x-amz-algorithm': 'AWS4-HMAC-SHA256',
915 + 'x-amz-date': date_long
916 + },
917 + [
918 + {"acl": "private"},
919 + {"Content-Type": file_type},
920 + {"Content-Disposition": "attachment"},
921 + {'x-amz-algorithm': 'AWS4-HMAC-SHA256'},
922 + {'x-amz-date': date_long}
923 + ],
924 + 3600
925 + )
926 +
927 + item = Item.objects.filter(item_id=upload_item.item_id)
928 + item_data = serializers.serialize("json", item)
929 + json_item = json.loads(item_data)
930 + res = json_item[0]['fields']
931 + res['id'] = json_item[0]['pk']
932 +
933 + data = {
934 + "signed_url": presigned_post,
935 + 'url': '%s/%s' % (presigned_post["url"], file_id),
936 + 'item': res
937 + }
938 +
939 + return Response(data, status=status.HTTP_200_OK)
940 +
941 + # url: /status/
942 + @action(methods=['POST'], detail=True, permission_classes=[AllowAny],
943 + url_path='status', url_name='status')
944 + def status(self, request, *args, **kwargs):
945 + if request.method == 'POST':
946 + pk = request.POST.get('item_id', '')
947 + queryset = Item.objects.filter(item_id=pk)
948 + for cand in queryset:
949 + cand.status = True
950 + cand.save()
951 + return Response({'Message': 'File Upload Successful'}, status=status.HTTP_200_OK)
952 + return Response({'Error': 'No such item found in queryset'}, status=status.HTTP_400_BAD_REQUEST)
953 +
954 +
955 +class SharedItemViewSet(viewsets.ModelViewSet):
956 + queryset = SharedItem.objects.all()
957 + # serializer_class = SharedItemSerializer
958 + permission_classes = [permissions.IsAuthenticatedOrReadOnly, permissions.AllowAny,
959 + # IsOwnerOrReadOnly
960 + ]
961 +
962 + # url: http://localhost:8000/items/1/share/
963 + # 마지막 slash도 써주어야함
964 + @csrf_exempt
965 + @action(methods=['POST'], detail=True, permission_classes=[AllowAny], url_path='share', url_name='share')
966 + def share(self, request, pk):
967 + if request.method == 'POST':
968 + password = request.POST.get('password', '')
969 + expires = request.POST.get('expires', '')
970 +
971 + sharedfile = get_object_or_None(SharedItem, item_id=pk)
972 + if sharedfile != None:
973 + # 서버는 정상이나 이미 공유객체로 등록된 파일임
974 + return Response({'message': 'This file is already shared'}, status=status.HTTP_200_OK)
975 + sharedfile = SharedItem(item_id=pk, password=password, expires=expires)
976 + sharedfile.save()
977 + sharedfile = SharedItem.objects.get(item_id=pk)
978 +
979 + # sf = serializers.serialize("json", sharedfile)
980 + item = Item.objects.filter(item_id=pk)
981 + item_json = serializers.serialize("json", item)
982 +
983 + json_data = json.loads(item_json)
984 + print(json_data)
985 + res = json_data[0]['fields']
986 + res['id'] = json_data[0]['pk']
987 + return Response({"shared": sharedfile.created_time, 'data': res}, status=status.HTTP_200_OK)
988 +
989 +
990 +item = ItemViewSet.as_view({
991 + 'delete': 'destroy',
992 +})
993 +>>>>>>> ecbbba22f47e9fea8c06b1d35c71e3699b5616e5
......