Many Issues Resolved

- Placement Modal Resolved
- Add Placement API Resolved
- Update Deadline API
- Update Offer Accepted API
- Update Email Verified API
- Update Additional Info API
- Profile API Changes: Added Offers
- Serializers are tested and changed to fit the new modals
- Latest Documentation
-All APIs Tested and Checked
This commit is contained in:
gowtham3105 2021-12-03 01:04:49 +05:30
parent 19a95f839f
commit 57071ff29f
14 changed files with 952 additions and 249 deletions

View File

@ -1,7 +1,13 @@
from django.urls import path from django.urls import path
from . import companyViews from . import adminViews
urlpatterns = [ urlpatterns = [
path('markStatus/', adminViews.markStatus, name="Mark Status"),
path('getDashboard/', adminViews.getDashboard, name="Get Dashboard"),
path('updateDeadline/', adminViews.updateDeadline, name="Update Deadline"),
path('updateOfferAccepted/', adminViews.updateOfferAccepted, name="Update Offer Accepted"),
path('updateEmailVerified', adminViews.updateEmailVerified, name="Update Email Verified"),
path('updateAdditionalInfo/', adminViews.updateAdditionalInfo, name="Update Additional Info"),
] ]

View File

@ -0,0 +1,155 @@
from datetime import datetime
from .utils import *
from rest_framework.decorators import api_view
from .serializers import *
@api_view(['POST'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID, STUDENT_LIST])
def markStatus(request, id, email, user_type):
try:
data = request.data
# 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
if len(application) > 0:
application = application[0]
application.selected = True if i[STUDENT_SELECTED] == "true" else False
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,
id=application.id)
data = {
"company_name": application.placement.company_name,
"designation": application.placement.designation,
"student_name": application.student.name
}
if application.selected: # Sending corresponding email to students
sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE)
else:
sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE)
application.save()
else:
raise ValueError("Student - " + i[STUDENT_ID] + " didn't apply for this opening")
return Response({'action': "Mark Status", 'message': "Marked Status"},
status=status.HTTP_200_OK)
except ValueError as e:
return Response({'action': "Mark Status", 'message': str(e)},
status=status.HTTP_400_BAD_REQUEST)
except:
logger.warning("Mark Status: " + str(sys.exc_info()))
return Response({'action': "Mark Status", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET'])
@isAuthorized([ADMIN])
def getDashboard(request, id, email, user_type):
try:
placements = Placement.objects.all().order_by('-created_at')
ongoing = placements.filter(deadline_datetime__gt=datetime.now())
previous = placements.exclude(deadline_datetime__gt=datetime.now())
ongoing = PlacementSerializerForAdmin(ongoing, many=True).data
previous = PlacementSerializerForAdmin(previous, many=True).data
return Response(
{'action': "Get Dashboard - Admin", 'message': "Data Found", "ongoing": ongoing, "previous": previous},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Get Dashboard - Admin", 'message': 'Student Not Found'},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Get Dashboard - Admin: " + str(sys.exc_info()))
return Response({'action': "Get Dashboard - Admin", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID, DEADLINE_DATETIME])
def updateDeadline(request, id, email, user_type):
try:
data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
# 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.save()
return Response({'action': "Update Deadline", 'message': "Deadline Updated"},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Update Deadline", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Update Deadline: " + str(sys.exc_info()))
return Response({'action': "Update Deadline", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID, OFFER_ACCEPTED])
def updateOfferAccepted(request, id, email, user_type):
try:
data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
opening.offer_accepted = True if data[OFFER_ACCEPTED] == "true" else False
opening.save()
return Response({'action': "Update Offer Accepted", 'message': "Offer Accepted Updated"},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Update Offer Accepted", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Update Offer Accepted: " + str(sys.exc_info()))
return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID, EMAIL_VERIFIED])
def updateEmailVerified(request, id, email, user_type):
try:
data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
opening.email_verified = True if data[EMAIL_VERIFIED] == "true" else False
opening.save()
return Response({'action': "Update Email Verified", 'message': "Email Verified Updated"},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Update Email Verified", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Update Email Verified: " + str(sys.exc_info()))
return Response({'action': "Update Email Verified", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID, ADDITIONAL_INFO])
def updateAdditionalInfo(request, id, email, user_type):
try:
data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
if data[ADDITIONAL_INFO] == "":
opening.additional_info = []
elif isinstance(data[ADDITIONAL_INFO], list):
opening.additional_info = data[ADDITIONAL_INFO]
else:
raise ValueError("Additional Info must be a list")
opening.save()
return Response({'action': "Update Additional Info", 'message': "Additional Info Updated"},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Update Additional Info", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND)
except ValueError:
return Response({'action': "Update Additional Info", 'message': "Additional Info must be a list"},
status=status.HTTP_400_BAD_REQUEST)
except:
logger.warning("Update Additional Info: " + str(sys.exc_info()))
return Response({'action': "Update Additional Info", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -3,5 +3,5 @@ from . import companyViews
urlpatterns = [ urlpatterns = [
path('addOpening/', companyViews.addOpening, name="Add Opening"), path('addPlacement/', companyViews.addPlacement, name="Add Placement"),
] ]

View File

@ -1,120 +1,222 @@
import json import json
from datetime import datetime from datetime import datetime
from django.utils.timezone import make_aware
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from .models import *
from .utils import * from .utils import *
logger = logging.getLogger('db') logger = logging.getLogger('db')
@api_view(['POST']) @api_view(['POST'])
@precheck([DESIGNATION, DESCRIPTION, OPENING_TYPE, CITY, CITY_TYPE, @precheck([COMPANY_NAME, ADDRESS, COMPANY_TYPE, NATURE_OF_BUSINESS, WEBSITE, COMPANY_DETAILS, IS_COMPANY_DETAILS_PDF,
COMPENSATION, COMPENSATION_DETAILS, ALLOWED_BATCH, ALLOWED_BRANCH, CONTACT_PERSON_NAME, PHONE_NUMBER, EMAIL, CITY, STATE, COUNTRY, PINCODE, DESIGNATION, DESCRIPTION,
ROUNDS, CO_OP, START_DATE, ADDITIONAL_INFO, IS_DESCRIPTION_PDF,
DURATION, ROUND_DETAILS]) COMPENSATION_CTC, COMPENSATION_GROSS, COMPENSATION_TAKE_HOME, COMPENSATION_BONUS, COMPENSATION_DETAILS,
def addOpening(request): IS_COMPENSATION_DETAILS_PDF,
ALLOWED_BRANCH, SELECTION_PROCEDURE_ROUNDS, SELECTION_PROCEDURE_DETAILS, IS_SELECTION_PROCEDURE_DETAILS_PDF,
TENTATIVE_DATE_OF_JOINING,
TENTATIVE_NO_OF_OFFERS, OTHER_REQUIREMENTS
])
def addPlacement(request):
try: try:
data = request.data data = request.data
if data[OPENING_TYPE] == "Placement": files = request.FILES
opening = Placement() opening = Placement()
else:
raise ValueError("Invalid Opening Type")
opening.id = generateRandomString() opening.id = generateRandomString()
# Create Company object here for every Opening # Add a company details in the opening
opening.company_name = data[COMPANY_NAME]
opening.address = data[ADDRESS]
# Some new code above opening.company_type = data[COMPANY_TYPE]
opening.nature_of_business = data[NATURE_OF_BUSINESS]
if data[DESIGNATION] != "": opening.website = data[WEBSITE]
opening.designation = data[DESIGNATION] opening.company_details = data[COMPANY_DETAILS]
if data[IS_COMPANY_DETAILS_PDF] == "true":
opening.is_company_details_pdf = True
elif data[IS_COMPANY_DETAILS_PDF] == "false":
opening.is_company_details_pdf = False
else: else:
raise ValueError(DESIGNATION + " Not Found") raise ValueError('Invalid value for is_company_details_pdf')
if opening.is_company_details_pdf:
company_details_pdf = []
for file in files.getlist(COMPANY_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + opening.id + '/'
company_details_pdf.append(saveFile(file, file_location))
opening.company_details_pdf_names = company_details_pdf
# Add a contact person details in the opening
opening.contact_person_name = data[CONTACT_PERSON_NAME]
# Check if Phone number is Integer
if data[PHONE_NUMBER].isdigit():
opening.phone_number = int(data[PHONE_NUMBER])
else:
raise ValueError('Phone number should be integer')
opening.email = data[EMAIL]
# Add a company location in the opening
opening.city = data[CITY]
opening.state = data[STATE]
opening.country = data[COUNTRY]
# Check if Pincode is Integer
if data[PINCODE].isdigit():
opening.pin_code = int(data[PINCODE])
else:
raise ValueError('Pincode should be integer')
# If India then set city_type as Domestic else International
if opening.country == 'India':
opening.city_type = 'Domestic'
else:
opening.city_type = 'International'
# Add a designation details in the opening
opening.designation = data[DESIGNATION]
opening.description = data[DESCRIPTION] opening.description = data[DESCRIPTION]
if data[START_DATE] != "": # Check if is_description_pdf is boolean
opening.description = data[START_DATE] if data[IS_DESCRIPTION_PDF] == "true":
opening.is_description_pdf = True
elif data[IS_DESCRIPTION_PDF] == "false":
opening.is_description_pdf = False
else: else:
raise ValueError(START_DATE + " Not Found") raise ValueError('Invalid value for is_description_pdf')
if data[START_DATE] != "":
opening.start_date = datetime.strptime(data[START_DATE], '%d-%m-%Y') if opening.is_description_pdf:
description_pdf = []
for file in files.getlist(DESCRIPTION_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + opening.id + '/'
description_pdf.append(saveFile(file, file_location))
opening.description_pdf_names = description_pdf
# Add a compensation details in the opening
# Check if compensation_ctc is integer
if data[COMPENSATION_CTC].isdigit():
opening.compensation_CTC = int(data[COMPENSATION_CTC])
elif data[COMPENSATION_CTC] is None:
opening.compensation_CTC = None
else: else:
raise ValueError(START_DATE + " Not Found") raise ValueError('Compensation CTC must be an integer')
if data[CITY] != "":
opening.city = data[CITY] # Check if compensation_gross is integer
if data[COMPENSATION_GROSS].isdigit():
opening.compensation_gross = int(data[COMPENSATION_GROSS])
elif data[COMPENSATION_GROSS] is None:
opening.compensation_gross = None
else: else:
raise ValueError(CITY + " Not Found") raise ValueError('Compensation Gross must be an integer')
if data[CITY_TYPE] != "":
opening.city_type = data[CITY_TYPE] # Check if compensation_take_home is integer
if data[COMPENSATION_TAKE_HOME].isdigit():
opening.compensation_take_home = int(data[COMPENSATION_TAKE_HOME])
elif data[COMPENSATION_TAKE_HOME] is None:
opening.compensation_take_home = None
else: else:
raise ValueError(CITY_TYPE + " Not Found") raise ValueError('Compensation Take Home must be an integer')
if data[COMPENSATION] != "":
opening.compensation = data[COMPENSATION] # Check if compensation_bonus is integer
if data[COMPENSATION_BONUS].isdigit():
opening.compensation_bonus = int(data[COMPENSATION_BONUS])
elif data[COMPENSATION_BONUS] is None:
opening.compensation_bonus = None
else: else:
raise ValueError(COMPENSATION + " Not Found") raise ValueError('Compensation Bonus must be an integer')
opening.compensation_details = data[COMPENSATION_DETAILS] opening.compensation_details = data[COMPENSATION_DETAILS]
# Check if is_compensation_details_pdf is boolean
if data[ALLOWED_BATCH] != "": if data[IS_COMPENSATION_DETAILS_PDF] == "true":
if set(json.loads(data[ALLOWED_BATCH])).issubset(BATCHES): opening.is_compensation_details_pdf = True
opening.allowed_batch = json.loads(data[ALLOWED_BATCH]) elif data[IS_COMPENSATION_DETAILS_PDF] == "false":
else: opening.is_compensation_details_pdf = False
raise ValueError(ALLOWED_BATCH + " is Invalid")
else: else:
raise ValueError(ALLOWED_BATCH + " Not Found") raise ValueError('Invalid value for is_compensation_details_pdf')
if data[ALLOWED_BRANCH] != "":
if set(json.loads(data[ALLOWED_BRANCH])).issubset(BRANCHES): if opening.is_compensation_details_pdf:
opening.allowed_branch = json.loads(data[ALLOWED_BRANCH]) compensation_details_pdf = []
else: for file in files.getlist(COMPENSATION_DETAILS_PDF):
raise ValueError(ALLOWED_BATCH + " is Invalid") file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + opening.id + '/'
compensation_details_pdf.append(saveFile(file, file_location))
opening.compensation_details_pdf_names = compensation_details_pdf
opening.bond_details = data[BOND_DETAILS]
# Check if selection_procedure_rounds is list
if data[SELECTION_PROCEDURE_ROUNDS] is None:
raise ValueError('Selection Procedure Rounds cannot be empty')
else: else:
raise ValueError(ALLOWED_BRANCH + " Not Found") try:
opening.selection_procedure_rounds = json.loads(data[SELECTION_PROCEDURE_ROUNDS])
except:
raise ValueError('Selection Procedure Rounds must be a list')
opening.selection_procedure_details = data[SELECTION_PROCEDURE_DETAILS]
# Check if is_selection_procedure_details_pdf is boolean
if data[IS_SELECTION_PROCEDURE_DETAILS_PDF] == "true":
opening.is_selection_procedure_details_pdf = True
elif data[IS_SELECTION_PROCEDURE_DETAILS_PDF] == "false":
opening.is_selection_procedure_details_pdf = False
else:
raise ValueError('Invalid value for is_selection_procedure_pdf')
opening.rounds = json.loads(data[ROUNDS]) if opening.is_selection_procedure_details_pdf:
selection_procedure_details_pdf = []
for file in files.getlist(SELECTION_PROCEDURE_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + opening.id + '/'
selection_procedure_details_pdf.append(saveFile(file, file_location))
opening.additional_info = json.loads(data[ADDITIONAL_INFO]) opening.selection_procedure_details_pdf_names = selection_procedure_details_pdf
opening.status = STATUS_ACCEPTING_APPLICATIONS stat, tier = getTier(opening.compensation_gross)
if stat:
opening.tier = tier
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.rounds_details = json.loads(data[ROUND_DETAILS]) # Only Allowing Fourth Year for Placement
opening.allowed_batch = [FOURTH_YEAR, ]
# Check if allowed_branch are valid
if data[ALLOWED_BRANCH] is None:
raise ValueError('Allowed Branch cannot be empty')
elif set(json.loads(data[ALLOWED_BRANCH])).issubset(BRANCHES):
opening.allowed_branch = json.loads(data[ALLOWED_BRANCH])
else:
raise ValueError('Allowed Branch must be a subset of ' + str(BRANCHES))
opening.created_at = make_aware(datetime.now()) # Check if tentative_no_of_offers is integer
files = request.FILES.getlist(ATTACHMENTS) if data[TENTATIVE_NO_OF_OFFERS].isdigit():
attachments = [] opening.tentative_no_of_offers = int(data[TENTATIVE_NO_OF_OFFERS])
for file in files: else:
attachments.append(saveFile(file, STORAGE_DESTINATION_COMPANY_ATTACHMENTS)) raise ValueError('Tentative No Of Offers must be an integer')
opening.other_requirements = data[OTHER_REQUIREMENTS]
opening.attachments = attachments
opening.save() opening.save()
data = { data = {
"designation": opening.designation, "designation": opening.designation,
"opening_type": data[OPENING_TYPE], "opening_type": PLACEMENT,
"opening_link": "google.com", # 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
} }
# Needs some edits here sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data,
COMPANY_OPENING_SUBMITTED_TEMPLATE)
email = 'This is temporary' return Response({'action': "Add Placement", 'message': "Placement Added Successfully"},
# Delete the above var when done
stat = sendEmail(email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data,
COMPANY_OPENING_SUBMITTED_TEMPLATE)
if stat is not True:
logger.warning("Add New Opening: Unable to send email - " + stat)
return Response({'action': "Add Opening", 'message': "Opening Added"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except ValueError as e: except ValueError as e:
return Response({'action': "Add Opening", 'message': str(e)}, return Response({'action': "Add Placement", 'message': str(e)},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
except: except:
logger.warning("Add New Opening: " + str(sys.exc_info())) logger.warning("Add New Placement: " + str(sys.exc_info()))
return Response({'action': "Add Opening", 'message': "Error Occurred {0}".format( return Response({'action': "Add Placement", 'message': "Something went wrong"},
str(sys.exc_info()[1]))},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)

View File

@ -1,14 +1,20 @@
BRANCH_CHOICES = [ BRANCH_CHOICES = [
["CSE", "CSE"], ["CSE", "CSE"],
["EE", "EE"], ["EE", "EE"],
["ME", "ME"] ["ME", "ME"],
['EP', 'EP'],
]
BRANCHES = [
"CSE",
"EE",
"ME",
"EP"
] ]
BATCH_CHOICES = [ BATCH_CHOICES = [
["FIRST", "First"], ["2021", "2021"],
["SECOND", "Second"], ["2020", "2020"],
["THIRD", "Third"], ["2019", "2019"],
["FOURTH", "Fourth"] ["2018", "2018"]
] ]
OFFER_CITY_TYPE = [ OFFER_CITY_TYPE = [
@ -26,70 +32,102 @@ TIERS = [
['6', 'Tier 6'] ['6', 'Tier 6']
] ]
TOTAL_BRANCHES = 4 # Total No of Branches
TOTAL_BRANCHES = 3 # Total No of Branches
TOTAL_BATCHES = 4 # Total No of Batches TOTAL_BATCHES = 4 # Total No of Batches
# To be Configured Properly
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
PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}"
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/"
TOKEN = "token_id" TOKEN = "token_id"
EMAIL = "email" EMAIL = "email"
STUDENT = 'student' STUDENT = 'student'
ADMIN = 'Admin' ADMIN = 'admin'
COMPANY = '' COMPANY = ''
STORAGE_DESTINATION = "./Storage/Resumes/" # To be Configured Properly
FOURTH_YEAR = '2018'
MAX_OFFERS_PER_STUDENT = 2
STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/"
STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/' STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/'
RESUME_FILE_NAME = 'resume_file_name' RESUME_FILE_NAME = 'resume_file_name'
APPLICATION_ID = "application_id" APPLICATION_ID = "application_id"
OPENING_ID = "opening_id" OPENING_ID = "opening_id"
STUDENT_ID = "student_id"
ADDITIONAL_INFO = "additional_info" ADDITIONAL_INFO = "additional_info"
STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications" STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications"
PLACEMENT = "Placement" PLACEMENT = "Placement"
COMPANY_WEBSITE = 'website' COMPANY_NAME = "company_name"
COMPANY_ADDRESS = 'address' ADDRESS = "address"
COMPANY_TYPE = "company_type"
NATURE_OF_BUSINESS = "nature_of_business"
WEBSITE = 'website'
COMPANY_DETAILS = "company_details"
COMPANY_DETAILS_PDF = "company_details_pdf"
IS_COMPANY_DETAILS_PDF = "is_company_details_pdf"
COMPANY_DETAILS_PDF_NAMES = "company_details_pdf_names"
PHONE_NUMBER = 'phone_number' PHONE_NUMBER = 'phone_number'
CONTACT_PERSON_NAME = 'contact_person_name' CONTACT_PERSON_NAME = 'contact_person_name'
CITY = 'city'
STATE = 'state'
COUNTRY = 'country'
PINCODE = 'pincode'
DESIGNATION = 'designation' DESIGNATION = 'designation'
DESCRIPTION = 'description' DESCRIPTION = 'description'
DESCRIPTION_PDF = 'description_pdf'
DESCRIPTION_PDF_NAMES = 'description_pdf_names'
IS_DESCRIPTION_PDF = 'is_description_pdf'
OPENING_TYPE = 'opening_type' OPENING_TYPE = 'opening_type'
CITY = 'city' COMPENSATION_CTC = 'compensation_ctc'
CITY_TYPE = 'city_type' COMPENSATION_GROSS = 'compensation_gross'
COMPENSATION = 'compensation' COMPENSATION_TAKE_HOME = 'compensation_take_home'
COMPENSATION_BONUS = 'compensation_bonus'
COMPENSATION_DETAILS = 'compensation_details' COMPENSATION_DETAILS = 'compensation_details'
COMPENSATION_DETAILS_PDF = 'compensation_details_pdf'
COMPENSATION_DETAILS_PDF_NAMES = 'compensation_details_pdf_names'
IS_COMPENSATION_DETAILS_PDF = 'is_compensation_details_pdf'
ALLOWED_BATCH = 'allowed_batch' ALLOWED_BATCH = 'allowed_batch'
ALLOWED_BRANCH = 'allowed_branch' ALLOWED_BRANCH = 'allowed_branch'
ATTACHMENTS = 'attachments' BOND_DETAILS = 'bond_details'
ROUNDS = 'rounds' SELECTION_PROCEDURE_ROUNDS = 'selection_procedure_rounds'
ROUND_DETAILS = 'round_details' SELECTION_PROCEDURE_DETAILS = 'selection_procedure_details'
DURATION = 'duration' SELECTION_PROCEDURE_DETAILS_PDF = 'selection_procedure_details_pdf'
CO_OP = 'co_op' SELECTION_PROCEDURE_DETAILS_PDF_NAMES = 'selection_procedure_details_pdf_names'
START_DATE = "start_date" IS_SELECTION_PROCEDURE_DETAILS_PDF = 'is_selection_procedure_details_pdf'
TENTATIVE_DATE_OF_JOINING = 'tentative_date_of_joining'
TENTATIVE_NO_OF_OFFERS = 'tentative_no_of_offers'
OTHER_REQUIREMENTS = 'other_requirements'
DEADLINE_DATETIME = 'deadline_datetime'
OFFER_ACCEPTED = 'offer_accepted'
EMAIL_VERIFIED = 'email_verified'
STUDENT_LIST = "student_list" STUDENT_LIST = "student_list"
STUDENT_STATUS = "student_status" STUDENT_ID = "student_id"
STUDENT_SELECTED = "student_selected"
BRANCHES = [
"CSE",
"EE",
"ME"
]
BATCHES = [
"FIRST",
"SECOND",
"THIRD",
"FOURTH"
]
COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - CDC IIT Dharwad" COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - CDC IIT Dharwad"
STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}'
STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - {company_name}'
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_NOT_SELECTED_TEMPLATE = 'student_application_status_not_selected.html'

View File

@ -2,6 +2,8 @@ from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from .constants import * from .constants import *
# from .utils import *
class User(models.Model): class User(models.Model):
@ -26,58 +28,80 @@ class Admin(models.Model):
name = models.CharField(blank=False, max_length=50) name = models.CharField(blank=False, max_length=50)
def two_day_after_today():
return timezone.now() + timezone.timedelta(days=2)
class Placement(models.Model): class Placement(models.Model):
id = models.CharField(blank=False, primary_key=True, max_length=15) id = models.CharField(blank=False, primary_key=True, max_length=15)
name = models.CharField(blank=False, max_length=50, default="") # Company Details
address = models.CharField(blank=False, max_length=150, default="") company_name = models.CharField(blank=False, max_length=50)
companyType = models.CharField(blank=False, max_length=50, default="") address = models.CharField(blank=False, max_length=150)
website = models.CharField(blank=True, max_length=50, default="") company_type = models.CharField(blank=False, max_length=50)
contact_person_name = models.CharField(blank=False, max_length=50, default="") nature_of_business = models.CharField(blank=False, max_length=50, default="")
phone_number = models.PositiveBigIntegerField(blank=False, default=0) website = models.CharField(blank=True, max_length=50)
designation = models.CharField(blank=False, max_length=25, default=None, null=True) company_details = models.CharField(blank=False, max_length=500, default=None, null=True)
description = models.CharField(blank=False, max_length=200) company_details_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, default=list, blank=True)
start_date = models.DateField(blank=False, verbose_name="Start Date") is_company_details_pdf = models.BooleanField(blank=False, default=False)
contact_person_name = models.CharField(blank=False, max_length=50)
phone_number = models.PositiveBigIntegerField(blank=False)
email = models.CharField(blank=False, max_length=50, default="")
city = models.CharField(blank=False, max_length=100, default="") city = models.CharField(blank=False, max_length=100, default="")
state = models.CharField(blank=False, max_length=100, default="")
country = models.CharField(blank=False, max_length=100, default="")
pin_code = models.IntegerField(blank=False, default=None,null=True)
city_type = models.CharField(blank=False, max_length=15, choices=OFFER_CITY_TYPE) city_type = models.CharField(blank=False, max_length=15, choices=OFFER_CITY_TYPE)
compensation = models.IntegerField(blank=False) # Job - Per Year # Job Details
compensation_details = models.CharField(blank=True, max_length=200) designation = models.CharField(blank=False, max_length=25, default=None, null=True)
description = models.CharField(blank=False, max_length=200, default=None, null=True)
description_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, default=list, blank=True)
is_description_pdf = models.BooleanField(blank=False, default=False)
compensation_CTC = models.IntegerField(blank=False, default=None, null=True ) # Job - Per Year
compensation_gross = models.IntegerField(blank=False, default=None, null=True)
compensation_take_home = models.IntegerField(blank=False, default=None, null=True)
compensation_bonus = models.IntegerField(blank=True, default=None, null=True)
compensation_details = models.CharField(blank=True, max_length=200, default=None, null=True)
compensation_details_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, default=list, blank=True)
is_compensation_details_pdf = models.BooleanField(blank=False, default=False)
bond_details = models.CharField(blank=True, max_length=200)
selection_procedure_rounds = ArrayField(models.CharField(null=True, default=None, max_length=100), size=10, default=list, blank=True)
selection_procedure_details = models.CharField(blank=True, max_length=200)
selection_procedure_details_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, default=list, blank=True)
is_selection_procedure_details_pdf = models.BooleanField(blank=False, default=False)
tier = models.CharField(blank=False, choices=TIERS, max_length=10, default=None, null=True) tier = models.CharField(blank=False, choices=TIERS, max_length=10, default=None, null=True)
tentative_date_of_joining = models.DateField(blank=False, verbose_name="Tentative Date", default=timezone.now)
allowed_batch = ArrayField( allowed_batch = ArrayField(
models.CharField(max_length=10, choices=BATCH_CHOICES), models.CharField(max_length=10, choices=BATCH_CHOICES),
size=TOTAL_BATCHES, size=TOTAL_BATCHES,
default=list default=list
) )
allowed_branch = ArrayField( allowed_branch = ArrayField(
models.CharField(choices=BRANCH_CHOICES, blank=False, max_length=10), models.CharField(choices=BRANCH_CHOICES, blank=False, max_length=10),
size=TOTAL_BRANCHES, size=TOTAL_BRANCHES,
default=list default=list
) )
attachments = ArrayField( tentative_no_of_offers = models.IntegerField(blank=False, default=1)
models.CharField(max_length=100, blank=True), other_requirements = models.CharField(blank=True, max_length=200, default="")
size=10, additional_info = ArrayField(models.CharField(blank=True, max_length=200), size=15, default=list, blank=True)
blank=True email_verified = models.BooleanField(blank=False, default=False)
) offer_accepted = models.BooleanField(blank=False, default=None, null=True)
rounds = ArrayField( deadline_datetime = models.DateTimeField(blank=False, verbose_name="Deadline Date", default=two_day_after_today)
models.CharField(max_length=25, blank=True),
size=10,
)
additional_info = ArrayField(
models.CharField(max_length=25, blank=True),
size=10,
blank=True
)
status = models.CharField(max_length=50, blank=False)
rounds_details = models.JSONField(blank=True, default=dict)
created_at = models.DateTimeField(blank=False, default=None, null=True) created_at = models.DateTimeField(blank=False, default=None, null=True)
def save(self, *args, **kwargs):
''' On save, add timestamps '''
if not self.created_at:
self.created_at = timezone.now()
return super(Placement, self).save(*args, **kwargs)
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)
student = models.ForeignKey(Student, blank=False, on_delete=models.CASCADE) student = models.ForeignKey(Student, blank=False, on_delete=models.CASCADE)
resume = models.CharField(max_length=100, blank=False, null=True, default=None) resume = models.CharField(max_length=100, blank=False, null=True, default=None)
status = models.CharField(max_length=50, null=True, blank=True, default=None) additional_info = models.JSONField(blank=True, null=True, default=None)
additional_info = models.JSONField(blank=True, default=None, null=True)
selected = models.BooleanField(null=True, default=None, blank=True) selected = models.BooleanField(null=True, default=None, blank=True)
applied_at = models.DateTimeField(blank=False, default=None, null=True) applied_at = models.DateTimeField(blank=False, default=None, null=True)

View File

@ -1,56 +1,162 @@
import urllib
from rest_framework import serializers from rest_framework import serializers
from .models import * from .models import *
class StudentSerializer(serializers.ModelSerializer): class StudentSerializer(serializers.ModelSerializer):
resume_list = serializers.SerializerMethodField()
offers = serializers.SerializerMethodField()
def get_resume_list(self, obj):
links = []
for i in obj.resumes:
ele = {}
ele['link'] = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(obj.id + "/" + i)
ele['name'] = i
links.append(ele)
return links
def get_offers(self, obj):
selected_companies = PlacementApplication.objects.filter(student_id=obj.id, selected=True)
companies = []
for i in selected_companies:
ele = {}
ele['designation'] = i.placement.designation
ele['company_name'] = i.placement.company_name
ele['application_id'] = i.id
companies.append(ele)
return companies
class Meta: class Meta:
model = Student model = Student
fields = '__all__' exclude = ['resumes']
# exclude = ['id']
class PlacementSerializerForStudent(serializers.ModelSerializer):
company_details_pdf_links = serializers.SerializerMethodField()
description_pdf_links = serializers.SerializerMethodField()
compensation_pdf_links = serializers.SerializerMethodField()
selection_procedure_details_pdf_links = serializers.SerializerMethodField()
class PlacementSerializer(serializers.ModelSerializer): def get_company_details_pdf_links(self, obj):
company_details = serializers.SerializerMethodField() links =[]
for pdf_name in obj.company_details_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_description_pdf_links(self, obj):
links =[]
for pdf_name in obj.description_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_compensation_pdf_links(self, obj):
links =[]
for pdf_name in obj.compensation_details_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_selection_procedure_details_pdf_links(self, obj):
links =[]
for pdf_name in obj.selection_procedure_details_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_company_details(self, obj):
data = {
"id": obj.company.id,
"name": obj.company.name,
"address": obj.company.address,
"companyType": obj.company.companyType,
"website": obj.company.website,
}
return data
class Meta: class Meta:
model = Placement model = Placement
exclude=[COMPANY] 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]
depth = 1
class PlacementSerializerForAdmin(serializers.ModelSerializer):
company_details_pdf_links = serializers.SerializerMethodField()
description_pdf_links = serializers.SerializerMethodField()
compensation_pdf_links = serializers.SerializerMethodField()
selection_procedure_details_pdf_links = serializers.SerializerMethodField()
def get_company_details_pdf_links(self, obj):
links =[]
for pdf_name in obj.company_details_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_description_pdf_links(self, obj):
links =[]
for pdf_name in obj.description_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_compensation_pdf_links(self, obj):
links =[]
for pdf_name in obj.compensation_details_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
def get_selection_procedure_details_pdf_links(self, obj):
links =[]
for pdf_name in obj.selection_procedure_details_pdf_names:
ele = {}
link = LINK_TO_STORAGE_COMPANY_ATTACHMENT + urllib.parse.quote_plus(obj.id + "/" + pdf_name)
ele['link'] = link
ele['name'] = pdf_name
links.append(ele)
return links
class Meta:
model = Placement
exclude = [COMPANY_DETAILS_PDF_NAMES, DESCRIPTION_PDF_NAMES,
COMPENSATION_DETAILS_PDF_NAMES, SELECTION_PROCEDURE_DETAILS_PDF_NAMES]
depth = 1 depth = 1
class PlacementApplicationSerializer(serializers.ModelSerializer): class PlacementApplicationSerializer(serializers.ModelSerializer):
application_status = serializers.SerializerMethodField() placement = serializers.SerializerMethodField()
company_details = serializers.SerializerMethodField() resume_link = serializers.SerializerMethodField()
def get_placement(self, obj):
def get_application_status(self, obj): data = PlacementSerializerForStudent(obj.placement).data
if obj.status is None:
return obj.placement.status
else:
return obj.status
def get_company_details(self, obj):
data = {
"id": obj.placement.company.id,
"name": obj.placement.company.name,
"address": obj.placement.company.address,
"companyType": obj.placement.company.companyType,
"website": obj.placement.company.website,
}
return data return data
def get_resume_link(self, obj):
link = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(obj.id + "/" + obj.resume)
return link
class Meta: class Meta:
model = PlacementApplication model = PlacementApplication
exclude = ['status', 'student'] exclude = [STUDENT, 'resume']

View File

@ -1,5 +1,5 @@
import logging import json
from os import path, remove from datetime import datetime
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
@ -16,8 +16,7 @@ def login(request, id, email, user_type):
return Response({'action': "Login", 'message': "Verified", "user_type": user_type}, return Response({'action': "Login", 'message': "Verified", "user_type": user_type},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except: except:
return Response({'action': "Login", 'message': "Error Occurred {0}".format( return Response({'action': "Login", 'message': "Something Went Wrong"},
str(sys.exc_info()[1]))},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -31,7 +30,8 @@ def studentProfile(request, id, email, user_type):
return Response({'action': "Student Profile", 'message': "Details Found", "details": data}, return Response({'action': "Student Profile", 'message': "Details Found", "details": data},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except: except:
return Response({'action': "Student Profile", 'message': "Error Occurred {0}".format(str(sys.exc_info()[1]))}, logger.warning("Student Profile: " + str(sys.exc_info()))
return Response({'action': "Student Profile", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -41,20 +41,12 @@ def addResume(request, id, email, user_type):
destination_path = "" destination_path = ""
try: try:
student = get_object_or_404(Student, id=id) student = get_object_or_404(Student, id=id)
prefix = generateRandomString()
files = request.FILES files = request.FILES
file_name = prefix + "_" + files['file'].name
print(file_name)
student.resumes.append(file_name)
file = files['file'] file = files['file']
destination_path = STORAGE_DESTINATION + str(file_name) destination_path = STORAGE_DESTINATION_RESUMES + id + "/"
if path.exists(destination_path): file_name = saveFile(file, destination_path)
remove(destination_path) student.resumes.append(file_name)
with open(destination_path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
student.save() student.save()
return Response({'action': "Upload Resume", 'message': "Resume Added"}, return Response({'action': "Upload Resume", 'message': "Resume Added"},
@ -68,8 +60,7 @@ def addResume(request, id, email, user_type):
remove(destination_path) remove(destination_path)
else: else:
logger.warning("Upload Resume: " + str(sys.exc_info())) logger.warning("Upload Resume: " + str(sys.exc_info()))
return Response({'action': "Upload Resume", 'message': "Error Occurred {0}".format( return Response({'action': "Upload Resume", 'message': "Something Went Wrong"},
str(sys.exc_info()[1]))},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -81,23 +72,23 @@ 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],
status=STATUS_ACCEPTING_APPLICATIONS) deadline_datetime__gte=datetime.now(),
placementsdata = PlacementSerializer(placements, many=True).data offer_accepted=True, email_verified=True).order_by('deadline_datetime')
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': "Placement and Internships", 'message': "Data Found", "placements": placementsdata, {'action': "Get Dashboard - Student", 'message': "Data Found", "placements": placementsdata,
'placementApplication': placementApplications}, 'placementApplication': placementApplications},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404: except Http404:
return Response({'action': "Placements and Internships", 'message': 'Student Not Found'}, return Response({'action': "Get Dashboard - Student", 'message': 'Student Not Found'},
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except: except:
logger.warning("Placements and Internships: " + str(sys.exc_info())) logger.warning("Get Dashboard -Student: " + str(sys.exc_info()))
return Response({'action': "Placements and Internships", 'message': "Error Occurred {0}".format( return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"},
str(sys.exc_info()[1]))},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -108,7 +99,7 @@ def deleteResume(request, id, email, user_type):
try: try:
student = get_object_or_404(Student, id=id) student = get_object_or_404(Student, id=id)
file_name = request.data[RESUME_FILE_NAME] file_name = request.data[RESUME_FILE_NAME]
destination_path = STORAGE_DESTINATION + str(file_name) destination_path = STORAGE_DESTINATION_RESUMES + id + "/" + str(file_name)
if path.exists(destination_path): if path.exists(destination_path):
remove(destination_path) remove(destination_path)
student.resumes.remove(file_name) student.resumes.remove(file_name)
@ -125,28 +116,32 @@ def deleteResume(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except: except:
logger.warning("Delete Resume: " + str(sys.exc_info())) logger.warning("Delete Resume: " + str(sys.exc_info()))
return Response({'action': "Delete Resume", 'message': "Error Occurred {0}".format( return Response({'action': "Delete Resume", 'message': "Something Went Wrong"},
str(sys.exc_info()))},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST']) @api_view(['POST'])
@isAuthorized(allowed_users=[STUDENT]) @isAuthorized(allowed_users=[STUDENT])
@precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME, @precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME,
ADDITIONAL_INFO]) ])
def submitApplication(request, id, email, user_type): def submitApplication(request, id, email, user_type):
try: try:
data = request.data data = request.data
student = get_object_or_404(Student, id=id) student = get_object_or_404(Student, id=id)
# Only Allowing Applications for Placements
if data[OPENING_TYPE] == PLACEMENT: if data[OPENING_TYPE] == PLACEMENT:
if not len(PlacementApplication.objects.filter( if not len(PlacementApplication.objects.filter(
student_id=id, placement_id=data[OPENING_ID])): student_id=id, placement_id=data[OPENING_ID])):
application = PlacementApplication() application = PlacementApplication()
opening = get_object_or_404(Placement, id=data[OPENING_ID], opening = get_object_or_404(Placement, id=data[OPENING_ID],
status=STATUS_ACCEPTING_APPLICATIONS) allowed_batch__contains=[student.batch],
allowed_branch__contains=[student.branch],
deadline_datetime__gte=datetime.now().date()
)
if not opening.offer_accepted or not opening.email_verified:
raise PermissionError("Placement Not Approved")
cond_stat, cond_msg = PlacementApplicationConditions(student, opening) cond_stat, cond_msg = PlacementApplicationConditions(student, opening)
print(cond_stat, cond_msg)
if not cond_stat: if not cond_stat:
raise PermissionError(cond_msg) raise PermissionError(cond_msg)
application.placement = opening application.placement = opening
@ -162,21 +157,29 @@ def submitApplication(request, id, email, user_type):
application.student = student application.student = student
application.id = generateRandomString() application.id = generateRandomString()
additional_info = {}
for i in opening.additional_info: for i in opening.additional_info:
if i not in data[ADDITIONAL_INFO]: if i not in data[ADDITIONAL_INFO]:
print(i)
raise AttributeError(i + " not found in Additional Info") raise AttributeError(i + " not found in Additional Info")
else:
additional_info[i] = data[ADDITIONAL_INFO][i]
application.additional_info = data[ADDITIONAL_INFO] application.additional_info = json.dumps(additional_info)
if not sendApplicationEmail(email, student.name, opening.company.name, data[OPENING_TYPE], data = {
data[ADDITIONAL_INFO]): "name": student.name,
logger.error("Submit Application: Unable to Send Email") "company_name": opening.company_name,
# raise RuntimeError("Unable to Send Email") "application_type": data[OPENING_TYPE],
"additional_info": dict(json.loads(application.additional_info)),
}
subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
sendEmail(email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
application.save() application.save()
return Response({'action': "Submit Application", 'message': "Application Submitted"}, return Response({'action': "Submit Application", 'message': "Application Submitted"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404 as e:
return Response({'action': "Submit Application", 'message': "Student Not Found"},
status=status.HTTP_404_NOT_FOUND)
except PermissionError as e: except PermissionError as e:
return Response({'action': "Submit Application", 'message': str(e)}, return Response({'action': "Submit Application", 'message': str(e)},
status=status.HTTP_403_FORBIDDEN) status=status.HTTP_403_FORBIDDEN)
@ -185,6 +188,5 @@ 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()))
return Response({'action': "Submit Application", 'message': "Error Occurred {0}".format( return Response({'action': "Submit Application", 'message': "Something Went Wrong"},
str(sys.exc_info()[1]))},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)

View File

@ -5,6 +5,7 @@ import string
import sys import sys
from os import path, remove from os import path, remove
import background_task
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
@ -16,7 +17,8 @@ from google.oauth2 import id_token
from rest_framework import status from rest_framework import status
from rest_framework.response import Response from rest_framework.response import Response
from .models import * from .constants import *
from .models import User, PrePlacementOffer, PlacementApplication
logger = logging.getLogger('db') logger = logging.getLogger('db')
@ -78,11 +80,9 @@ def isAuthorized(allowed_users=None):
raise PermissionError("Authorization Header Not Found") raise PermissionError("Authorization Header Not Found")
except PermissionError as e: except PermissionError as e:
print(e)
return Response({'action': "Is Authorized?", 'message': str(e)}, return Response({'action': "Is Authorized?", 'message': str(e)},
status=status.HTTP_401_UNAUTHORIZED) status=status.HTTP_401_UNAUTHORIZED)
except Http404: except Http404:
print('http404')
return Response({'action': "Is Authorized?", 'message': "User Not Found. Contact CDC for more details"}, return Response({'action': "Is Authorized?", 'message': "User Not Found. Contact CDC for more details"},
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except ValueError as e: except ValueError as e:
@ -90,9 +90,10 @@ def isAuthorized(allowed_users=None):
return Response({'action': "Is Authorized?", 'message': str(e)}, return Response({'action': "Is Authorized?", 'message': str(e)},
status=status.HTTP_401_UNAUTHORIZED) status=status.HTTP_401_UNAUTHORIZED)
except: except:
return Response({'action': "Is Authorized?", 'message': "Error Occurred {0}".format( logger.warning("Is Authorized? " + str(sys.exc_info()))
str(sys.exc_info()[1]))}, return Response(
status=status.HTTP_400_BAD_REQUEST) {'action': "Is Authorized?", 'message': "Something went wrong. Contact CDC for more details"},
status=status.HTTP_400_BAD_REQUEST)
return wrapper_func return wrapper_func
@ -108,30 +109,6 @@ def generateRandomString():
return False return False
def sendApplicationEmail(email, name, company_name, applicaton_type, additional_info):
try:
subject = 'CDC - Application Submitted - ' + str(company_name)
data = {
"name": name,
"company_name": company_name,
"applicaton_type": applicaton_type,
"additional_info": additional_info
}
html_content = render_to_string('student_application_submited.html', data) # render with dynamic value
text_content = strip_tags(html_content)
email_from = settings.EMAIL_HOST_USER
recipient_list = [str(email), ]
msg = EmailMultiAlternatives(subject, text_content, email_from, recipient_list)
msg.attach_alternative(html_content, "text/html")
msg.send()
return True
except:
return False
def saveFile(file, location): def saveFile(file, location):
prefix = generateRandomString() prefix = generateRandomString()
file_name = prefix + "_" + file.name file_name = prefix + "_" + file.name
@ -139,7 +116,7 @@ def saveFile(file, location):
if not path.isdir(location): if not path.isdir(location):
os.mkdir(location) os.mkdir(location)
destination_path = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + str(file_name) destination_path = location + str(file_name)
if path.exists(destination_path): if path.exists(destination_path):
remove(destination_path) remove(destination_path)
@ -150,6 +127,7 @@ def saveFile(file, location):
return file_name return file_name
@background_task.background(schedule=10)
def sendEmail(email_to, subject, data, template): def sendEmail(email_to, subject, data, template):
try: try:
html_content = render_to_string(template, data) # render with dynamic value html_content = render_to_string(template, data) # render with dynamic value
@ -163,17 +141,18 @@ def sendEmail(email_to, subject, data, template):
msg.send() msg.send()
return True return True
except: except:
logger.error("Send Email: " + str(sys.exc_info()))
print(str(sys.exc_info()[1])) print(str(sys.exc_info()[1]))
return str(sys.exc_info()[1]) return False
def PlacementApplicationConditions(student, placement): def PlacementApplicationConditions(student, placement):
try: try:
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(internship_application__student=student, accepted=True) PPO = PrePlacementOffer.objects.filter(student=student, accepted=True)
if len(selected_companies) + len(PPO) >= 2: 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")
if len(selected_companies_PSU) > 0: if len(selected_companies_PSU) > 0:
@ -195,3 +174,41 @@ def PlacementApplicationConditions(student, placement):
print(sys.exc_info()) print(sys.exc_info())
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info())) logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
return False, "_" return False, "_"
def getTier(compensation_gross, is_psu=False):
try:
if is_psu:
return True, 'psu'
if compensation_gross < 0:
raise ValueError("Negative Compensation")
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:
print(sys.exc_info())
logger.warning("Utils - getTier: " + str(sys.exc_info()))
return False, "_"

View File

@ -41,6 +41,7 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'corsheaders', 'corsheaders',
'django_db_logger', 'django_db_logger',
'background_task'
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -160,7 +161,7 @@ EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
EMAIL_PORT = 587 EMAIL_PORT = 587
EMAIL_HOST_USER = 'saisurya3127@gmail.com'#'email here' EMAIL_HOST_USER = 'saisurya3127@gmail.com'#'email here'
EMAIL_HOST_PASSWORD = 'ehwkqmryyqjiifcz'#'password here' EMAIL_HOST_PASSWORD = 'yeylqcnsyjfpzsew'#'password here'
LOGGING = { LOGGING = {
'version': 1, 'version': 1,

View File

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="x-apple-disable-message-reformatting">
<title></title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="shortcut icon" href="favicon.ico"/>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
<style>
table, td, div, h1, p {
font-family: 'Roboto', sans-serif;
}
</style>
</head>
<body style="margin:0;padding:0;">
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#ffffff;">
<tr>
<td align="center" style="padding:0;">
<table role="presentation"
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/>
</td>
</tr>
<tr>
<td style="padding:36px 30px 42px 30px;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="padding:0 0 36px 0;color:#153643;">
<h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif;
">Thank You for filling the form</h1>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
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.
</p>
<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
feel to
write to
<nobr><u>cdc@iitdh.ac.in</u></nobr>
</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:30px;background:#334878;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;font-size:9px;font-family: 'Roboto', sans-serif;">
<tr>
<td style="padding:0;width:50%;" align="left">
<p style="margin:0;font-size:14px;line-height:16px;font-family: 'Roboto', sans-serif;color:#ffffff;">
&reg; CDC,IIT Dharwad,2021<br/>
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="x-apple-disable-message-reformatting">
<title></title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="shortcut icon" href="favicon.ico"/>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
<style>
table, td, div, h1, p {
font-family: 'Roboto', sans-serif;
}
</style>
</head>
<body style="margin:0;padding:0;">
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#ffffff;">
<tr>
<td align="center" style="padding:0;">
<table role="presentation"
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/>
</td>
</tr>
<tr>
<td style="padding:36px 30px 42px 30px;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="padding:0 0 36px 0;color:#153643;">
<h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif;
">Hey, {{ student_name }}</h1>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
We regret to inform you that you have not been selected for <b>{{ designation }}</b> role at <b>{{ company_name }}</b>.
CDC will keep bringing more such opportunities for you in the future.
</td>
</tr>
<tr>
<td style="padding:0;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="width:260px;padding:0;vertical-align:top;color:#334878;">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:30px;background:#334878;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;font-size:9px;font-family: 'Roboto', sans-serif;">
<tr>
<td style="padding:0;width:50%;" align="left">
<p style="margin:0;font-size:14px;line-height:16px;font-family: 'Roboto', sans-serif;color:#ffffff;">
&reg; CDC,IIT Dharwad,2021<br/>
</p>
</td>
</tr>
</table>
</td>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="x-apple-disable-message-reformatting">
<title></title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="shortcut icon" href="favicon.ico"/>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
<style>
table, td, div, h1, p {
font-family: 'Roboto', sans-serif;
}
</style>
</head>
<body style="margin:0;padding:0;">
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#ffffff;">
<tr>
<td align="center" style="padding:0;">
<table role="presentation"
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="./image.png" alt="" width="200" style="height:auto;display:block;"/>
</td>
</tr>
<tr>
<td style="padding:36px 30px 42px 30px;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="padding:0 0 36px 0;color:#153643;">
<h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif;
">Hey, {{ student_name }}</h1>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
Congratulations, You have been selected for the <b>{{ designation }}</b> at <b>{{ company_name }}</b>.<br>
</td>
</tr>
<tr>
<td style="padding:0;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="width:260px;padding:0;vertical-align:top;color:#334878;">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:30px;background:#334878;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;font-size:9px;font-family: 'Roboto', sans-serif;">
<tr>
<td style="padding:0;width:50%;" align="left">
<p style="margin:0;font-size:14px;line-height:16px;font-family: 'Roboto', sans-serif;color:#ffffff;">
&reg; CDC,IIT Dharwad,2021<br/>
</p>
</td>
</tr>
</table>
</td>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@ -44,7 +44,7 @@
<h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif; <h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif;
">Hello there, {{ name }}</h1> ">Hello there, {{ name }}</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 application for a <b>{{ applicaton_type }}</b> offer at <b> We have received your application for a <b>{{ application_type }}</b> offer at <b>
{{ company_name }}</b> {{ company_name }}</b>
. We received these additional details<br> . We received these additional details<br>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: <p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: