Changes for Deadline changes and email sending

This commit is contained in:
gowtham 2022-04-30 22:27:49 +05:30
parent a4c9fa1d8e
commit 9881303969
9 changed files with 145 additions and 55 deletions

View File

@ -54,9 +54,9 @@ def markStatus(request, id, email, user_type):
def getDashboard(request, id, email, user_type): def getDashboard(request, id, email, user_type):
try: try:
placements = Placement.objects.all().order_by('-created_at') placements = Placement.objects.all().order_by('-created_at')
ongoing = placements.filter(deadline_datetime__gt=datetime.datetime.now(), offer_accepted__isnull=False) ongoing = placements.filter(deadline_datetime__gt=datetime.datetime.now(), offer_accepted=True)
previous = placements.exclude(deadline_datetime__gt=datetime.datetime.now()).filter( previous = placements.exclude(deadline_datetime__gt=datetime.datetime.now()).filter(
offer_accepted__isnull=False) offer_accepted=True)
new = placements.filter(offer_accepted__isnull=True) new = placements.filter(offer_accepted__isnull=True)
ongoing = PlacementSerializerForAdmin(ongoing, many=True).data ongoing = PlacementSerializerForAdmin(ongoing, many=True).data
previous = PlacementSerializerForAdmin(previous, many=True).data previous = PlacementSerializerForAdmin(previous, many=True).data
@ -102,8 +102,10 @@ def updateDeadline(request, id, email, user_type):
def updateOfferAccepted(request, id, email, user_type): def updateOfferAccepted(request, id, email, user_type):
try: try:
data = request.data data = request.data
print(data)
opening = get_object_or_404(Placement, pk=data[OPENING_ID]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
opening.offer_accepted = True if data[OFFER_ACCEPTED] == "true" else False opening.offer_accepted = True if data[OFFER_ACCEPTED] == True else False
print(opening.offer_accepted)
opening.save() opening.save()
return Response({'action': "Update Offer Accepted", 'message': "Offer Accepted Updated"}, return Response({'action': "Update Offer Accepted", 'message': "Offer Accepted Updated"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)

View File

@ -1,6 +1,5 @@
import json
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from django.forms.models import model_to_dict
from .models import * from .models import *
from .utils import * from .utils import *
@ -231,6 +230,7 @@ def addPlacement(request):
def verifyEmail(request): def verifyEmail(request):
try: try:
data = request.data data = request.data
send_email_to_company = None
token = data[TOKEN] token = data[TOKEN]
# decode token # decode token
decoded_token = jwt.decode(token, os.environ.get("EMAIL_VERIFICATION_SECRET_KEY"), algorithms=['HS256']) decoded_token = jwt.decode(token, os.environ.get("EMAIL_VERIFICATION_SECRET_KEY"), algorithms=['HS256'])
@ -243,18 +243,48 @@ def verifyEmail(request):
opening = get_object_or_404(Placement, id=opening_id) opening = get_object_or_404(Placement, id=opening_id)
if email != opening.email: if email != opening.email:
raise ValueError("Invalid Email") raise ValueError("Invalid Email")
if not opening.email_verified:
opening.email_verified = True opening.email_verified = True
send_email_to_company = True
else:
send_email_to_company = False
opening.save() opening.save()
else:
raise ValueError('Invalid opening type')
if send_email_to_company:
# Email sending part.
details = model_to_dict(opening, fields=[field.name for field in Placement._meta.fields],
exclude=['id', 'is_company_details_pdf', 'offer_accepted', 'is_description_pdf',
'is_compensation_details_pdf', 'is_selection_procedure_details_pdf',
'email_verified'])
keys = list(details.keys())
newdetails = {}
for key in keys:
if isinstance(details[key], list):
details[key] = {"details": details[key], "type": ["list"]}
if key in ['website', 'company_details_pdf_names', 'description_pdf_names',
'compensation_details_pdf_names', 'selection_procedure_pdf_names']:
if key == 'website':
details[key] = {"details": details[key], "type": ["link"]}
else:
details[key] = {"details": details[key]["details"], "type": ["list", "link"],
"link": LINK_TO_STORAGE_COMPANY_ATTACHMENT + opening.id + "/"}
new_key = key.replace('_', ' ')
if key == 'company_details_pdf_names':
new_key = 'company details pdf'
newdetails[new_key] = details[key]
data = { data = {
"designation": opening.designation, "designation": opening.designation,
"opening_type": PLACEMENT, "opening_type": PLACEMENT,
"opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too "opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too
"company_name": opening.company_name "company_name": opening.company_name,
"data": newdetails
} }
sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data, json_data = json.dumps(data, default=str)
sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), json_data,
COMPANY_OPENING_SUBMITTED_TEMPLATE) COMPANY_OPENING_SUBMITTED_TEMPLATE)
else:
raise ValueError('Invalid opening type')
return Response({'action': "Verify Email", 'message': "Email Verified Successfully"}, return Response({'action': "Verify Email", 'message': "Email Verified Successfully"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404: except Http404:

View File

@ -43,7 +43,7 @@ PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}" # On fron
LINK_TO_STORAGE_COMPANY_ATTACHMENT = "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/" LINK_TO_STORAGE_COMPANY_ATTACHMENT = "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/"
LINK_TO_STORAGE_RESUME = "https://storage.googleapis.com/cdc-backend-attachments/resume/" LINK_TO_STORAGE_RESUME = "https://storage.googleapis.com/cdc-backend-attachments/resume/"
LINK_TO_APPLICATIONS_CSV = "https://storage.googleapis.com/cdc-backend-attachments/applications-csv/" LINK_TO_APPLICATIONS_CSV = "https://storage.googleapis.com/cdc-backend-attachments/applications-csv/"
LINK_TO_EMAIl_VERIFICATION_API = "https://api.sendgrid.com/v3/mail/send?token={token}" LINK_TO_EMAIl_VERIFICATION_API = "http://localhost:3000/company/verifyEmail?token={token}"
EMAIL = "email" EMAIL = "email"

View File

@ -34,13 +34,13 @@ class StudentSerializer(serializers.ModelSerializer):
model = Student model = Student
exclude = ['resumes'] exclude = ['resumes']
class PlacementSerializerForStudent(serializers.ModelSerializer): class PlacementSerializerForStudent(serializers.ModelSerializer):
company_details_pdf_links = serializers.SerializerMethodField() company_details_pdf_links = serializers.SerializerMethodField()
description_pdf_links = serializers.SerializerMethodField() description_pdf_links = serializers.SerializerMethodField()
compensation_pdf_links = serializers.SerializerMethodField() compensation_pdf_links = serializers.SerializerMethodField()
selection_procedure_details_pdf_links = serializers.SerializerMethodField() selection_procedure_details_pdf_links = serializers.SerializerMethodField()
def get_company_details_pdf_links(self, obj): def get_company_details_pdf_links(self, obj):
links = [] links = []
for pdf_name in obj.company_details_pdf_names: for pdf_name in obj.company_details_pdf_names:
@ -81,21 +81,21 @@ class PlacementSerializerForStudent(serializers.ModelSerializer):
links.append(ele) links.append(ele)
return links return links
class Meta: class Meta:
model = Placement model = Placement
exclude = [CONTACT_PERSON_NAME, PHONE_NUMBER, EMAIL, COMPANY_DETAILS_PDF_NAMES, DESCRIPTION_PDF_NAMES, exclude = [CONTACT_PERSON_NAME, PHONE_NUMBER, EMAIL, COMPANY_DETAILS_PDF_NAMES, DESCRIPTION_PDF_NAMES,
COMPENSATION_DETAILS_PDF_NAMES, SELECTION_PROCEDURE_DETAILS_PDF_NAMES, OFFER_ACCEPTED, EMAIL_VERIFIED] COMPENSATION_DETAILS_PDF_NAMES, SELECTION_PROCEDURE_DETAILS_PDF_NAMES, OFFER_ACCEPTED,
EMAIL_VERIFIED,
]
depth = 1 depth = 1
class PlacementSerializerForAdmin(serializers.ModelSerializer): class PlacementSerializerForAdmin(serializers.ModelSerializer):
company_details_pdf_links = serializers.SerializerMethodField() company_details_pdf_links = serializers.SerializerMethodField()
description_pdf_links = serializers.SerializerMethodField() description_pdf_links = serializers.SerializerMethodField()
compensation_pdf_links = serializers.SerializerMethodField() compensation_pdf_links = serializers.SerializerMethodField()
selection_procedure_details_pdf_links = serializers.SerializerMethodField() selection_procedure_details_pdf_links = serializers.SerializerMethodField()
def get_company_details_pdf_links(self, obj): def get_company_details_pdf_links(self, obj):
links = [] links = []
for pdf_name in obj.company_details_pdf_names: for pdf_name in obj.company_details_pdf_names:
@ -136,8 +136,6 @@ class PlacementSerializerForAdmin(serializers.ModelSerializer):
links.append(ele) links.append(ele)
return links return links
class Meta: class Meta:
model = Placement model = Placement
exclude = [COMPANY_DETAILS_PDF_NAMES, DESCRIPTION_PDF_NAMES, exclude = [COMPANY_DETAILS_PDF_NAMES, DESCRIPTION_PDF_NAMES,
@ -159,11 +157,11 @@ class PlacementApplicationSerializer(serializers.ModelSerializer):
ele['name'] = obj.resume ele['name'] = obj.resume
return ele return ele
class Meta: class Meta:
model = PlacementApplication model = PlacementApplication
exclude = [STUDENT, 'resume'] exclude = [STUDENT, 'resume']
class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer): class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer):
student_details = serializers.SerializerMethodField() student_details = serializers.SerializerMethodField()
resume_link = serializers.SerializerMethodField() resume_link = serializers.SerializerMethodField()

View File

@ -1,5 +1,7 @@
import json import json
from datetime import datetime # from datetime import datetime
import datetime
import traceback
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
@ -72,13 +74,11 @@ def getDashboard(request, id, email, user_type):
placements = Placement.objects.filter(allowed_batch__contains=[studentDetails.batch], placements = Placement.objects.filter(allowed_batch__contains=[studentDetails.batch],
allowed_branch__contains=[studentDetails.branch], allowed_branch__contains=[studentDetails.branch],
deadline_datetime__gte=datetime.now(), deadline_datetime__gte=datetime.datetime.now(),
offer_accepted=True, email_verified=True).order_by('deadline_datetime') offer_accepted=True, email_verified=True).order_by('deadline_datetime')
placementsdata = PlacementSerializerForStudent(placements, many=True).data placementsdata = PlacementSerializerForStudent(placements, many=True).data
placementApplications = PlacementApplication.objects.filter(student_id=id) placementApplications = PlacementApplication.objects.filter(student_id=id)
placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data
return Response( return Response(
{'action': "Get Dashboard - Student", 'message': "Data Found", "placements": placementsdata, {'action': "Get Dashboard - Student", 'message': "Data Found", "placements": placementsdata,
'placementApplication': placementApplications}, 'placementApplication': placementApplications},
@ -88,6 +88,8 @@ def getDashboard(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except: except:
logger.warning("Get Dashboard -Student: " + str(sys.exc_info())) logger.warning("Get Dashboard -Student: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"}, return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -140,7 +142,7 @@ def submitApplication(request, id, email, user_type):
opening = get_object_or_404(Placement, id=data[OPENING_ID], opening = get_object_or_404(Placement, id=data[OPENING_ID],
allowed_batch__contains=[student.batch], allowed_batch__contains=[student.batch],
allowed_branch__contains=[student.branch], allowed_branch__contains=[student.branch],
deadline_datetime__gte=datetime.now().date() deadline_datetime__gte=datetime.datetime.now().date()
) )
if not opening.offer_accepted or not opening.email_verified: if not opening.offer_accepted or not opening.email_verified:
raise PermissionError("Placement Not Approved") raise PermissionError("Placement Not Approved")
@ -192,5 +194,8 @@ def submitApplication(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except: except:
logger.warning("Submit Application: " + str(sys.exc_info())) logger.warning("Submit Application: " + str(sys.exc_info()))
print(traceback.format_exc())
print(sys.exc_info())
return Response({'action': "Submit Application", 'message': "Something Went Wrong"}, return Response({'action': "Submit Application", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)

View File

@ -5,8 +5,9 @@ import random
import re import re
import string import string
import sys import sys
import traceback
from os import path, remove from os import path, remove
import json
import background_task import background_task
import jwt import jwt
from django.conf import settings from django.conf import settings
@ -135,6 +136,8 @@ def saveFile(file, location):
@background_task.background(schedule=10) @background_task.background(schedule=10)
def sendEmail(email_to, subject, data, template): def sendEmail(email_to, subject, data, template):
try: try:
if not isinstance(data, dict):
data = json.loads(data)
html_content = render_to_string(template, data) # render with dynamic value html_content = render_to_string(template, data) # render with dynamic value
text_content = strip_tags(html_content) text_content = strip_tags(html_content)
@ -156,7 +159,9 @@ def PlacementApplicationConditions(student, placement):
selected_companies = PlacementApplication.objects.filter(student=student, selected=True) selected_companies = PlacementApplication.objects.filter(student=student, selected=True)
selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu'] selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu']
PPO = PrePlacementOffer.objects.filter(student=student, accepted=True) PPO = PrePlacementOffer.objects.filter(student=student, accepted=True)
# find lenght of PPO
print(PPO)
print(len(PPO), "ere")
if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT: if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT:
raise PermissionError("Max Applications Reached for the Season") raise PermissionError("Max Applications Reached for the Season")
@ -177,6 +182,8 @@ def PlacementApplicationConditions(student, placement):
return False, e return False, e
except: except:
print(sys.exc_info()) print(sys.exc_info())
print(traceback.format_exc())
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info())) logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
return False, "_" return False, "_"
@ -237,15 +244,21 @@ def generateOneTimeVerificationLink(email, opening_id, opening_type):
def verify_recaptcha(request): def verify_recaptcha(request):
try: try:
print(settings.RECAPTCHA_SECRET_KEY)
data = { data = {
'secret': settings.RECAPTCHA_SECRET_KEY, 'secret': settings.RECAPTCHA_SECRET_KEY,
'response': request 'response': request
} }
print(data)
r = rq.post('https://www.google.com/recaptcha/api/siteverify', data=data) r = rq.post('https://www.google.com/recaptcha/api/siteverify', data=data)
result = r.json() result = r.json()
# logger.info("Recaptcha Response: " + str(result)+"request: "+str(data)) # logger.info("Recaptcha Response: " + str(result)+"request: "+str(data))
print(result, "Result")
return result['success'] return result['success']
except: except:
# get exception line number
print(sys.exc_info()) print(sys.exc_info())
print(traceback.format_exc())
logger.warning("Utils - verify_recaptcha: " + str(sys.exc_info())) logger.warning("Utils - verify_recaptcha: " + str(sys.exc_info()))
return False, "_" return False, "_"

View File

@ -83,23 +83,23 @@ WSGI_APPLICATION = 'CDC_Backend.wsgi.application'
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = { DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
# 'NAME': os.environ.get("DB_NAME"),
# 'USER': os.environ.get("DB_USER"),
# 'PASSWORD': os.environ.get("DB_PASSWORD"),
# 'HOST': os.environ.get("DB_HOST"),
# 'PORT': os.environ.get("DB_PORT"),
# },
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'd84i5cbjig5rrf', 'NAME': os.environ.get("DB_NAME"),
'USER': 'hbkullcdjbxuwh', 'USER': os.environ.get("DB_USER"),
'PASSWORD': '45d990da00e2cc96d7d4e2e5e308d4b07a387883f70c40e090a6252175cb634e', 'PASSWORD': os.environ.get("DB_PASSWORD"),
'HOST': 'ec2-54-163-97-228.compute-1.amazonaws.com', 'HOST': os.environ.get("DB_HOST"),
'PORT': '5432', 'PORT': os.environ.get("DB_PORT"),
} },
#
# 'default': {
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
# 'NAME': 'd84i5cbjig5rrf',
# 'USER': 'hbkullcdjbxuwh',
# 'PASSWORD': '45d990da00e2cc96d7d4e2e5e308d4b07a387883f70c40e090a6252175cb634e',
# 'HOST': 'ec2-54-163-97-228.compute-1.amazonaws.com',
# 'PORT': '5432',
# }
} }
# Password validation # Password validation

View File

@ -21,6 +21,14 @@
table, td, div, h1, p { table, td, div, h1, p {
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
} }
#details_table tr:nth-child(even) {background: #FFF}
#details_table tr:nth-child(odd) {background: #f9f9f9}
#details_table td {padding: 10px}
#details_table{
border: #334878 1px solid;
border-collapse: collapse;
}
</style> </style>
</head> </head>
@ -47,13 +55,44 @@
We have received your <b>{{ opening_type }}</b> notification for a <b>{{ designation }}</b> offer at <b> We have received your <b>{{ opening_type }}</b> notification for a <b>{{ designation }}</b> offer at <b>
{{ company_name }}</b>. Click <a href="{{ opening_link }}">here</a> to view your notification. {{ company_name }}</b>. Click <a href="{{ opening_link }}">here</a> to view your notification.
</p> </p>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;"> <p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
We will keep you informed with the updates. If you have any queries, please We will keep you informed with the updates. If you have any queries, please
feel to feel to
write to write to
<nobr><u>cdc@iitdh.ac.in</u></nobr> <nobr><u>cdc@iitdh.ac.in</u></nobr>
</p> </p>
<table id="details_table">
{% for key, value in data.items %}
<tr>
<td >
{{ key }}
</td>
<td>
{% if 'list' in value.type %}
{% for item in value.details %}
<li>
{% if 'link' in value.type and value.link %}
<a href="{{value.link|add:item}}">{{ item }}</a>
{% elif 'link' in value.type %}
<a href="{{item}}">{{ item }}</a>
{% else %}
{{ item }}
{% endif %}
</li>
{% endfor %}
{% else %}
{% if 'link' in value.type %}
<a href="{{ value.details }}">{{ value.details }}</a>
{% else %}
{{ value }}
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</td> </td>
</tr> </tr>

View File

@ -1,4 +1,4 @@
# CDC - Backend python# CDC - Backend
--- ---
@ -34,6 +34,9 @@
1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py) 1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py)
2. Update the `CORS_ORIGIN_WHITELIST` list and `CORS_ORIGIN_ALLOW_ALL` variable 2. Update the `CORS_ORIGIN_WHITELIST` list and `CORS_ORIGIN_ALLOW_ALL` variable
### Starting the Email Server
Run the following command to start the email backend process <br>
`python manage.py process_tasks`
### API Reference ### API Reference
Check [here](./CDC_Backend/README.md) for Api Reference Check [here](./CDC_Backend/README.md) for Api Reference