cdc-placement-website-backend/CDC_Backend/APIs/utils.py

591 lines
24 KiB
Python
Raw Permalink Normal View History

2021-12-17 17:15:56 +05:30
import datetime
2022-05-02 17:16:56 +05:30
import json
2021-10-15 20:47:23 +05:30
import logging
import os
import random
2021-12-16 23:05:04 +05:30
import re
2021-10-15 20:47:23 +05:30
import string
import sys
import traceback
2021-10-15 20:47:23 +05:30
from os import path, remove
2022-05-02 17:16:56 +05:30
import background_task
2021-12-17 19:23:32 +05:30
import jwt
2022-05-02 17:16:56 +05:30
import pdfkit
import pytz
2022-05-02 17:16:56 +05:30
import requests as rq
2021-10-15 20:47:23 +05:30
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.forms.models import model_to_dict
2021-10-15 20:47:23 +05:30
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.utils import timezone
2021-10-15 20:47:23 +05:30
from google.auth.transport import requests
from google.oauth2 import id_token
from rest_framework import status
from rest_framework.response import Response
from .constants import *
from .models import User, PrePlacementOffer, PlacementApplication, Placement, Student, Internship,InternshipApplication
2021-10-15 20:47:23 +05:30
logger = logging.getLogger('db')
def get_token():
def decorator(view_func):
def wrapper_func(request, *args, **kwargs):
try:
authcode = request.data[AUTH_CODE]
data = {
'code': authcode,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'redirect_uri': REDIRECT_URI,
'grant_type': 'authorization_code'
}
r = rq.post(OAUTH2_API_ENDPOINT, data=data)
if r.status_code == 200:
response = r.json()
token = response[ID_TOKEN]
refresh_token = response[REFRESH_TOKEN]
request.META["HTTP_AUTHORIZATION"] = "Bearer " + token
request.META["MODIFIED"] = "True"
kwargs['refresh_token'] = refresh_token
return view_func(request, *args, **kwargs)
else:
return Response({'action': "Get Token", 'message': "Invalid Auth Code"},
status=status.HTTP_400_BAD_REQUEST)
except Exception as e:
logger.warning("Get Token: " + str(sys.exc_info()))
return Response({'action': "Get Token", 'message': str(e)},
status=status.HTTP_400_BAD_REQUEST)
2023-07-29 17:39:34 +05:30
return wrapper_func
2023-07-29 17:39:34 +05:30
return decorator
2021-10-15 20:47:23 +05:30
def precheck(required_data=None):
if required_data is None:
required_data = []
def decorator(view_func):
def wrapper_func(request, *args, **kwargs):
try:
request_data = None
if request.method == 'GET':
request_data = request.GET
elif request.method == 'POST':
request_data = request.data
if not len(request_data):
request_data = request.POST
if len(request_data):
for i in required_data:
2023-07-25 00:34:39 +05:30
# print(i)
2021-10-15 20:47:23 +05:30
if i not in request_data:
return Response({'action': "Pre check", 'message': str(i) + " Not Found"},
status=status.HTTP_400_BAD_REQUEST)
else:
return Response({'action': "Pre check", 'message': "Message Data not Found"},
status=status.HTTP_400_BAD_REQUEST)
2023-07-25 00:34:39 +05:30
# print("Pre check: " + str(request_data))
2021-10-15 20:47:23 +05:30
return view_func(request, *args, **kwargs)
except:
2023-07-25 00:34:39 +05:30
# print what exception is
print(traceback.format_exc())
logger.warning("Pre check: " + str(sys.exc_info()))
2021-12-12 20:13:47 +05:30
return Response({'action': "Pre check", 'message': "Something went wrong"},
2021-10-15 20:47:23 +05:30
status=status.HTTP_400_BAD_REQUEST)
return wrapper_func
return decorator
def isAuthorized(allowed_users=None):
if allowed_users is None:
allowed_users = []
def decorator(view_func):
def wrapper_func(request, *args, **kwargs):
try:
headers = request.META
if 'HTTP_AUTHORIZATION' in headers:
token_id = headers['HTTP_AUTHORIZATION'][7:]
idinfo = id_token.verify_oauth2_token(token_id, requests.Request(), CLIENT_ID)
email = idinfo[EMAIL]
user = get_object_or_404(User, email=email)
if user:
user.last_login_time = timezone.now()
2022-05-02 17:16:56 +05:30
user.save()
2021-10-15 20:47:23 +05:30
if len(set(user.user_type).intersection(set(allowed_users))) or allowed_users == '*':
if "MODIFIED" in headers:
2023-07-29 17:39:34 +05:30
return view_func(request, user.id, user.email, user.user_type, token_id, *args,
**kwargs)
else:
return view_func(request, user.id, user.email, user.user_type, *args, **kwargs)
2021-10-15 20:47:23 +05:30
else:
raise PermissionError("Access Denied. You are not allowed to use this service")
else:
raise PermissionError("Authorization Header Not Found")
2021-12-12 20:13:47 +05:30
except PermissionError:
return Response({'action': "Is Authorized?", 'message': 'Access Denied'},
2021-10-15 20:47:23 +05:30
status=status.HTTP_401_UNAUTHORIZED)
except Http404:
return Response({'action': "Is Authorized?", 'message': "User Not Found. Contact CDC for more details"},
status=status.HTTP_404_NOT_FOUND)
except ValueError as e:
2021-12-12 20:13:47 +05:30
logger.error("Problem with Google Oauth2.0 " + str(e))
return Response({'action': "Is Authorized?", 'message': 'Problem with Google Sign In'},
2021-10-15 20:47:23 +05:30
status=status.HTTP_401_UNAUTHORIZED)
except:
logger.warning("Is Authorized? " + str(sys.exc_info()))
return Response(
{'action': "Is Authorized?", 'message': "Something went wrong. Contact CDC for more details"},
status=status.HTTP_400_BAD_REQUEST)
2021-10-15 20:47:23 +05:30
return wrapper_func
return decorator
def isAuthorizedService():
def decorator(view_func):
def wrapper_func(request, *args, **kwargs):
try:
headers = request.META
if 'HTTP_AUTHORIZATION' in headers:
token_id = headers['HTTP_AUTHORIZATION'][7:]
2023-10-19 06:51:47 +05:30
jwt.decode(token_id, os.environ.get("JWT_SECRET_KEY"), algorithms="HS256")
return view_func(request, *args, **kwargs)
else:
raise PermissionError("Authorization Header Not Found")
except:
logger.warning("Is Authorized? " + str(sys.exc_info()))
return Response(
{'action': "Is Authorized?", 'message': "Something went wrong. Contact CDC for more details"},
status=status.HTTP_400_BAD_REQUEST)
return wrapper_func
return decorator
2021-10-15 20:47:23 +05:30
def generateRandomString():
try:
N = 15
2021-12-17 17:15:56 +05:30
res = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=N))
2021-10-15 20:47:23 +05:30
return res
except:
return False
def saveFile(file, location):
prefix = generateRandomString()
file_name = prefix + "_" + file.name.strip()
2021-10-15 20:47:23 +05:30
2021-12-16 23:05:04 +05:30
file_name = re.sub(r'[\\/:*?"<>|]', '_', file_name)
2021-10-15 20:47:23 +05:30
if not path.isdir(location):
2021-12-16 23:05:04 +05:30
os.makedirs(location)
2021-10-15 20:47:23 +05:30
destination_path = location + str(file_name)
2021-10-15 20:47:23 +05:30
if path.exists(destination_path):
remove(destination_path)
with open(destination_path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
return file_name
2022-07-28 18:01:55 +05:30
@background_task.background(schedule=2)
def sendEmail(email_to, subject, data, template, attachment_jnf_response=None):
2021-10-15 20:47:23 +05:30
try:
if not isinstance(data, dict):
data = json.loads(data)
2021-10-15 20:47:23 +05:30
html_content = render_to_string(template, data) # render with dynamic value
text_content = strip_tags(html_content)
email_from = settings.EMAIL_HOST_USER
if type(email_to) is list:
recipient_list = [str(email) for email in email_to]
else:
recipient_list = [str(email_to), ]
2021-10-15 20:47:23 +05:30
2023-10-27 15:54:17 +05:30
#batch 100 ppl to send as bcc
for i in range(0,len(recipient_list),100):
msg = EmailMultiAlternatives(subject, text_content, email_from,None,bcc=recipient_list[i:i+100])
msg.attach_alternative(html_content, "text/html")
if attachment_jnf_response:
# logger.info(attachment_jnf_response)
pdf = pdfkit.from_string(attachment_jnf_response['html'], False,
options={"--enable-local-file-access": "", '--dpi': '96'})
msg.attach(attachment_jnf_response['name'], pdf, 'application/pdf')
msg.send()
2021-10-15 20:47:23 +05:30
return True
except:
logger.error("Send Email: " + str(sys.exc_info()))
return False
2021-10-15 20:47:23 +05:30
def PlacementApplicationConditions(student, placement):
try:
selected_companies = PlacementApplication.objects.filter(student=student, selected=True)
selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu']
PPO = PrePlacementOffer.objects.filter(student=student, accepted=True)
2022-12-06 16:16:56 +05:30
PPO_PSU = [i for i in PPO if i.tier == 'psu']
2022-07-28 18:01:55 +05:30
# find length of PPO
if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT:
2021-10-15 20:47:23 +05:30
raise PermissionError("Max Applications Reached for the Season")
if len(selected_companies_PSU) > 0:
raise PermissionError('Selected for PSU Can\'t apply anymore')
2022-12-06 16:16:56 +05:30
if len(PPO_PSU) > 0:
raise PermissionError('Selected for PSU Can\'t apply anymore')
2021-10-15 20:47:23 +05:30
if placement.tier == 'psu':
return True, "Conditions Satisfied"
for i in selected_companies:
if int(i.placement.tier) < int(placement.tier):
2022-10-08 13:20:41 +05:30
return False, "Can't apply for this tier"
for i in PPO:
2022-12-06 16:16:56 +05:30
if int(i.tier) < int(placement.tier):
2021-10-15 20:47:23 +05:30
return False, "Can't apply for this tier"
if student.degree != 'bTech' and not placement.rs_eligible:
raise PermissionError("Can't apply for this placement")
2021-10-15 20:47:23 +05:30
return True, "Conditions Satisfied"
except PermissionError as e:
return False, e
except:
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
return False, "_"
def InternshipApplicationConditions(student, internship):
try:
selected_companies = InternshipApplication.objects.filter(student=student, selected=True)
if len(selected_companies)>=1:
2023-10-03 19:14:10 +05:30
# print("selected companies > 1")
return False, "You have already secured a Internship"
return True, "Conditions Satisfied"
except PermissionError as e:
return False, e
except:
logger.warning("Utils - InternshipApplicationConditions: " + str(sys.exc_info()))
return False, "_"
def getTier(compensation_gross, is_psu=False):
try:
if is_psu:
return True, 'psu'
if compensation_gross < 0:
raise ValueError("Negative Compensation")
2023-09-09 01:19:17 +05:30
elif compensation_gross < 450000: # Open Tier If less than 450,000
return True, "8"
elif compensation_gross < 600000: # Tier 7 If less than 600,000
return True, "7"
# Tier 6 If less than 800,000 and greater than or equal to 600,000
elif compensation_gross < 800000:
return True, "6"
# Tier 5 If less than 1,000,000 and greater than or equal to 800,000
elif compensation_gross < 1000000:
return True, "5"
# Tier 4 If less than 1,200,000 and greater than or equal to 1,000,000
elif compensation_gross < 1200000:
return True, "4"
# Tier 3 If less than 1,500,000 and greater than or equal to 1,200,000
elif compensation_gross < 1500000:
return True, "3"
# Tier 2 If less than 1,800,000 and greater than or equal to 1,500,000
elif compensation_gross < 1800000:
return True, "2"
# Tier 1 If greater than or equal to 1,800,000
elif compensation_gross >= 1800000:
return True, "1"
else:
raise ValueError("Invalid Compensation")
except ValueError as e:
logger.warning("Utils - getTier: " + str(sys.exc_info()))
return False, e
except:
logger.warning("Utils - getTier: " + str(sys.exc_info()))
return False, "_"
2021-12-17 17:15:56 +05:30
def generateOneTimeVerificationLink(email, opening_id, opening_type):
try:
token_payload = {
"email": email,
"opening_id": opening_id,
"opening_type": opening_type,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=EMAIL_VERIFICATION_TOKEN_TTL)
}
token = jwt.encode(token_payload, os.environ.get("EMAIL_VERIFICATION_SECRET_KEY"), algorithm="HS256")
link = LINK_TO_EMAIl_VERIFICATION_API.format(token=token)
return True, link
except:
logger.warning("Utils - generateOneTimeVerificationLink: " + str(sys.exc_info()))
return False, "_"
2022-04-10 23:12:02 +05:30
2022-05-02 17:16:56 +05:30
2022-04-10 23:12:02 +05:30
def verify_recaptcha(request):
try:
data = {
'secret': settings.RECAPTCHA_SECRET_KEY,
'response': request
}
r = rq.post('https://www.google.com/recaptcha/api/siteverify', data=data)
result = r.json()
if not result['success']:
logger.warning("Utils - verify_recaptcha: " + str(result))
2022-04-10 23:12:02 +05:30
return result['success']
except:
# get exception line number
2022-04-10 23:12:02 +05:30
logger.warning("Utils - verify_recaptcha: " + str(sys.exc_info()))
return False, "_"
2022-05-02 17:16:56 +05:30
def opening_description_table_html(opening):
# check typing of opening
2023-07-25 12:36:59 +05:30
type = ""
if isinstance(opening, Placement):
2023-07-25 12:36:59 +05:30
type = "Job"
details = model_to_dict(opening, fields=[field.name for field in Placement._meta.fields],
exclude=EXCLUDE_IN_PDF)
2023-07-25 00:34:39 +05:30
elif isinstance(opening, Internship):
2023-07-25 12:36:59 +05:30
type = "Internship"
2023-07-25 00:34:39 +05:30
details = model_to_dict(opening, fields=[field.name for field in Internship._meta.fields],
exclude=EXCLUDE_IN_PDF)
# check typing of opening is query dict
else: # if isinstance(opening, QueryDict):
details = opening
keys = list(details.keys())
2023-06-06 16:59:12 +05:30
newdetails = {"ID": opening.id}
for key in keys:
if isinstance(details[key], list):
details[key] = {"details": details[key], "type": ["list"]}
if key in SPECIAL_FORMAT_IN_PDF:
if key == 'website':
details[key] = {"details": details[key], "type": ["link"]}
else:
details[key] = {"details": [item for item in details[key]["details"]], "type": ["list", "link"],
2022-05-02 17:16:56 +05:30
"link": PDF_FILES_SERVING_ENDPOINT + opening.id + "/"}
new_key = key.replace('_', ' ')
if new_key.endswith(' names'):
new_key = new_key[:-6]
new_key = new_key.capitalize()
newdetails[new_key] = details[key]
imagepath = os.path.abspath('./templates/image.png')
data = {
2022-05-02 17:16:56 +05:30
"data": newdetails,
2023-07-25 12:36:59 +05:30
"imgpath": imagepath,
"type": type
}
2022-05-02 17:16:56 +05:30
return render_to_string(COMPANY_JNF_RESPONSE_TEMPLATE, data)
2022-07-28 18:01:55 +05:30
def placement_eligibility_filters(student, placements):
try:
filtered_placements = []
for placement in placements.iterator():
if PlacementApplicationConditions(student, placement)[0]:
filtered_placements.append(placement)
return filtered_placements
except:
logger.warning("Utils - placement_eligibility_filters: " + str(sys.exc_info()))
return placements
def internship_eligibility_filters(student, internships):
try:
filtered_internships = []
for internship in internships.iterator():
if InternshipApplicationConditions(student, internship)[0]:
filtered_internships.append(internship)
return filtered_internships
except:
logger.warning("Utils - internship_eligibility_filters: " + str(sys.exc_info()))
return internships
2022-07-28 18:01:55 +05:30
@background_task.background(schedule=2)
2023-10-03 10:14:03 +05:30
def send_opening_notifications(opening_id, opening_type=PLACEMENT):
2022-07-28 18:01:55 +05:30
try:
2023-10-03 10:14:03 +05:30
# print(opening_id, opening_type)
2023-10-03 02:16:33 +05:30
if opening_type == PLACEMENT:
opening = get_object_or_404(Placement, id=opening_id)
else:
opening = get_object_or_404(Internship, id=opening_id)
emails=[]
2022-07-28 18:01:55 +05:30
students = Student.objects.all()
for student in students.iterator():
2023-10-03 02:16:33 +05:30
if student.branch in opening.allowed_branch:
if student.degree == 'bTech' or opening.rs_eligible is True:
if (isinstance(opening,Placement) and PlacementApplicationConditions(student, opening)[0]) or (isinstance(opening,Internship) and InternshipApplicationConditions(student, opening)[0]):
try:
student_user = get_object_or_404(User, id=student.id)
emails.append(student_user.email)
#sendEmail(student_user.email, subject, data, NOTIFY_STUDENTS_OPENING_TEMPLATE)
except Http404:
logger.warning('Utils - send_opening_notifications: user not found : ' + student.id)
except Exception as e:
logger.warning('Utils - send_opening_notifications: For Loop' + str(e))
2023-10-03 19:14:10 +05:30
subject = NOTIFY_STUDENTS_OPENING_TEMPLATE_SUBJECT.format(
company_name=opening.company_name)
deadline_datetime = opening.deadline_datetime.astimezone(pytz.timezone('Asia/Kolkata'))
data = {
"company_name": opening.company_name,
"opening_type": "INTERNSHIP" if isinstance(opening, Internship) else "PLACEMENT",
"designation": opening.designation,
"deadline": deadline_datetime.strftime("%A, %-d %B %Y, %-I:%M %p"),
"link": PLACEMENT_OPENING_URL.format(id=opening.designation) if opening_type == PLACEMENT else INTERNSHIP_OPENING_URL.format(id=opening.designation),
}
sendEmail(emails, subject, data, NOTIFY_STUDENTS_OPENING_TEMPLATE) #handled multiple mailings
2022-07-28 18:01:55 +05:30
except:
logger.warning('Utils - send_opening_notifications: ' + str(sys.exc_info()))
return False
def get_eligible_emails(opening_id, opening_type=PLACEMENT,send_all=False):
try:
# print(opening_id, opening_type)
if opening_type == PLACEMENT:
opening = get_object_or_404(Placement, id=opening_id)
else:
opening = get_object_or_404(Internship, id=opening_id)
emails=[]
students = Student.objects.all()
for student in students.iterator():
if student.branch in opening.allowed_branch:
if student.degree == 'bTech' or opening.rs_eligible is True:
if (isinstance(opening,Placement) and PlacementApplicationConditions(student, opening)[0]) or (
isinstance(opening,Internship) and InternshipApplicationConditions(student, opening)[0]):
try:
student_user = get_object_or_404(User, id=student.id)
#if send_all True send all students eligible for the opening
if send_all:
emails.append(student_user.email)
continue
# check if he applied
if opening_type == PLACEMENT:
if PlacementApplication.objects.filter(student=student, placement=opening).exists():
continue
else:
if InternshipApplication.objects.filter(student=student, internship=opening).exists():
continue
emails.append(student_user.email)
except Exception as e:
logger.warning('Utils - send_opening_notifications: For Loop' + str(e))
2023-10-20 19:33:13 +05:30
return False, []
return True, emails
except:
logger.warning('Utils - send_opening_notifications: ' + str(sys.exc_info()))
2023-10-20 19:33:13 +05:30
return False, []
def exception_email(opening):
opening = opening.dict()
data = {
"designation": opening["designation"],
2023-10-03 02:16:33 +05:30
"opening_type": "INTERNSHIP" if opening["opening_type"] == "INF" else "PLACEMENT",
"company_name": opening["company_name"],
}
pdfhtml = opening_description_table_html(opening)
name = opening["company_name"] + '_jnf_response.pdf' if opening[OPENING_TYPE]!="INF" else opening["company_name"] + '_inf_response.pdf'
attachment_jnf_respone = {
"name": name,
"html": pdfhtml,
}
2023-08-05 02:10:41 +05:30
sendEmail("cdc@iitdh.ac.in", COMPANY_OPENING_ERROR_TEMPLATE.format(company_name=opening["company_name"]), data,
COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone)
def store_all_files(request):
files = request.FILES
data = request.data
# save all the files
if files:
# company details pdf
for file in files.getlist(COMPANY_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
# compensation details pdf
for file in files.getlist(COMPENSATION_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
#stipend details pdf for internships
for file in files.getlist(STIPEND_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
# selection procedure details pdf
for file in files.getlist(SELECTION_PROCEDURE_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
# description pdf
for file in files.getlist(DESCRIPTION_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
2023-07-29 17:39:34 +05:30
def send_email_for_opening(opening):
try:
# Prepare email data and attachment
pdfhtml = opening_description_table_html(opening)
2023-08-05 02:10:41 +05:30
if isinstance(opening, Placement):
name = opening.company_name + '_jnf_response.pdf'
elif isinstance(opening, Internship):
name = opening.company_name + '_inf_response.pdf'
2023-07-29 17:39:34 +05:30
attachment_jnf_respone = {
"name": name,
"html": pdfhtml,
}
data = {
"designation": opening.designation,
"opening_type": "INTERNSHIP" if isinstance(opening, Internship) else "PLACEMENT",
"company_name": opening.company_name,
}
2023-08-05 02:10:41 +05:30
emails = [opening.email] + CDC_REPS_EMAILS
2023-07-29 17:39:34 +05:30
# Send the email
2023-08-01 22:39:06 +05:30
sendEmail(emails,
COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.designation, company=opening.company_name), data,
2023-07-29 17:39:34 +05:30
COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone)
except Exception as e:
# Handle the exception here (e.g., log the error, send an error email, etc.)
print("An error occurred while sending the email:", e)
@background_task.background(schedule=2)
def send_opening_to_notifications_service(id,name,deadline,role,opening_type=PLACEMENT):
data={
"id":id,
"company":name,
"deadline":deadline,
"role":role,
"opening_type":opening_type
}
encoded=jwt.encode(data,os.environ.get("JWT_SECRET_KEY"),algorithm="HS256")
data_={
"token":encoded,
}
resp=rq.post(url=os.environ.get("PUSH_API_URL")+"addopening/",data=data_)
if resp.status_code==200:
print("Notification Sent")
else:
print("Notification Failed")
logger.warning("Utils - send_opening_to_notifications_service: " + str(resp) + "data sent:"+str(data))