Added Verify Email Functionality

This commit is contained in:
Gowtham Sai 2021-12-17 17:15:56 +05:30
parent 95fd24a776
commit 364a66be30
12 changed files with 90 additions and 21 deletions

View File

@ -16,7 +16,7 @@ def markStatus(request, id, email, user_type):
# Getting all application from db for this opening # Getting all application from db for this opening
applications = PlacementApplication.objects.filter(placement_id=data[OPENING_ID]) applications = PlacementApplication.objects.filter(placement_id=data[OPENING_ID])
for i in data[STUDENT_LIST]: for i in data[STUDENT_LIST]:
application = applications.filter(student_id=i[STUDENT_ID]) # Filtering student's application application = applications.filter(student__roll_no=i[STUDENT_ID]) # Filtering student's application
if len(application) > 0: if len(application) > 0:
application = application[0] application = application[0]
application.selected = True if i[STUDENT_SELECTED] == "true" else False application.selected = True if i[STUDENT_SELECTED] == "true" else False

View File

@ -4,4 +4,5 @@ from . import companyViews
urlpatterns = [ urlpatterns = [
path('addPlacement/', companyViews.addPlacement, name="Add Placement"), path('addPlacement/', companyViews.addPlacement, name="Add Placement"),
path('verifyEmail/', companyViews.verifyEmail, name="Verify Email"),
] ]

View File

@ -1,5 +1,5 @@
import json import json
from datetime import datetime import datetime
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
@ -178,7 +178,7 @@ def addPlacement(request):
else: else:
raise ValueError('Invalid compensation gross') raise ValueError('Invalid compensation gross')
# Convert to date object # Convert to date object
opening.tentative_date_of_joining = datetime.strptime(data[TENTATIVE_DATE_OF_JOINING], '%d-%m-%Y').date() opening.tentative_date_of_joining = datetime.datetime.strptime(data[TENTATIVE_DATE_OF_JOINING], '%d-%m-%Y').date()
# Only Allowing Fourth Year for Placement # Only Allowing Fourth Year for Placement
opening.allowed_batch = [FOURTH_YEAR, ] opening.allowed_batch = [FOURTH_YEAR, ]
@ -202,15 +202,18 @@ def addPlacement(request):
opening.save() opening.save()
stat, link = generateOneTimeVerificationLink(opening.email, opening.id, "Placement")
if not stat:
raise RuntimeError("Error in generating one time verification link for placement")
data = { data = {
"designation": opening.designation, "designation": opening.designation,
"opening_type": PLACEMENT, "one_time_link": link
"opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too
"company_name": opening.company_name
} }
sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data, sendEmail(opening.email, COMPANY_EMAIl_VERIFICATION_TEMPLATE_SUBJECT, data,
COMPANY_OPENING_SUBMITTED_TEMPLATE) COMPANY_EMAIL_VERIFICATION_TEMPLATE)
return Response({'action': "Add Placement", 'message': "Placement Added Successfully"}, return Response({'action': "Add Placement", 'message': "Placement Added Successfully"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
@ -222,3 +225,45 @@ def addPlacement(request):
logger.warning("Add New Placement: " + str(sys.exc_info())) logger.warning("Add New Placement: " + str(sys.exc_info()))
return Response({'action': "Add Placement", 'message': "Something went wrong"}, return Response({'action': "Add Placement", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@precheck([TOKEN])
def verifyEmail(request):
try:
data = request.data
token = data[TOKEN]
# decode token
decoded_token = jwt.decode(token, os.environ.get("EMAIL_VERIFICATION_SECRET_KEY"), algorithms=['HS256'])
# get email, opening_id, opening_type from token
email = decoded_token['email']
opening_id = decoded_token['opening_id']
opening_type = decoded_token['opening_type']
# get opening based on opening_type and opening_id
if opening_type == PLACEMENT:
opening = get_object_or_404(Placement, id=opening_id)
if email != opening.email:
raise ValueError("Invalid Email")
opening.email_verified = True
opening.save()
data = {
"designation": opening.designation,
"opening_type": PLACEMENT,
"opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too
"company_name": opening.company_name
}
sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data,
COMPANY_OPENING_SUBMITTED_TEMPLATE)
else:
raise ValueError('Invalid opening type')
return Response({'action': "Verify Email", 'message': "Email Verified Successfully"},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Verify Email", 'message': "Opening Not Found"},
status=status.HTTP_404_NOT_FOUND)
except ValueError as e:
return Response({'action': "Verify Email", 'message': str(e)},
status=status.HTTP_400_BAD_REQUEST)
except:
logger.warning("Verify Email: " + str(sys.exc_info()))
return Response({'action': "Verify Email", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -39,13 +39,12 @@ TOTAL_BATCHES = 4 # Total No of Batches
CLIENT_ID = "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com" # Google Login Client ID CLIENT_ID = "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com" # Google Login Client ID
# To be Configured Properly # To be Configured Properly
PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}" PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}" # On frontend, this is the URL to be opened
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}"
TOKEN = "token_id"
EMAIL = "email" EMAIL = "email"
STUDENT = 'student' STUDENT = 'student'
@ -55,13 +54,14 @@ COMPANY = ''
# To be Configured Properly # To be Configured Properly
FOURTH_YEAR = '2018' FOURTH_YEAR = '2018'
MAX_OFFERS_PER_STUDENT = 2 MAX_OFFERS_PER_STUDENT = 2
EMAIL_VERIFICATION_TOKEN_TTL = 48 # in hours
STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/" STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/"
STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/' STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/'
STORAGE_DESTINATION_APPLICATION_CSV = './Storage/Application_CSV/' STORAGE_DESTINATION_APPLICATION_CSV = './Storage/Application_CSV/'
TOKEN = 'token'
RESUME_FILE_NAME = 'resume_file_name' RESUME_FILE_NAME = 'resume_file_name'
APPLICATION_ID = "application_id" APPLICATION_ID = "application_id"
@ -123,14 +123,16 @@ STUDENT_ID = "student_id"
STUDENT_SELECTED = "student_selected" STUDENT_SELECTED = "student_selected"
COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - CDC IIT Dharwad" COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - Career Development Cell, IIT Dharwad"
STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}' STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}'
STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - {company_name}' STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - {company_name}'
COMPANY_EMAIl_VERIFICATION_TEMPLATE_SUBJECT = 'Email Verification - Career Development Cell, IIT Dharwad'
STUDENT_APPLICATION_SUBMITTED_TEMPLATE = 'student_application_submitted.html' STUDENT_APPLICATION_SUBMITTED_TEMPLATE = 'student_application_submitted.html'
COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html' COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html'
STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html' STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html'
STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE = 'student_application_status_not_selected.html' STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE = 'student_application_status_not_selected.html'
COMPANY_EMAIL_VERIFICATION_TEMPLATE = 'company_email_verification.html'
APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI', APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI',
'Resume', 'Selected', ] 'Resume', 'Selected', ]

View File

@ -1,9 +1,11 @@
import datetime
import logging import logging
import os import os
import random import random
import re import re
import string import string
import sys import sys
import jwt
from os import path, remove from os import path, remove
import background_task import background_task
@ -104,7 +106,7 @@ def isAuthorized(allowed_users=None):
def generateRandomString(): def generateRandomString():
try: try:
N = 15 N = 15
res = ''.join(random.choices(string.ascii_uppercase +string.ascii_lowercase+ string.digits, k=N)) res = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=N))
return res return res
except: except:
return False return False
@ -214,3 +216,20 @@ def getTier(compensation_gross, is_psu=False):
print(sys.exc_info()) print(sys.exc_info())
logger.warning("Utils - getTier: " + str(sys.exc_info())) logger.warning("Utils - getTier: " + str(sys.exc_info()))
return False, "_" return False, "_"
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:
print(sys.exc_info())
logger.warning("Utils - generateOneTimeVerificationLink: " + str(sys.exc_info()))
return False, "_"

View File

@ -32,7 +32,7 @@
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr> <tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;"> <td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/> <img src="https://drive.google.com/uc?id=1QTA6dB7jnsZfU1kzyUqfD_2V5xODpWFt" alt="" width="200" style="height:auto;display:block;"/>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -41,9 +41,9 @@
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;"> style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr> <tr>
<td style="padding:0 0 36px 0;color:#153643;"> <td style="padding:0 0 36px 0;color:#153643;">
<h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif;">Hi,</h1>
<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 have received your Job Notification for {{designation}}. Kindly verify your email by clicking <a href={{ one_time_link }}>here</a>. We have received your Job Notification. Kindly verify your email by clicking <a href="{{ one_time_link }}">here</a>.
</p> </p>
</td> </td>
</tr> </tr>

View File

@ -32,7 +32,7 @@
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr> <tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;"> <td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/> <img src="https://drive.google.com/uc?id=1QTA6dB7jnsZfU1kzyUqfD_2V5xODpWFt" alt="" width="200" style="height:auto;display:block;"/>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -31,7 +31,7 @@
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr> <tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;"> <td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/> <img src="https://drive.google.com/uc?id=1QTA6dB7jnsZfU1kzyUqfD_2V5xODpWFt" alt="" width="200" style="height:auto;display:block;"/>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -31,7 +31,7 @@
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr> <tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;"> <td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/> <img src="https://drive.google.com/uc?id=1QTA6dB7jnsZfU1kzyUqfD_2V5xODpWFt" alt="" width="200" style="height:auto;display:block;"/>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -32,7 +32,7 @@
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr> <tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;"> <td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/> <img src="https://drive.google.com/uc?id=1QTA6dB7jnsZfU1kzyUqfD_2V5xODpWFt" alt="" width="200" style="height:auto;display:block;"/>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -3,6 +3,7 @@ DEBUG=True
EMAIL=saisurya3127@gmail.com EMAIL=saisurya3127@gmail.com
EMAIL_PASSWORD=yeylqcnsyjfpzsew EMAIL_PASSWORD=yeylqcnsyjfpzsew
SECRET_KEY=%2e!&f6(ib^690y48z=)&w6fczhwukzzp@3y*^*7u+7%4s-mie SECRET_KEY=%2e!&f6(ib^690y48z=)&w6fczhwukzzp@3y*^*7u+7%4s-mie
EMAIL_VERIFICATION_SECRET_KEY=b'<\xa3\xaf&(*|\x0e\xbces\x07P\xf7\xd6\xa9sf\x19$\x96\xb7\x90\x8b\x88\x84\x0e\x191\xde,M\x90\x17(\xf7\nG\x13"\x8d$\x9f&\xb0\xcd\xa4\xaf\xa9\x1b\x15\x02B\x8a\xaf\xff\x0c\x1e\xd5\xb3\x06\xb8\xa6\x9bQ\xa0TR\xe8\x98\x9ae\xe0n}\xcc/[\xdaFz\x18\xfeX\xaf\xbd\xd0\x88\xeal\xe3\xd2\xe3\xb8\x8c\x199{\xf3<\xb0\xc5\xd0\xe7*Rv\xda\xbb \x1d\x85~\xff%>\x1e\xb8\xa7\xbf\xbc\xb2\x06\x86X\xc3\x9f\x13<\x9fd\xea\xb5"\\5&\x01\xa4\x7f=\xa0\x1b\x8bO\x01h\xe8\xfd\x1f\xfe\xba\xbeg\\\xc2\xcb\xc3\xd1~\xff\xd5/9d\xa8\xa7x{\x16\xdb\\\xbb\x08\rI\xcd\x9e7\x8c~\x0f\x1d\x81rXZD\xf0\xf7\x87K\x8f\xfb,\xf4\xf0\xa5\x9e\xde^\xca\xae\x80|9b\x9b\xaaE"\xba\xfb\xdf\x80\xb1\x99\x83e[\xf8\xce&Rq\x99\xdb}\xeeO\xd5\x18\x8d\x0bv\xe7\xab\xf9\xb9{\xb5u\xce\xcf\x90\xa6HE\xc5\x92p\x00\x158\xdf\x1d'
DB_NAME=cdc DB_NAME=cdc
DB_USER=postgres DB_USER=postgres
DB_PASSWORD=root DB_PASSWORD=root

View File

@ -28,6 +28,7 @@ pyasn1-modules==0.2.8
pylint==2.12.2 pylint==2.12.2
python-dotenv==0.19.2 python-dotenv==0.19.2
pytz==2021.3 pytz==2021.3
PyJWT==2.0.1
requests==2.26.0 requests==2.26.0
rsa==4.8 rsa==4.8
six==1.16.0 six==1.16.0