Merge pull request #68 from CDC-IITDH/modified-apis

Modified APIs
This commit is contained in:
CDC-IITDH 2021-12-17 19:40:51 +05:30 committed by GitHub
commit ea773fefe7
16 changed files with 165 additions and 66 deletions

View File

@ -8,10 +8,7 @@ from django.utils.safestring import SafeText
from .models import * from .models import *
admin.site.register(User) admin.site.register(User)
# admin.site.register(Student)
admin.site.register(Admin) admin.site.register(Admin)
# admin.site.register(Placement)
admin.site.register(PlacementApplication)
admin.site.register(PrePlacementOffer) admin.site.register(PrePlacementOffer)
admin.site.site_header = "CDC Recruitment Portal" admin.site.site_header = "CDC Recruitment Portal"
@ -38,4 +35,17 @@ class Placement(admin.ModelAdmin):
list_filter = ('tier',) list_filter = ('tier',)
@admin.register(PlacementApplication)
class PlacementApplication(admin.ModelAdmin):
list_display = ('id', 'Placement', 'Student', 'selected')
search_fields = ('id',)
ordering = ('id',)
list_filter = ('selected',)
def Placement(self, obj):
return model_admin_url(obj.placement)
def Student(self, obj):
return model_admin_url(obj.student)

View File

@ -1,10 +1,10 @@
import json
from datetime import datetime
from .utils import *
from rest_framework.decorators import api_view
import csv import csv
import json
from rest_framework.decorators import api_view
from .serializers import * from .serializers import *
from .utils import *
@api_view(['POST']) @api_view(['POST'])
@ -16,14 +16,15 @@ 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
email = str(application.student.roll_no) + "@iitdh.ac.in" # Only allowing for IITDh emails email = str(application.student.roll_no) + "@iitdh.ac.in" # Only allowing for IITDh emails
subject = STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT.format(company_name=application.placement.company_name, subject = STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT.format(
id=application.id) company_name=application.placement.company_name,
id=application.id)
data = { data = {
"company_name": application.placement.company_name, "company_name": application.placement.company_name,
"designation": application.placement.designation, "designation": application.placement.designation,
@ -53,13 +54,17 @@ 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.now()) ongoing = placements.filter(deadline_datetime__gt=datetime.datetime.now(), offer_accepted__isnull=False)
previous = placements.exclude(deadline_datetime__gt=datetime.now()) previous = placements.exclude(deadline_datetime__gt=datetime.datetime.now()).filter(
offer_accepted__isnull=False)
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
new = PlacementSerializerForAdmin(new, many=True).data
return Response( return Response(
{'action': "Get Dashboard - Admin", 'message': "Data Found", "ongoing": ongoing, "previous": previous}, {'action': "Get Dashboard - Admin", 'message': "Data Found", "ongoing": ongoing, "previous": previous,
"new": new},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404: except Http404:
return Response({'action': "Get Dashboard - Admin", 'message': 'Student Not Found'}, return Response({'action': "Get Dashboard - Admin", 'message': 'Student Not Found'},
@ -78,7 +83,7 @@ def updateDeadline(request, id, email, user_type):
data = request.data data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
# Updating deadline date with correct format in datetime field # Updating deadline date with correct format in datetime field
opening.deadline_datetime = datetime.strptime(data[DEADLINE_DATETIME], '%Y-%m-%d %H:%M:%S %z') opening.deadline_datetime = datetime.datetime.strptime(data[DEADLINE_DATETIME], '%Y-%m-%d %H:%M:%S %z')
opening.save() opening.save()
return Response({'action': "Update Deadline", 'message': "Deadline Updated"}, return Response({'action': "Update Deadline", 'message': "Deadline Updated"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
@ -90,6 +95,7 @@ def updateDeadline(request, id, email, user_type):
return Response({'action': "Update Deadline", 'message': "Something went wrong"}, return Response({'action': "Update Deadline", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST']) @api_view(['POST'])
@isAuthorized([ADMIN]) @isAuthorized([ADMIN])
@precheck([OPENING_ID, OFFER_ACCEPTED]) @precheck([OPENING_ID, OFFER_ACCEPTED])
@ -109,6 +115,7 @@ def updateOfferAccepted(request, id, email, user_type):
return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"}, return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST']) @api_view(['POST'])
@isAuthorized([ADMIN]) @isAuthorized([ADMIN])
@precheck([OPENING_ID, EMAIL_VERIFIED]) @precheck([OPENING_ID, EMAIL_VERIFIED])
@ -128,6 +135,7 @@ def updateEmailVerified(request, id, email, user_type):
return Response({'action': "Update Email Verified", 'message': "Something went wrong"}, return Response({'action': "Update Email Verified", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST']) @api_view(['POST'])
@isAuthorized([ADMIN]) @isAuthorized([ADMIN])
@precheck([OPENING_ID, ADDITIONAL_INFO]) @precheck([OPENING_ID, ADDITIONAL_INFO])
@ -165,8 +173,8 @@ def getApplications(request, id, email, user_type):
opening = get_object_or_404(Placement, pk=data[OPENING_ID]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
applications = PlacementApplication.objects.filter(placement=opening) applications = PlacementApplication.objects.filter(placement=opening)
serializer = PlacementApplicationSerializerForAdmin(applications, many=True) serializer = PlacementApplicationSerializerForAdmin(applications, many=True)
return Response({'action': "Get Applications", 'message': 'Data Found', 'applications':serializer.data}, return Response({'action': "Get Applications", 'message': 'Data Found', 'applications': serializer.data},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404: except Http404:
return Response({'action': "Get Applications", 'message': 'Opening Not Found'}, return Response({'action': "Get Applications", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
@ -176,7 +184,6 @@ def getApplications(request, id, email, user_type):
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST']) @api_view(['POST'])
@isAuthorized(allowed_users=[ADMIN]) @isAuthorized(allowed_users=[ADMIN])
@precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME, @precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME,
@ -193,7 +200,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")
@ -229,7 +236,7 @@ def submitApplication(request, id, email, user_type):
"additional_info": dict(json.loads(application.additional_info)), "additional_info": dict(json.loads(application.additional_info)),
} }
subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name) subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
student_email = str(student.roll_no)+"@iitdh.ac.in" student_email = str(student.roll_no) + "@iitdh.ac.in"
sendEmail(student_email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE) sendEmail(student_email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
application.save() application.save()
@ -250,7 +257,6 @@ def submitApplication(request, id, email, user_type):
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST']) @api_view(['POST'])
@isAuthorized(allowed_users=[ADMIN]) @isAuthorized(allowed_users=[ADMIN])
@precheck(required_data=[OPENING_ID]) @precheck(required_data=[OPENING_ID])
@ -270,12 +276,12 @@ def generateCSV(request, id, email, user_type):
header_row.extend(placement.additional_info) header_row.extend(placement.additional_info)
writer.writerow(header_row) writer.writerow(header_row)
for apl in applications: for apl in applications:
row_details=[] row_details = []
row_details.append(apl.applied_at) row_details.append(apl.applied_at)
row_details.append(apl.student.roll_no) row_details.append(apl.student.roll_no)
row_details.append(apl.student.name) row_details.append(apl.student.name)
row_details.append(str(apl.student.roll_no)+"@iitdh.ac.in") row_details.append(str(apl.student.roll_no) + "@iitdh.ac.in")
row_details.append(apl.student.phone_number) row_details.append(apl.student.phone_number)
row_details.append(apl.student.branch) row_details.append(apl.student.branch)
row_details.append(apl.student.batch) row_details.append(apl.student.batch)
@ -289,11 +295,11 @@ def generateCSV(request, id, email, user_type):
writer.writerow(row_details) writer.writerow(row_details)
f.close() f.close()
file_path = LINK_TO_APPLICATIONS_CSV + urllib.parse.quote_plus(filename+".csv") file_path = LINK_TO_APPLICATIONS_CSV + urllib.parse.quote_plus(filename + ".csv")
return Response({'action': "Create csv", 'message': "CSV created", 'file': file_path}, return Response({'action': "Create csv", 'message': "CSV created", 'file': file_path},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except: except:
logger.warning("Create csv: " + str(sys.exc_info())) logger.warning("Create csv: " + str(sys.exc_info()))
print(sys.exc_info()) print(sys.exc_info())
return Response({'action': "Create csv", 'message': "Error Occurred"}, return Response({'action': "Create csv", 'message': "Error Occurred"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)

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,4 @@
import json import json
from datetime import datetime
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
@ -178,7 +177,8 @@ 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, ]
@ -193,6 +193,8 @@ def addPlacement(request):
# Check if tentative_no_of_offers is integer # Check if tentative_no_of_offers is integer
if data[TENTATIVE_NO_OF_OFFERS].isdigit(): if data[TENTATIVE_NO_OF_OFFERS].isdigit():
opening.tentative_no_of_offers = int(data[TENTATIVE_NO_OF_OFFERS]) opening.tentative_no_of_offers = int(data[TENTATIVE_NO_OF_OFFERS])
elif data[TENTATIVE_NO_OF_OFFERS] == 'null':
opening.tentative_no_of_offers = None
else: else:
raise ValueError('Tentative No Of Offers must be an integer') raise ValueError('Tentative No Of Offers must be an integer')
@ -200,15 +202,16 @@ 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)
@ -220,3 +223,46 @@ 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

@ -22,6 +22,9 @@ class Student(models.Model):
resumes = ArrayField(models.CharField(null=True, default=None, max_length=100), size=10, default=list, blank=True) resumes = ArrayField(models.CharField(null=True, default=None, max_length=100), size=10, default=list, blank=True)
cpi = models.DecimalField(decimal_places=2, max_digits=4) cpi = models.DecimalField(decimal_places=2, max_digits=4)
def __str__(self):
return str(self.roll_no)
class Admin(models.Model): class Admin(models.Model):
id = models.CharField(blank=False, max_length=15, primary_key=True) id = models.CharField(blank=False, max_length=15, primary_key=True)
@ -81,7 +84,7 @@ class Placement(models.Model):
size=TOTAL_BRANCHES, size=TOTAL_BRANCHES,
default=list default=list
) )
tentative_no_of_offers = models.IntegerField(blank=False, default=1) tentative_no_of_offers = models.IntegerField(blank=False, default=None, null=True)
other_requirements = models.CharField(blank=True, max_length=200, default="") other_requirements = models.CharField(blank=True, max_length=200, default="")
additional_info = ArrayField(models.CharField(blank=True, max_length=200), size=15, default=list, blank=True) additional_info = ArrayField(models.CharField(blank=True, max_length=200), size=15, default=list, blank=True)
email_verified = models.BooleanField(blank=False, default=False) email_verified = models.BooleanField(blank=False, default=False)
@ -96,6 +99,9 @@ class Placement(models.Model):
return super(Placement, self).save(*args, **kwargs) return super(Placement, self).save(*args, **kwargs)
def __str__(self):
return self.company_name + " - " + self.id
class PlacementApplication(models.Model): class PlacementApplication(models.Model):
id = models.CharField(blank=False, primary_key=True, max_length=15) id = models.CharField(blank=False, primary_key=True, max_length=15)
placement = models.ForeignKey(Placement, blank=False, on_delete=models.RESTRICT, default=None, null=True) placement = models.ForeignKey(Placement, blank=False, on_delete=models.RESTRICT, default=None, null=True)
@ -116,6 +122,9 @@ class PlacementApplication(models.Model):
verbose_name_plural = "Placement Applications" verbose_name_plural = "Placement Applications"
unique_together = ('placement_id', 'student_id') unique_together = ('placement_id', 'student_id')
def __str__(self):
return self.placement.company_name + " - " + self.student.name
class PrePlacementOffer(models.Model): class PrePlacementOffer(models.Model):
id = models.AutoField(primary_key=True) id = models.AutoField(primary_key=True)

View File

@ -154,8 +154,11 @@ class PlacementApplicationSerializer(serializers.ModelSerializer):
return data return data
def get_resume_link(self, obj): def get_resume_link(self, obj):
link = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(obj.id + "/" + obj.resume) ele = {}
return link ele['link'] = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(obj.id + "/" + obj.resume)
ele['name'] = obj.resume
return ele
class Meta: class Meta:
model = PlacementApplication model = PlacementApplication

View File

@ -44,7 +44,7 @@ def addResume(request, id, email, user_type):
files = request.FILES files = request.FILES
file = files['file'] file = files['file']
destination_path = STORAGE_DESTINATION_RESUMES + id + "/" destination_path = STORAGE_DESTINATION_RESUMES + str(student.roll_no) + "/"
file_name = saveFile(file, destination_path) file_name = saveFile(file, destination_path)
student.resumes.append(file_name) student.resumes.append(file_name)

View File

@ -1,11 +1,14 @@
import datetime
import logging import logging
import os import os
import random import random
import re
import string import string
import sys import sys
from os import path, remove from os import path, remove
import background_task import background_task
import jwt
from django.conf import settings from django.conf import settings
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from django.http import Http404 from django.http import Http404
@ -103,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
@ -113,8 +116,10 @@ def saveFile(file, location):
prefix = generateRandomString() prefix = generateRandomString()
file_name = prefix + "_" + file.name file_name = prefix + "_" + file.name
file_name = re.sub(r'[\\/:*?"<>|]', '_', file_name)
if not path.isdir(location): if not path.isdir(location):
os.mkdir(location) os.makedirs(location)
destination_path = location + str(file_name) destination_path = location + str(file_name)
if path.exists(destination_path): if path.exists(destination_path):
@ -123,7 +128,6 @@ def saveFile(file, location):
with open(destination_path, 'wb+') as destination: with open(destination_path, 'wb+') as destination:
for chunk in file.chunks(): for chunk in file.chunks():
destination.write(chunk) destination.write(chunk)
return file_name return file_name
@ -212,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

@ -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

@ -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

@ -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