diff --git a/socbackend/accounts/custom_auth.py b/socbackend/accounts/custom_auth.py index 9fe613c..f2a5525 100644 --- a/socbackend/accounts/custom_auth.py +++ b/socbackend/accounts/custom_auth.py @@ -5,17 +5,19 @@ class CookieJWTAuthentication(JWTAuthentication): def authenticate(self, request): - header = None + token = None + user = None try: - header = super().authenticate(request) + user, token = super().authenticate(request) + # print({user, token}) except Exception as e: logger.debug(f"Header login failed: {e}") - if header is None: + if token is None: # Attempt to get token from the cookie token = request.COOKIES.get("auth") if token: return self.get_user(self.get_validated_token(token)), None - return header, None + return user, token diff --git a/socbackend/projects/urls.py b/socbackend/projects/urls.py index 636595a..89fb7f4 100644 --- a/socbackend/projects/urls.py +++ b/socbackend/projects/urls.py @@ -8,6 +8,7 @@ path("/", views.ProjectDetailView.as_view(), name="project_detail"), path("wishlist/", views.ProjectWishlist.as_view(), name="wishlist"), path("preference/", views.ProjectPreference.as_view(), name="prefenrence"), + path('upload/', views.FileUploadView.as_view(), name='upload') # path("add/", views.ProjectAddView.as_view(), name="project_add"), ] diff --git a/socbackend/projects/views.py b/socbackend/projects/views.py index 9af5792..cfda858 100644 --- a/socbackend/projects/views.py +++ b/socbackend/projects/views.py @@ -5,7 +5,7 @@ # from projects.models import Season from accounts.custom_auth import CookieJWTAuthentication -from rest_framework import generics, views +from rest_framework import generics, views, status from rest_framework.response import Response from rest_framework.views import APIView from .models import Mentee, Project, MenteePreference, MenteeWishlist @@ -13,6 +13,8 @@ from accounts.models import UserProfile from rest_framework.permissions import AllowAny import logging +import os +import csv logger = logging.getLogger(__name__) # from .serializers import ( @@ -106,6 +108,79 @@ def delete(self, request): preference = MenteePreference.objects.get(mentee=mentee, project=project) preference.delete() return Response({"message": "Project removed from preferences."}) + +class FileUploadView(APIView): + authentication_classes = [CookieJWTAuthentication] + + EXPECTED_HEADERS = ['id','mentor','title','co_mentor_info','specific_category','description','mentee_max','prereuisites','banner_image','banner_image_link','timeline','checkpoints','general_category'] + + def post(self, request, *args, **kwargs): + try: + uploaded_file = request.FILES.get('file') + # print("Uploaded file:", uploaded_file) + + if not uploaded_file: + return Response({ + 'message': 'No file uploaded.' + }, status=status.HTTP_400_BAD_REQUEST) + + file_extension = os.path.splitext(uploaded_file.name)[1] + if file_extension.lower() != '.csv': + return Response({ + 'message': 'Unsupported file. Upload only csv file' + }, status=status.HTTP_400_BAD_REQUEST) + + + # read csv file directly from memory + csv_reader = csv.DictReader(uploaded_file.read().decode('utf-8').splitlines()) + headers = [] + + is_header_checked = False + + for idx, row in enumerate(csv_reader): + if not is_header_checked: + headers = list(row.keys()) + is_header_checked = True + if headers != self.EXPECTED_HEADERS: + raise Exception('Headers mistach: csv file headers corrupted') + + try: + project, created = Project.objects.get_or_create( + title=row['title'].strip(), + mentor=row['mentor'].strip(), + defaults={ + 'co_mentor_info': row['co_mentor_info'], + 'specific_category': row['specific_category'], + 'description': row['description'], + 'mentee_max': int(row['mentee_max']), + 'prereuisites': row['prereuisites'], + 'banner_image_link': row['banner_image_link'], + 'timeline': row['timeline'], + 'checkpoints': row['checkpoints'], + 'general_category': row['general_category'], + 'banner_image': row['banner_image'] + } + ) + + if created: + project.save() + print(f'new entry created for {project.title}') + else: + logger.error(f'project {project.code} already exists') + + except Exception as e: + logger.error(f'database error for {row['title']}: {e}') + + return Response({ + 'message': 'File upload successful' + }, status=status.HTTP_200_OK) + + except Exception as e: + logger.error(f'error: {e}') + # print('error: ', e) + return Response({ + 'message': 'Corrupted file' + }, status=status.HTTP_400_BAD_REQUEST) class BasicProjectListView(generics.ListAPIView): permission_classes = []