김재형

Merge remote-tracking branch 'origin/feature/item_api+folder_api' into develop

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