From 364a66be308eb117817cc671d218bebab977ed97 Mon Sep 17 00:00:00 2001 From: Gowtham Sai <66207607+gowtham3105@users.noreply.github.com> Date: Fri, 17 Dec 2021 17:15:56 +0530 Subject: [PATCH] Added Verify Email Functionality --- CDC_Backend/APIs/adminViews.py | 2 +- CDC_Backend/APIs/companyUrls.py | 1 + CDC_Backend/APIs/companyViews.py | 59 ++++++++++++++++--- CDC_Backend/APIs/constants.py | 12 ++-- CDC_Backend/APIs/utils.py | 21 ++++++- ...l.html => company_email_verification.html} | 6 +- .../templates/company_opening_submitted.html | 2 +- ...udent_application_status_not_selected.html | 2 +- .../student_application_status_selected.html | 2 +- .../student_application_submitted.html | 2 +- dev.env | 1 + requirements.txt | 1 + 12 files changed, 90 insertions(+), 21 deletions(-) rename CDC_Backend/templates/{verify_email.html => company_email_verification.html} (91%) diff --git a/CDC_Backend/APIs/adminViews.py b/CDC_Backend/APIs/adminViews.py index 3183343..dc50652 100644 --- a/CDC_Backend/APIs/adminViews.py +++ b/CDC_Backend/APIs/adminViews.py @@ -16,7 +16,7 @@ def markStatus(request, id, email, user_type): # Getting all application from db for this opening applications = PlacementApplication.objects.filter(placement_id=data[OPENING_ID]) 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: application = application[0] application.selected = True if i[STUDENT_SELECTED] == "true" else False diff --git a/CDC_Backend/APIs/companyUrls.py b/CDC_Backend/APIs/companyUrls.py index 5cda889..525a585 100644 --- a/CDC_Backend/APIs/companyUrls.py +++ b/CDC_Backend/APIs/companyUrls.py @@ -4,4 +4,5 @@ from . import companyViews urlpatterns = [ path('addPlacement/', companyViews.addPlacement, name="Add Placement"), + path('verifyEmail/', companyViews.verifyEmail, name="Verify Email"), ] diff --git a/CDC_Backend/APIs/companyViews.py b/CDC_Backend/APIs/companyViews.py index a73b0cf..862483f 100644 --- a/CDC_Backend/APIs/companyViews.py +++ b/CDC_Backend/APIs/companyViews.py @@ -1,5 +1,5 @@ import json -from datetime import datetime +import datetime from rest_framework.decorators import api_view @@ -178,7 +178,7 @@ def addPlacement(request): else: raise ValueError('Invalid compensation gross') # 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 opening.allowed_batch = [FOURTH_YEAR, ] @@ -202,15 +202,18 @@ def addPlacement(request): 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 = { "designation": opening.designation, - "opening_type": PLACEMENT, - "opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too - "company_name": opening.company_name + "one_time_link": link } - sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data, - COMPANY_OPENING_SUBMITTED_TEMPLATE) + sendEmail(opening.email, COMPANY_EMAIl_VERIFICATION_TEMPLATE_SUBJECT, data, + COMPANY_EMAIL_VERIFICATION_TEMPLATE) return Response({'action': "Add Placement", 'message': "Placement Added Successfully"}, status=status.HTTP_200_OK) @@ -222,3 +225,45 @@ def addPlacement(request): logger.warning("Add New Placement: " + str(sys.exc_info())) return Response({'action': "Add Placement", 'message': "Something went wrong"}, 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) diff --git a/CDC_Backend/APIs/constants.py b/CDC_Backend/APIs/constants.py index 4201ce9..af96560 100644 --- a/CDC_Backend/APIs/constants.py +++ b/CDC_Backend/APIs/constants.py @@ -39,13 +39,12 @@ TOTAL_BATCHES = 4 # Total No of Batches CLIENT_ID = "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com" # Google Login Client ID # 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_RESUME = "https://storage.googleapis.com/cdc-backend-attachments/resume/" 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" STUDENT = 'student' @@ -55,13 +54,14 @@ COMPANY = '' # To be Configured Properly FOURTH_YEAR = '2018' MAX_OFFERS_PER_STUDENT = 2 +EMAIL_VERIFICATION_TOKEN_TTL = 48 # in hours STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/" STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/' STORAGE_DESTINATION_APPLICATION_CSV = './Storage/Application_CSV/' - +TOKEN = 'token' RESUME_FILE_NAME = 'resume_file_name' APPLICATION_ID = "application_id" @@ -123,14 +123,16 @@ STUDENT_ID = "student_id" 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_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' COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html' STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_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', 'Resume', 'Selected', ] diff --git a/CDC_Backend/APIs/utils.py b/CDC_Backend/APIs/utils.py index de58aae..382e995 100644 --- a/CDC_Backend/APIs/utils.py +++ b/CDC_Backend/APIs/utils.py @@ -1,9 +1,11 @@ +import datetime import logging import os import random import re import string import sys +import jwt from os import path, remove import background_task @@ -104,7 +106,7 @@ def isAuthorized(allowed_users=None): def generateRandomString(): try: 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 except: return False @@ -214,3 +216,20 @@ def getTier(compensation_gross, is_psu=False): print(sys.exc_info()) logger.warning("Utils - getTier: " + str(sys.exc_info())) 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, "_" diff --git a/CDC_Backend/templates/verify_email.html b/CDC_Backend/templates/company_email_verification.html similarity index 91% rename from CDC_Backend/templates/verify_email.html rename to CDC_Backend/templates/company_email_verification.html index d12d078..e3f480a 100644 --- a/CDC_Backend/templates/verify_email.html +++ b/CDC_Backend/templates/company_email_verification.html @@ -32,7 +32,7 @@ style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> - + @@ -41,9 +41,9 @@ style="width:100%;border-collapse:collapse;border:0;border-spacing:0;"> -

Hi,

+

- We have received your Job Notification for {{designation}}. Kindly verify your email by clicking here. + We have received your Job Notification. Kindly verify your email by clicking here.

diff --git a/CDC_Backend/templates/company_opening_submitted.html b/CDC_Backend/templates/company_opening_submitted.html index 88147e0..a37c107 100644 --- a/CDC_Backend/templates/company_opening_submitted.html +++ b/CDC_Backend/templates/company_opening_submitted.html @@ -32,7 +32,7 @@ style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> - + diff --git a/CDC_Backend/templates/student_application_status_not_selected.html b/CDC_Backend/templates/student_application_status_not_selected.html index ee01642..4adcd2d 100644 --- a/CDC_Backend/templates/student_application_status_not_selected.html +++ b/CDC_Backend/templates/student_application_status_not_selected.html @@ -31,7 +31,7 @@ style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> - + diff --git a/CDC_Backend/templates/student_application_status_selected.html b/CDC_Backend/templates/student_application_status_selected.html index 0cd439f..608268a 100644 --- a/CDC_Backend/templates/student_application_status_selected.html +++ b/CDC_Backend/templates/student_application_status_selected.html @@ -31,7 +31,7 @@ style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> - + diff --git a/CDC_Backend/templates/student_application_submitted.html b/CDC_Backend/templates/student_application_submitted.html index eaeb123..05e5be8 100644 --- a/CDC_Backend/templates/student_application_submitted.html +++ b/CDC_Backend/templates/student_application_submitted.html @@ -32,7 +32,7 @@ style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;"> - + diff --git a/dev.env b/dev.env index 8695ea6..cfebb89 100644 --- a/dev.env +++ b/dev.env @@ -3,6 +3,7 @@ DEBUG=True EMAIL=saisurya3127@gmail.com EMAIL_PASSWORD=yeylqcnsyjfpzsew 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_USER=postgres DB_PASSWORD=root diff --git a/requirements.txt b/requirements.txt index bdb3ad7..fc2002f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,6 +28,7 @@ pyasn1-modules==0.2.8 pylint==2.12.2 python-dotenv==0.19.2 pytz==2021.3 +PyJWT==2.0.1 requests==2.26.0 rsa==4.8 six==1.16.0