Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of Endpoints for reupload, download and remove documents functionality #56

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
187 changes: 145 additions & 42 deletions apps/jobs/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import jwt
import uuid
import os
from re import search
import django.core.exceptions
from django.http import FileResponse
from django.db.utils import IntegrityError
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import status, viewsets
Expand Down Expand Up @@ -78,7 +80,9 @@ def list(self, request):

# get number of applicants
if serialized_job_data:
serialized_job_data = JobViewSets.get_number_of_applicants(serialized_job_data)
serialized_job_data = JobViewSets.get_number_of_applicants(
serialized_job_data
)

return response.create_response(
serialized_job_data.data, status.HTTP_200_OK
Expand Down Expand Up @@ -129,7 +133,6 @@ def details(self, request, *args, **kwargs):
)
return response.create_response(serialized_job_data.data, status.HTTP_200_OK)


@staticmethod
def get_number_of_applicants(serialized_data):
"""
Expand All @@ -153,7 +156,7 @@ def get_number_of_applicants(serialized_data):
jobdata.update({"Number of Applicants": number_of_applicants})

return serialized_data

@staticmethod
def get_active_jobs_count(serialized_company_data):
"""
Expand All @@ -162,10 +165,12 @@ def get_active_jobs_count(serialized_company_data):
"""

for company in serialized_company_data.data:
jobs_belong_to_company = Job.objects.filter(company_id=company.get("company_id"))
active_jobs = sum(1 for job in jobs_belong_to_company if job.is_active)
company.update({"Active Jobs": active_jobs})

jobs_belong_to_company = Job.objects.filter(
company_id=company.get("company_id")
)
active_jobs = sum(1 for job in jobs_belong_to_company if job.is_active)
company.update({"Active Jobs": active_jobs})

return serialized_company_data

@action(detail=True, methods=["get"])
Expand Down Expand Up @@ -319,38 +324,38 @@ def featured_jobs(self, request):
"""

# past 3 weeks datetime specified for featured jobs (can be modified as per use)
past_3_weeks_datetime = datetime_safe.datetime.now(tz=timezone.utc) - timedelta(days=18)
past_3_weeks_datetime = datetime_safe.datetime.now(tz=timezone.utc) - timedelta(
days=18
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please put it constants

)

# get the jobs_data and sort it in DESC order
# `-` with column name indicates to return the result in DESC order
try:
jobs_data = Job.objects.filter(
created_at__gt=past_3_weeks_datetime,
is_active=True
created_at__gt=past_3_weeks_datetime, is_active=True
).order_by("-created_at")

jobs_posted_within_3_weeks = JobSerializer(jobs_data, many=True)

# find out how many jobs were posted within past_3_weeks
jobs_posted_within_3_weeks = JobViewSets.get_number_of_applicants(jobs_posted_within_3_weeks)
jobs_posted_within_3_weeks = JobViewSets.get_number_of_applicants(
jobs_posted_within_3_weeks
)

# find 5 jobs with maximum number of applicants
featured_jobs = sorted(
jobs_posted_within_3_weeks.data,
key=lambda k: (k.get('Number of Applicants')),
reverse=True
key=lambda k: (k.get("Number of Applicants")),
reverse=True,
)

return response.create_response(
featured_jobs[0:5],
status.HTTP_200_OK
)
return response.create_response(featured_jobs[0:5], status.HTTP_200_OK)
except Exception:
return response.create_response(
response.SOMETHING_WENT_WRONG,
status.HTTP_500_INTERNAL_SERVER_ERROR
response.SOMETHING_WENT_WRONG, status.HTTP_500_INTERNAL_SERVER_ERROR
)


class UserViewSets(viewsets.ModelViewSet):
"""
User object viewsets
Expand Down Expand Up @@ -498,16 +503,16 @@ def update(self, request, *args, **kwargs):
UserSerializer(user_data).data, status.HTTP_200_OK
)

@action(detail=False, methods=['get'])
@action(detail=False, methods=["get"])
def get_profile_details(self, request):
"""
API: /api/v1/user/myProfile
Returns user profile data in the response.
Returns user profile data in the response.
This method gets the user_id from "access-token".
"""

# Get the value from Access-Token header
if access_token:=request.headers.get(response.ACCESS_TOKEN, None):
if access_token := request.headers.get(response.ACCESS_TOKEN, None):
try:
# decode JWT Token; for any issues with it, raise an exception
decoded_user_access_token = jwt.decode(
Expand All @@ -516,29 +521,25 @@ def get_profile_details(self, request):
user_id = decoded_user_access_token.get(values.USER_ID, None)
if not user_id:
raise Exception

# get user data
user_data = self.queryset.filter(user_id=user_id)
if user_data:
serialized_user_data = self.serializer_class(user_data, many=True)
return response.create_response(
serialized_user_data.data,
status.HTTP_200_OK
serialized_user_data.data, status.HTTP_200_OK
)
else:
return response.create_response(
response.USER_DATA_NOT_PRESENT,
status.HTTP_404_NOT_FOUND
response.USER_DATA_NOT_PRESENT, status.HTTP_404_NOT_FOUND
)
except Exception:
return response.create_response(
response.ACCESS_TOKEN_NOT_VALID,
status.HTTP_400_BAD_REQUEST
response.ACCESS_TOKEN_NOT_VALID, status.HTTP_400_BAD_REQUEST
)
else:
return response.create_response(
response.ACCESS_TOKEN_NOT_PRESENT,
status.HTTP_401_UNAUTHORIZED
response.ACCESS_TOKEN_NOT_PRESENT, status.HTTP_401_UNAUTHORIZED
)

@action(detail=True, methods=["get"])
Expand Down Expand Up @@ -597,6 +598,104 @@ def get_application_status(self, serialized_data):

return serialized_data

@action(detail=True, methods=["put"])
def reupload_documents(self, request, pk=None):
"""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request: Base Api/user/be9ccc8b-d8c9-42f7-b776-dfef4649f39f/reupload_documents/
response: {
        "user_id": "be9ccc8b-d8c9-42f7-b776-dfef4649f39f",
        "name": "Devid gutta",
        "about": null,
        "resume": "http://127.0.0.1:3000/media/resume/resume_t9X71uc.pdf",
       "profile_picture":"http://127.0.0.1:3000/media/profile_picture/profile.pdf",
        "cover_letter": "http://127.0.0.1:3000/media/cover_letter/CV.pdf",
        "user_type": "Job Seeker",
        "experience": "0",
        "qualification": null,
        ...

API: /api/v1/user/{pk}/reupload-documents
Allows users to re-upload their documents (resume, profile picture, cover letter).
"""
user = User.objects.get(user_id=pk)
if not user:
return response.create_response(
"User does not exist", status.HTTP_404_NOT_FOUND
)

# Resume re-upload
resume_data = request.FILES.get("resume")
if resume_data:
user.resume = resume_data
user.save()

# Profile Picture re-upload
profile_picture_data = request.FILES.get("profile_picture")
if profile_picture_data:
user.profile_picture = profile_picture_data
user.save()

# Cover Letter re-upload
cover_letter_data = request.FILES.get("cover_letter")
if cover_letter_data:
user.cover_letter = cover_letter_data
user.save()

return response.create_response(
"Documents re-uploaded successfully", status.HTTP_200_OK
)

@action(detail=True, methods=["get"])
def download_documents(self, request, pk=None):
"""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request:Base Api/user/be9ccc8b-d8c9-42f7-b776-dfef4649f39f/download_documents?document_type=cover_letter
response: New page will appear which gives option to save as pdf into local system.

API: /api/v1/user/{pk}/download-documents
Allows users to download their documents (resume, profile picture, cover letter).
"""
user = User.objects.get(user_id=pk)
if not user:
return response.create_response(
"User does not exist", status.HTTP_404_NOT_FOUND
)

document_type = request.query_params.get("document_type", "")
file_path = None

# Determine the file path based on the requested document type
if document_type == "resume":
file_path = user.resume.path
elif document_type == "profile_picture":
file_path = user.profile_picture.path
elif document_type == "cover_letter":
file_path = user.cover_letter.path

if not file_path or not os.path.exists(file_path):
return response.create_response(
f"{document_type.capitalize()} not found", status.HTTP_404_NOT_FOUND
)

# Serve the file using Django FileResponse
return FileResponse(open(file_path, "rb"), as_attachment=True)

@action(detail=True, methods=["delete"])
def remove_documents(self, request, pk=None):
"""
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

request: Base Api/user/be9ccc8b-d8c9-42f7-b776-dfef4649f39f/remove_documents/?document_type=resume
response: {
    "user_id": "be9ccc8b-d8c9-42f7-b776-dfef4649f39f",
    "name": "Devid gutta",
    "about": null,
    "resume": null,
    "profile_picture": "http://127.0.0.1:3000/media/profile_picture/profile.pdf.pdf",
    "cover_letter": "http://127.0.0.1:3000/media/cover_letter/cv.pdf",
    "user_type": "Job Seeker",
    "experience": "0",
    "qualification": null,
    ...

API: /api/v1/user/{pk}/remove-documents
Allows users to remove their documents (resume, profile picture, cover letter).
"""
user = User.objects.get(user_id=pk)
if not user:
return response.create_response(
"User does not exist", status.HTTP_404_NOT_FOUND
)

document_type = request.query_params.get("document_type", "")
if not document_type:
return response.create_response(
"Please provide a valid document_type query parameter",
status.HTTP_400_BAD_REQUEST,
)

# Remove the document based on the requested document type
if document_type == "resume":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep this value in constants

user.resume = None
elif document_type == "profile_picture":
user.profile_picture = None
elif document_type == "cover_letter":
user.cover_letter = None

user.save()

return response.create_response(
f"{document_type.capitalize()} removed successfully", status.HTTP_200_OK
)


class CompanyViewSets(viewsets.ModelViewSet):
"""
Expand All @@ -619,7 +718,7 @@ class CompanyViewSets(viewsets.ModelViewSet):

def list(self, request):
"""
Method to return a list of companies available,
Method to return a list of companies available,
Along with the count of active jobs present in the company
"""

Expand All @@ -630,17 +729,18 @@ def list(self, request):

# get number of applicants
if serialized_company_data:
serialized_company_data = JobViewSets.get_active_jobs_count(serialized_company_data)
serialized_company_data = JobViewSets.get_active_jobs_count(
serialized_company_data
)

return response.create_response(
serialized_company_data.data, status.HTTP_200_OK
)
except Exception:
return response.create_response(
response.SOMETHING_WENT_WRONG,
status.HTTP_500_INTERNAL_SERVER_ERROR
response.SOMETHING_WENT_WRONG, status.HTTP_500_INTERNAL_SERVER_ERROR
)

def retrieve(self, request, pk=None):
"""
retrieve the data of given company id
Expand All @@ -657,12 +757,15 @@ def retrieve(self, request, pk=None):
company_data = Company.objects.filter(company_id=pk)
serialized_company_data = self.serializer_class(company_data, many=True)
if serialized_company_data:
serialized_company_data = JobViewSets.get_active_jobs_count(serialized_company_data)
return response.create_response(serialized_company_data.data, status.HTTP_200_OK)
serialized_company_data = JobViewSets.get_active_jobs_count(
serialized_company_data
)
return response.create_response(
serialized_company_data.data, status.HTTP_200_OK
)
except Exception:
return response.create_response(
response.SOMETHING_WENT_WRONG,
status.HTTP_500_INTERNAL_SERVER_ERROR
response.SOMETHING_WENT_WRONG, status.HTTP_500_INTERNAL_SERVER_ERROR
)

@action(detail=False, methods=["get"])
Expand Down Expand Up @@ -751,4 +854,4 @@ def list(self, request, *args, **kwargs):
else:
return super().list(request, *args, **kwargs)
else:
return super().list(request, *args, **kwargs)
return super().list(request, *args, **kwargs)
4 changes: 3 additions & 1 deletion null_jobs_backend/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"rest_framework",
"rest_framework.authtoken",
"rest_framework_simplejwt",
'rest_framework_simplejwt.token_blacklist', # used to blacklist the refresh token
"rest_framework_simplejwt.token_blacklist", # used to blacklist the refresh token
"drf_yasg",
"apps.accounts",
"apps.jobs",
Expand Down Expand Up @@ -228,3 +228,5 @@

# GOOGLE AUTH
SITE_ID = 2
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
5 changes: 5 additions & 0 deletions null_jobs_backend/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
from django.conf import settings
from django.conf.urls.static import static

schema_view = get_schema_view(
openapi.Info(
Expand All @@ -43,3 +45,6 @@
"api/redoc/", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"
),
]

if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)