Merge pull request #57 from CDC-IITDH/many-issues-resolved

Many Issues Resolved
This commit is contained in:
CDC-IITDH 2021-12-12 19:52:07 +05:30 committed by GitHub
commit 89f96fae2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2122 additions and 391 deletions

View File

@ -1,9 +1,41 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from django.contrib import admin
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.shortcuts import resolve_url
from django.utils.html import format_html
from django.utils.safestring import SafeText
from .models import *
admin.site.register(User) admin.site.register(User)
admin.site.register(Student) # admin.site.register(Student)
admin.site.register(Admin) admin.site.register(Admin)
admin.site.register(Placement) # admin.site.register(Placement)
admin.site.register(PlacementApplication) admin.site.register(PlacementApplication)
admin.site.register(PrePlacementOffer) admin.site.register(PrePlacementOffer)
admin.site.site_header = "CDC Recruitment Portal"
def model_admin_url(obj, name=None) -> str:
url = resolve_url(admin_urlname(obj._meta, SafeText("change")), obj.pk)
return format_html('<a href="{}">{}</a>', url, name or str(obj))
@admin.register(Student)
class Student(admin.ModelAdmin):
list_display = ("roll_no", "name", "batch", "branch", "phone_number")
search_fields = ("roll_no", "name","phone_number")
ordering = ("roll_no", "name", "batch", "branch", "phone_number")
list_filter = ("batch", "branch")
@admin.register(Placement)
class Placement(admin.ModelAdmin):
list_display = (COMPANY_NAME, CONTACT_PERSON_NAME, PHONE_NUMBER, 'tier', 'compensation_CTC')
search_fields = (COMPANY_NAME, CONTACT_PERSON_NAME)
ordering = (COMPANY_NAME, CONTACT_PERSON_NAME, 'tier', 'compensation_CTC')
list_filter = ('tier',)

View File

@ -1,7 +1,15 @@
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"),
path('getApplications/', adminViews.getApplications, name="Get Applications"),
path("submitApplication/", adminViews.submitApplication, name="Submit Application"),
path('generateCSV/', adminViews.generateCSV, name="Generate CSV"),
] ]

View File

@ -0,0 +1,299 @@
import json
from datetime import datetime
from .utils import *
from rest_framework.decorators import api_view
import csv
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)
@api_view(['GET'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID])
def getApplications(request, id, email, user_type):
try:
data = request.GET
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
applications = PlacementApplication.objects.filter(placement=opening)
serializer = PlacementApplicationSerializerForAdmin(applications, many=True)
return Response({'action': "Get Applications", 'message': 'Data Found', 'applications':serializer.data},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Get Applications", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Get Applications: " + str(sys.exc_info()))
return Response({'action': "Get Applications", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized(allowed_users=[ADMIN])
@precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME,
STUDENT_ID])
def submitApplication(request, id, email, user_type):
try:
data = request.data
student = get_object_or_404(Student, roll_no=data[STUDENT_ID])
# Only Allowing Applications for Placements
if data[OPENING_TYPE] == PLACEMENT:
if not len(PlacementApplication.objects.filter(
student_id=student.id, placement_id=data[OPENING_ID])):
application = PlacementApplication()
opening = get_object_or_404(Placement, id=data[OPENING_ID],
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)
if not cond_stat:
raise PermissionError(cond_msg)
application.placement = opening
else:
raise PermissionError("Application is already Submitted")
else:
raise ValueError(OPENING_TYPE + " is Invalid")
if data[RESUME_FILE_NAME] in student.resumes:
application.resume = data[RESUME_FILE_NAME]
else:
raise FileNotFoundError(RESUME_FILE_NAME + " Not Found")
application.student = student
application.id = generateRandomString()
additional_info = {}
for i in opening.additional_info:
if i not in data[ADDITIONAL_INFO]:
raise AttributeError(i + " not found in Additional Info")
else:
additional_info[i] = data[ADDITIONAL_INFO][i]
application.additional_info = json.dumps(additional_info)
data = {
"name": student.name,
"company_name": opening.company_name,
"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)
student_email = str(student.roll_no)+"@iitdh.ac.in"
sendEmail(student_email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
application.save()
return Response({'action': "Submit Application", 'message': "Application Submitted"},
status=status.HTTP_200_OK)
except Http404 as e:
return Response({'action': "Submit Application", 'message': str(e)},
status=status.HTTP_404_NOT_FOUND)
except PermissionError as e:
return Response({'action': "Submit Application", 'message': str(e)},
status=status.HTTP_403_FORBIDDEN)
except FileNotFoundError as e:
return Response({'action': "Submit Application", 'message': str(e)},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Submit Application: " + str(sys.exc_info()))
return Response({'action': "Submit Application", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized(allowed_users=[ADMIN])
@precheck(required_data=[OPENING_ID])
def generateCSV(request, id, email, user_type):
try:
data = request.data
placement = get_object_or_404(Placement, id=data[OPENING_ID])
applications = PlacementApplication.objects.filter(placement=placement)
filename = generateRandomString()
if not os.path.isdir(STORAGE_DESTINATION_APPLICATION_CSV):
os.mkdir(STORAGE_DESTINATION_APPLICATION_CSV)
destination_path = STORAGE_DESTINATION_APPLICATION_CSV + filename + ".csv"
f = open(destination_path, 'w')
writer = csv.writer(f)
header_row = APPLICATION_CSV_COL_NAMES.copy()
header_row.extend(placement.additional_info)
writer.writerow(header_row)
for apl in applications:
row_details=[]
row_details.append(apl.applied_at)
row_details.append(apl.student.roll_no)
row_details.append(apl.student.name)
row_details.append(str(apl.student.roll_no)+"@iitdh.ac.in")
row_details.append(apl.student.phone_number)
row_details.append(apl.student.branch)
row_details.append(apl.student.batch)
row_details.append(apl.student.cpi)
link = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(apl.student.id + "/" + apl.resume)
row_details.append(link)
row_details.append(apl.selected)
for i in placement.additional_info:
row_details.append(json.loads(apl.additional_info)[i])
writer.writerow(row_details)
f.close()
file_path = LINK_TO_APPLICATIONS_CSV + urllib.parse.quote_plus(filename+".csv")
return Response({'action': "Create csv", 'message': "CSV created", 'file': file_path},
status=status.HTTP_200_OK)
except:
logger.warning("Create csv: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Create csv", 'message': "Error Occurred"},
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,105 @@ 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/"
LINK_TO_APPLICATIONS_CSV = "https://storage.googleapis.com/cdc-backend-attachments/applications-csv/"
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/'
STORAGE_DESTINATION_APPLICATION_CSV = './Storage/Application_CSV/'
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'
APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI',
'Resume', 'Selected', ]

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,178 @@
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']
class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer):
student_details = serializers.SerializerMethodField()
resume_link = serializers.SerializerMethodField()
def get_student_details(self, obj):
data = StudentSerializer(obj.student).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:
model = PlacementApplication
exclude = ['placement', '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': str(e)},
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
@ -102,36 +103,12 @@ def isAuthorized(allowed_users=None):
def generateRandomString(): def generateRandomString():
try: try:
N = 15 N = 15
res = ''.join(random.choices(string.ascii_uppercase + 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
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

@ -11,7 +11,9 @@ https://docs.djangoproject.com/en/2.2/ref/settings/
""" """
import os import os
from dotenv import load_dotenv
load_dotenv("../dev.env")
# import django_heroku # import django_heroku
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
@ -41,6 +43,7 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'corsheaders', 'corsheaders',
'django_db_logger', 'django_db_logger',
'background_task'
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -80,19 +83,15 @@ 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.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'cdc', 'NAME': os.environ.get("DB_NAME"),
'USER': 'postgres', 'USER': os.environ.get("DB_USER"),
'PASSWORD': 'root', 'PASSWORD': os.environ.get("DB_PASSWORD"),
'HOST': 'localhost', 'HOST': os.environ.get("DB_HOST"),
'PORT': '5432', 'PORT': os.environ.get("DB_PORT"),
}, },
# 'default': { # 'default': {
# 'ENGINE': 'django.db.backends.postgresql_psycopg2', # 'ENGINE': 'django.db.backends.postgresql_psycopg2',
# 'NAME': 'd84i5cbjig5rrf', # 'NAME': 'd84i5cbjig5rrf',
@ -159,8 +158,8 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com' 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 = os.environ.get("EMAIL") # 'email here'
EMAIL_HOST_PASSWORD = 'ehwkqmryyqjiifcz'#'password here' EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_PASSWORD") # 'password here'
LOGGING = { LOGGING = {
'version': 1, 'version': 1,
@ -178,6 +177,11 @@ LOGGING = {
'level': 'DEBUG', 'level': 'DEBUG',
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler' 'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
}, },
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
}
}, },
'loggers': { 'loggers': {
'db': { 'db': {
@ -187,5 +191,4 @@ LOGGING = {
} }
} }
# django_heroku.settings(locals()) # django_heroku.settings(locals())

View File

@ -1,13 +1,23 @@
# API References # API References
1. [**Common APIs**](#common-apis) 1. [**Common APIs**](#common-apis)
1. [**api/login/**](#apilogin) 1. [**api/login/**](#apilogin)
2. [**Student APIs**](#student-portal-apis) 2. [**Student APIs**](#student-portal-apis)
1. [**api/student/profile/**](#apistudentprofile) 1. [**api/student/profile/**](#apistudentprofile)
2. [**api/student/getDashboard/**](#apistudentgetdashboard) 2. [**api/student/getDashboard/**](#apistudentgetdashboard)
3. [**api/student/addResume/**](#apistudentaddresume) 3. [**api/student/addResume/**](#apistudentaddresume)
4. [**api/student/deleteResume/**](#apistudentdeleteresume) 4. [**api/student/deleteResume/**](#apistudentdeleteresume)
5. [**api/student/submitApplication/**](#apistudentsubmitapplication) 5. [**api/student/submitApplication/**](#apistudentsubmitapplication)
3. [**Common Errors**](#common-errors) 3. [**Admin APIs**](#admin-portal-apis)
1. [**api/admin/markStatus/**](#apiadminmarkstatus)
2. [**api/admin/getDashboard/**](#apiadmingetdashboard)
3. [**api/admin/updateDeadline/**](#apiadminupdatedeadline)
4. [**api/admin/updateOfferAccepted**](#apiadminupdateofferaccepted)
5. [**api/admin/updateEmailVerified**](#apiadminupdateemailverified)
6. [**api/admin/updateAdditionalInfo**](#apiadminupdateadditionalinfo)
4. [**Company APIs**](#company-portal-apis)
1. [**api/company/addPlacement/**](#apicompanyaddplacement)
5. [**Common Errors**](#common-errors)
--- ---
@ -35,19 +45,19 @@ Response is a Json with these fields
```json ```json
{ {
"action": "Login", "action": "Login",
"message": "Verified", "message": "Verified",
"user_type": [ "user_type": [
"student" "student"
] ]
} }
``` ```
- action: Tells us about the message creator<Br> - action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request. - message: Tells us what happened with our Request.
- user_type: Tells us about the role the user possess. Can have these values - user_type: Tells us about the role the user possess. Can have these values
- student - student
- Admin - Admin
### Status Codes ### Status Codes
@ -88,16 +98,26 @@ Response is a Json with these fields
"action": "Student Profile", "action": "Student Profile",
"message": "Details Found", "message": "Details Found",
"details": { "details": {
"id": "fdgdb", "id": "190010036",
"resume_list": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/resume/190010036%2F8KIOT3PW1JIS718_CSE-V-SEM.pdf",
"name": "8KIOT3PW1JIS718_CSE-V-SEM.pdf"
}
],
"offers": [
{
"designation": "Software Developer",
"company_name": "Make My Trip",
"application_id": "LLW4STE76GEJYOR"
}
],
"roll_no": 190010036, "roll_no": 190010036,
"name": "Gowtham Sai", "name": "Gowtham Sai",
"batch": "THIRD", "batch": "2019",
"branch": "CSE", "branch": "CSE",
"phone_number": 9390291911, "phone_number": 9390291911,
"resumes": [ "cpi": "9.15"
"XB85F4RIGBF5VJN_Cv-Gowtham.pdf"
],
"cpi": "9.02"
} }
} }
``` ```
@ -113,7 +133,7 @@ The possible responses for this api request are as follows
| Status Codes | Possible Messages | | Status Codes | Possible Messages |
| --------------- | ------------------------ | | --------------- | ------------------------ |
| 200 OK | `Details Found` | | 200 OK | `Details Found` |
| 400 BAD_REQUEST | `Error Occurred {error}` | | 400 BAD_REQUEST | `Something Went Wrong` |
You may see some different errors which can be seen [here](#common-errors) You may see some different errors which can be seen [here](#common-errors)
@ -121,11 +141,11 @@ You may see some different errors which can be seen [here](#common-errors)
## `api/student/getDashboard` ## `api/student/getDashboard`
This Api is used to get all the placements applicable to the student. This Api is used to get all the placements applicable to the student and his applications which he has already applied.
### How to Use? ### How to Use?
Send a `GET` request to `api/student/Dashboard`<br> Send a `GET` request to `api/student/getDashboard`<br>
Request_Body: Request_Body:
@ -136,88 +156,215 @@ Request_Body:
> Headers <br> > Headers <br>
> Authorization: "Bearer {tokenID}" > Authorization: "Bearer {tokenID}"
> Only users with `student` role can access this Api.
### Response ### Response
Response is a Json with these fields Response is a Json with these fields
```json ```json
{ {
"action": "Placement and Internships", "action": "Get Dashboard - Student",
"message": "Data Found", "message": "Data Found",
"placements": [ "placements": [
{ {
"id": "fdgdb121", "id": "Q54IRZZMC3RP8F6",
"designation": "Software Developer", "company_details_pdf_links": [
"description": "nice job", {
"start_date": "2021-06-17", "link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FI5U4RDTV0OP0EM0_2019+Student+Details+-+Total%28State+Sort%29+-+Copy.pdf",
"name": "I5U4RDTV0OP0EM0_2019 Student Details - Total(State Sort) - Copy.pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FW04JWWNNMIBX0JX_2019+Student+Details+-+Total%28State+Sort%29.pdf",
"name": "W04JWWNNMIBX0JX_2019 Student Details - Total(State Sort).pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FT1BXP98WBT9BHOR_AP0313017732021LL-Driving+Licence+-+Copy.pdf",
"name": "T1BXP98WBT9BHOR_AP0313017732021LL-Driving Licence - Copy.pdf"
}
],
"description_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FC78TE2Z67BPZ41O_CSE-V-SEM.pdf",
"name": "C78TE2Z67BPZ41O_CSE-V-SEM.pdf"
}
],
"compensation_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2F8D5OFQ46H43DD3S_module5And6Attendance.pdf",
"name": "8D5OFQ46H43DD3S_module5And6Attendance.pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FG8OU2PE919PFKSR_Print+Application11.pdf",
"name": "G8OU2PE919PFKSR_Print Application11.pdf"
}
],
"selection_procedure_details_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FDZTQQ6YBGBQ47PY_screencapture-onlinesbi-sbi-sbicollect-fsssuccessresponseredirect-htm-2021-07-19-18_",
"name": "DZTQQ6YBGBQ47PY_screencapture-onlinesbi-sbi-sbicollect-fsssuccessresponseredirect-htm-2021-07-19-18_"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FN490PUXJEEN4JZ9_screencapture-onlinesbi-sbi-sbicollect-payment-suvidhapayment-htm-2021-07-19-23_12_3",
"name": "N490PUXJEEN4JZ9_screencapture-onlinesbi-sbi-sbicollect-payment-suvidhapayment-htm-2021-07-19-23_12_3"
}
],
"company_name": "Make My Trip",
"address": "MakeMyTrip India Pvt. Ltd.5, Awagarh House, MG Road(next to Bachoomal collections)Agra (UP), - 282002India",
"company_type": "Private Sector",
"nature_of_business": "Technology",
"website": "www.makemytrip.com",
"company_details": "This s a very nice company",
"is_company_details_pdf": true,
"city": "Mumbai", "city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"pin_code": 530013,
"city_type": "Domestic", "city_type": "Domestic",
"compensation": 1200000, "designation": "Software Developer",
"compensation_details": "", "description": "very nice job",
"is_description_pdf": true,
"compensation_CTC": 1200000,
"compensation_gross": 1100000,
"compensation_take_home": 1000000,
"compensation_bonus": 10000,
"compensation_details": "very good compensation",
"is_compensation_details_pdf": true,
"bond_details": "nil",
"selection_procedure_rounds": [
"Resume Shortlisting",
"Technical Interview",
"HR Interview"
],
"selection_procedure_details": "All rounds are complusory",
"is_selection_procedure_details_pdf": true,
"tier": "4",
"tentative_date_of_joining": "2022-01-15",
"allowed_batch": [ "allowed_batch": [
"THIRD", "2018",
"FOURTH" "2019"
], ],
"allowed_branch": [ "allowed_branch": [
"CSE", "CSE",
"EE", "EE"
"ME"
],
"attachments": [],
"rounds": [
"Resume Shortlisting",
"Technical Test",
"Interview"
], ],
"tentative_no_of_offers": 5,
"other_requirements": "above 8 cpi",
"additional_info": [ "additional_info": [
"school", "School",
"place of study", "Home Town"
"language"
], ],
"status": "Resume Shortlisting", "deadline_date": "2021-12-04",
"rounds_details": { "created_at": "2021-12-02T20:12:21+05:30"
"Interview": "One -to-One interview",
"Technical Test": "Online Technical test which will be monitored remotely",
"Resume Shortlisting": "Resume will be seen"
},
"company_details": {
"id": "fdgdb",
"name": "Apple",
"address": "California",
"companyType": "Technology",
"website": ""
}
} }
], ],
"placementApplication": [ "placementApplication": [
{ {
"id": "dsdads", "id": "LLW4STE76GEJYOR",
"application_status": "Resume Shortlisting", "placement": {
"resume": "XB85F4RIGBF5VJN_Cv-Gowtham.pdf", "id": "Q54IRZZMC3RP8F6",
"additional_info": { "company_details_pdf_links": [
"school": "Delhi Public School", {
"language": "Telugu", "link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FI5U4RDTV0OP0EM0_2019+Student+Details+-+Total%28State+Sort%29+-+Copy.pdf",
"place of study": "Visakhapatnam" "name": "I5U4RDTV0OP0EM0_2019 Student Details - Total(State Sort) - Copy.pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FW04JWWNNMIBX0JX_2019+Student+Details+-+Total%28State+Sort%29.pdf",
"name": "W04JWWNNMIBX0JX_2019 Student Details - Total(State Sort).pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FT1BXP98WBT9BHOR_AP0313017732021LL-Driving+Licence+-+Copy.pdf",
"name": "T1BXP98WBT9BHOR_AP0313017732021LL-Driving Licence - Copy.pdf"
}
],
"description_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FC78TE2Z67BPZ41O_CSE-V-SEM.pdf",
"name": "C78TE2Z67BPZ41O_CSE-V-SEM.pdf"
}
],
"compensation_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2F8D5OFQ46H43DD3S_module5And6Attendance.pdf",
"name": "8D5OFQ46H43DD3S_module5And6Attendance.pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FG8OU2PE919PFKSR_Print+Application11.pdf",
"name": "G8OU2PE919PFKSR_Print Application11.pdf"
}
],
"selection_procedure_details_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FDZTQQ6YBGBQ47PY_screencapture-onlinesbi-sbi-sbicollect-fsssuccessresponseredirect-htm-2021-07-19-18_",
"name": "DZTQQ6YBGBQ47PY_screencapture-onlinesbi-sbi-sbicollect-fsssuccessresponseredirect-htm-2021-07-19-18_"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FN490PUXJEEN4JZ9_screencapture-onlinesbi-sbi-sbicollect-payment-suvidhapayment-htm-2021-07-19-23_12_3",
"name": "N490PUXJEEN4JZ9_screencapture-onlinesbi-sbi-sbicollect-payment-suvidhapayment-htm-2021-07-19-23_12_3"
}
],
"company_name": "Make My Trip",
"address": "MakeMyTrip India Pvt. Ltd.5, Awagarh House, MG Road(next to Bachoomal collections)Agra (UP), - 282002India",
"company_type": "Private Sector",
"nature_of_business": "Technology",
"website": "www.makemytrip.com",
"company_details": "This s a very nice company",
"is_company_details_pdf": true,
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"pin_code": 530013,
"city_type": "Domestic",
"designation": "Software Developer",
"description": "very nice job",
"is_description_pdf": true,
"compensation_CTC": 1200000,
"compensation_gross": 1100000,
"compensation_take_home": 1000000,
"compensation_bonus": 10000,
"compensation_details": "very good compensation",
"is_compensation_details_pdf": true,
"bond_details": "nil",
"selection_procedure_rounds": [
"Resume Shortlisting",
"Technical Interview",
"HR Interview"
],
"selection_procedure_details": "All rounds are complusory",
"is_selection_procedure_details_pdf": true,
"tier": "4",
"tentative_date_of_joining": "2022-01-15",
"allowed_batch": [
"2018",
"2019"
],
"allowed_branch": [
"CSE",
"EE"
],
"tentative_no_of_offers": 5,
"other_requirements": "above 8 cpi",
"additional_info": [
"School",
"Home Town"
],
"deadline_date": "2021-12-04",
"created_at": "2021-12-02T20:12:21+05:30"
}, },
"resume_link": "https://storage.googleapis.com/cdc-backend-attachments/resume/LLW4STE76GEJYOR%2F8KIOT3PW1JIS718_CSE-V-SEM.pdf",
"additional_info": "{\"School\": \"Narayana English Medium High School\", \"Home Town\": \"Vizag\"}",
"selected": null, "selected": null,
"placement": "fdgdb121" "applied_at": "2021-12-02T21:58:18.032466+05:30"
} }
] ]
} }
``` ```
- action: Tells us about the message creator<Br> - action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request. - message: Tells us what happened with our Request.
- placements: Has the placements data. - placements: Array of Placement Objects
- internships: Has the internships data. - placementApplication: Array of Placement Application Objects
- application_status: Can have many names
- Accepting Applications
- One of the Round Names
- Completed
- selected: Can take three Values
- null: Student is still in the Selection process
- true: Student is Selected
- false: Student is not selected
### Status Codes ### Status Codes
@ -225,8 +372,9 @@ The possible responses for this api request are as follows
| Status Codes | Possible Messages | | Status Codes | Possible Messages |
| --------------- | ------------------------ | | --------------- | ------------------------ |
| 200 OK | `Resume Added` | | 200 OK | `Data Found` |
| 400 BAD_REQUEST | `Error Occurred {error}` | | 404 Not Found | `Student Not Found` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You can see some common errors [here](#common-errors) You can see some common errors [here](#common-errors)
@ -331,7 +479,7 @@ You can see some common errors [here](#common-errors)
## `api/student/submitApplication/` ## `api/student/submitApplication/`
This Api is used to submit application to Internships/Placements. This Api is used to submit application to Placements.
### How to Use? ### How to Use?
@ -343,24 +491,23 @@ Request_Body:
```json ```json
{ {
"opening_type": "Placement", "opening_type": "Placement",
"opening_id": "fgervsdgdsf", "opening_id": "Q54IRZZMC3RP8F6",
"resume_file_name": "1FYE0PQZZ508HR6_Resume for Google STEP.pdf", "resume_file_name": "8KIOT3PW1JIS718_CSE-V-SEM.pdf",
"additional_info": { "additional_info": {
"school": "Narayana English Medium", "School": "Narayana English Medium High School",
"place of study": "Vizag", "Home Town": "Vizag"
"language": "Telugu" }
}
} }
``` ```
> Headers <br> > Headers <br>
> Authorization: "Bearer {tokenID}" > Authorization: "Bearer {tokenID}"
- opening_type: Can be Placement/Internship - opening_type: Can be Placement
- opening_id: Opening Id unique to each opening. - opening_id: Opening Id unique to each opening.
- additional_info: This is the info which the Internship/Placement demands besides the normal user data which has to - additional_info: This is the info which the Placement demands besides the normal user data which has to
asked and sent. These fields can be found in the Internship Details. asked and sent. These fields can be found in the Placement Details.
### Response ### Response
@ -384,12 +531,559 @@ The possible responses for this api request are as follows
| ------------- | ---------------------------------- | | ------------- | ---------------------------------- |
| 200 OK | `Application Submitted` | | 200 OK | `Application Submitted` |
| 403 FORBIDDEN | `Application is already Submitted` | | 403 FORBIDDEN | `Application is already Submitted` |
| 403 FORBIDDEN | `Placement Not Approved` |
| 404 NOT FOUND | `RESUME_FILE_NAME Not Found` | | 404 NOT FOUND | `RESUME_FILE_NAME Not Found` |
You can see some common errors [here](#common-errors) You can see some common errors [here](#common-errors)
--- ---
# Admin Portal APIs
## `api/admin/markStatus`
This Api is used to mark the status for application for a specific placement.
### How to Use?
Send a `POST` request to `api/admin/markStatus`<br>
Request_Body:
```json
{
"opening_id": "Q54IRZZMC3RP8F6",
"student_list": [
{
"student_id":"190010036",
"student_selected":"true"
},
{
"student_id":"190050022",
"student_selected":"false"
}
]
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
### Response
Response is a Json with these fields
```json
{
"action": "Mark Status",
"message": "Marked Status"
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Marked Status` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You may see some different errors which can be seen [here](#common-errors)
---
## `api/admin/getDashboard`
This Api is used to get all the placements.
### How to Use?
Send a `GET` request to `api/admin/getdashboard`<br>
Request_Body:
```json
{}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
### Response
Response is a Json with these fields
```json
{
"action": "Get Dashboard - Admin",
"message": "Data Found",
"ongoing": [
{
"id": "Q54IRZZMC3RP8F6",
"company_details_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FI5U4RDTV0OP0EM0_2019+Student+Details+-+Total%28State+Sort%29+-+Copy.pdf",
"name": "I5U4RDTV0OP0EM0_2019 Student Details - Total(State Sort) - Copy.pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FW04JWWNNMIBX0JX_2019+Student+Details+-+Total%28State+Sort%29.pdf",
"name": "W04JWWNNMIBX0JX_2019 Student Details - Total(State Sort).pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FT1BXP98WBT9BHOR_AP0313017732021LL-Driving+Licence+-+Copy.pdf",
"name": "T1BXP98WBT9BHOR_AP0313017732021LL-Driving Licence - Copy.pdf"
}
],
"description_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FC78TE2Z67BPZ41O_CSE-V-SEM.pdf",
"name": "C78TE2Z67BPZ41O_CSE-V-SEM.pdf"
}
],
"compensation_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2F8D5OFQ46H43DD3S_module5And6Attendance.pdf",
"name": "8D5OFQ46H43DD3S_module5And6Attendance.pdf"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FG8OU2PE919PFKSR_Print+Application11.pdf",
"name": "G8OU2PE919PFKSR_Print Application11.pdf"
}
],
"selection_procedure_details_pdf_links": [
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FDZTQQ6YBGBQ47PY_screencapture-onlinesbi-sbi-sbicollect-fsssuccessresponseredirect-htm-2021-07-19-18_",
"name": "DZTQQ6YBGBQ47PY_screencapture-onlinesbi-sbi-sbicollect-fsssuccessresponseredirect-htm-2021-07-19-18_"
},
{
"link": "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/Q54IRZZMC3RP8F6%2FN490PUXJEEN4JZ9_screencapture-onlinesbi-sbi-sbicollect-payment-suvidhapayment-htm-2021-07-19-23_12_3",
"name": "N490PUXJEEN4JZ9_screencapture-onlinesbi-sbi-sbicollect-payment-suvidhapayment-htm-2021-07-19-23_12_3"
}
],
"company_name": "Make My Trip",
"address": "MakeMyTrip India Pvt. Ltd.5, Awagarh House, MG Road(next to Bachoomal collections)Agra (UP), - 282002India",
"company_type": "Private Sector",
"nature_of_business": "Technology",
"website": "www.makemytrip.com",
"company_details": "This s a very nice company",
"is_company_details_pdf": true,
"contact_person_name": "Gowtham",
"phone_number": 9390291911,
"email": "saisurya3127@gmail.com",
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"pin_code": 530013,
"city_type": "Domestic",
"designation": "Software Developer",
"description": "very nice job",
"is_description_pdf": true,
"compensation_CTC": 1200000,
"compensation_gross": 1100000,
"compensation_take_home": 1000000,
"compensation_bonus": 10000,
"compensation_details": "very good compensation",
"is_compensation_details_pdf": true,
"bond_details": "nil",
"selection_procedure_rounds": [
"Resume Shortlisting",
"Technical Interview",
"HR Interview"
],
"selection_procedure_details": "All rounds are complusory",
"is_selection_procedure_details_pdf": true,
"tier": "4",
"tentative_date_of_joining": "2022-01-15",
"allowed_batch": [
"2018",
"2019"
],
"allowed_branch": [
"CSE",
"EE"
],
"tentative_no_of_offers": 5,
"other_requirements": "above 8 cpi",
"additional_info": [
"School",
"Home Town"
],
"email_verified": false,
"offer_accepted": null,
"deadline_date": "2021-12-04",
"created_at": "2021-12-02T20:12:21+05:30"
}
],
"previous": []
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
- ongoing: Gives us the list of placements that are accepting applications.
- previous: Gives us the list of placements that stopped accepting applications.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Data Found` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You can see some common errors [here](#common-errors)
---
## `api/admin/updateDeadline`
This Api is used to update deadline for a specific placement.
### How to Use?
Send a `POST` request to `api/admin/updateDeadline`<br>
Request_Body:
```json
{
"opening_id": "Q54IRZZMC3RP8F6",
"deadline_datetime": "2021-12-06 16:28:18 +0530"
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
### Response
Response is a Json with these fields
```json
{
"action": "Update Deadline",
"message": "Deadline Updated"
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Deadline Updated` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You may see some different errors which can be seen [here](#common-errors)
---
## `api/admin/updateOfferAccepted`
This Api is used to update offer verification state for a specific placement.
### How to Use?
Send a `POST` request to `api/admin/updateOfferAccepted`<br>
Request_Body:
```json
{
"opening_id": "Q54IRZZMC3RP8F6",
"offer_accepted": "true"
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
### Response
Response is a Json with these fields
```json
{
"action": "Update Offer Accepted",
"message": "Offer Accepted Updated"
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Update Offer Accepted` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You may see some different errors which can be seen [here](#common-errors)
---
## `api/admin/updateEmailVerified`
This Api is used to update email verification state for a specific placement.
### How to Use?
Send a `POST` request to `api/admin/updateEmailVerified`<br>
Request_Body:
```json
{
"opening_id": "Q54IRZZMC3RP8F6",
"email_verified": "false"
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
### Response
Response is a Json with these fields
```json
{
"action": "Update Email Verified",
"message": "Email Verified Updated"
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Email Verified Updated` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You may see some different errors which can be seen [here](#common-errors)
---
## `api/admin/updateAdditionalInfo`
This Api is used to update additional_info for a specific placement.
### How to Use?
Send a `POST` request to `api/admin/updateAdditionalInfo`<br>
Request_Body:
```json
{
"opening_id": "Q54IRZZMC3RP8F6",
"additional_info": [
"School",
"Place of Living",
"Research Interests"
]
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
### Response
Response is a Json with these fields
```json
{
"action": "Update Additional Info",
"message": "Additional Info Updated"
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Additional Info Updated` |
| 400 BAD_REQUEST | `Something Went Wrong` |
You may see some different errors which can be seen [here](#common-errors)
---
# Company Portal APIs
## `api/company/addPlacement/`
This Api is used to add placements.
### How to Use?
Send a `POST` request to `api/company/addPlacement`<br>
Request_Body:
```json
{
"company_name": [
"Make My Trip"
],
"address": [
"MakeMyTrip India Pvt. Ltd.\n5, Awagarh House, MG Road\n(next to Bachoomal collections)\nAgra (UP), - 282002\nIndia"
],
"company_type": [
"Private Sector"
],
"nature_of_business": [
"Technology"
],
"website": [
"www.makemytrip.com"
],
"company_details": [
"This s a very nice company"
],
"is_company_details_pdf": [
"true"
],
"contact_person_name": [
"Gowtham"
],
"phone_number": [
"9390291911"
],
"email": [
"saisurya3127@gmail.com"
],
"city": [
"Mumbai"
],
"state": [
"Maharashtra"
],
"country": [
"India"
],
"pincode": [
"530013"
],
"designation": [
"Software Developer"
],
"description": [
"very nice job"
],
"is_description_pdf": [
"true"
],
"compensation_ctc": [
"1200000"
],
"compensation_gross": [
"1100000"
],
"compensation_take_home": [
"1000000"
],
"compensation_bonus": [
"10000"
],
"compensation_details": [
"very good compensation"
],
"is_compensation_details_pdf": [
"true"
],
"bond_details": [
"nil"
],
"selection_procedure_rounds": [
"['Resume Shortlisting', 'Technical Interview', 'HR Interview']"
],
"selection_procedure_details": [
"All rounds are complusory"
],
"is_selection_procedure_details_pdf": [
"true"
],
"tentative_date_of_joining": [
"15-01-2022"
],
"allowed_branch": [
"['CSE', 'EE']"
],
"tentative_no_of_offers": [
"5"
],
"other_requirements": [
"above 8 cpi"
],
"company_details_pdf": [
"__FILE_OBJECT__",
"__FILE_OBJECT__"
],
"description_pdf": [
"__FILE_OBJECT__"
],
"compensation_details_pdf": [
"__FILE_OBJECT__"
],
"selection_procedure_details_pdf": [
"__FILE_OBJECT__",
"__FILE_OBJECT__"
]
}
```
### Response
Response is a Json with these fields
```json
{
"action": "Add Placement",
"message": "Placement Added Successfully"
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
### Status Codes
The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| ------------- | ----------------- |
| 200 OK | `Placement Added Successfully` |
| 404 NOT FOUND | `Something went wrong` |
You can see some common errors [here](#common-errors)
---
## `Common Errors` ## `Common Errors`
Some common errors that you may see while accessing the Apis Some common errors that you may see while accessing the Apis
@ -400,4 +1094,9 @@ Some common errors that you may see while accessing the Apis
| 401 UNAUTHORIZED | `Access Denied. You are not allowed to use this service` | Your may not have required access to those access those Apis. | | 401 UNAUTHORIZED | `Access Denied. You are not allowed to use this service` | Your may not have required access to those access those Apis. |
| 401 UNAUTHORIZED | `Token has wrong audience` | You may be using wrong credentials for Google OAuth2.0. | | 401 UNAUTHORIZED | `Token has wrong audience` | You may be using wrong credentials for Google OAuth2.0. |
| 404 NOT FOUND | `User Not Found. Contact CDC for more details` | You may not be a user at CDC, IIT Dharwad. Please contact us to get your user account | | 404 NOT FOUND | `User Not Found. Contact CDC for more details` | You may not be a user at CDC, IIT Dharwad. Please contact us to get your user account |
| 400 BAD_REQUEST | `Error Occurred {error}` | Any random Error which can be seen in the {error} string. | | 400 BAD_REQUEST | `Error Occurred` | Any random Error which can be seen in the {error} string. |
| 400 BAD_REQUEST | `Something went wrong` | Any random Error which can be seen in the {error} string. |

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:

View File

@ -37,3 +37,5 @@
### API Reference ### API Reference
Check [here](./CDC_Backend/README.md) for Api Reference Check [here](./CDC_Backend/README.md) for Api Reference
For Documentation with Postman Collection, click [here](https://documenter.getpostman.com/view/15531322/UVJfhuhQ#568ad036-ad0e-449a-a26f-4d86616b1393)

10
dev.env Normal file
View File

@ -0,0 +1,10 @@
HOSTING_URL=http://localhost:8000/
DEBUG=True
EMAIL=saisurya3127@gmail.com
EMAIL_PASSWORD=yeylqcnsyjfpzsew
SECRET_KEY=%2e!&f6(ib^690y48z=)&w6fczhwukzzp@3y*^*7u+7%4s-mie
DB_NAME=cdc
DB_USER=postgres
DB_PASSWORD=root
DB_HOST=localhost
DB_PORT=5432

92
nginx.conf Executable file
View File

@ -0,0 +1,92 @@
#user nobody;
worker_processes 1;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# Server static files /storage
location /storage {
alias '/home/gowtham/Gowtham/Shared Projects/cdc-placement-website-backend/CDC_Backend/Storage';
# autoindex on;
}
location /static {
# autoindex on;
alias '/home/gowtham/Gowtham/Shared Projects/cdc-placement-website-backend/CDC_Backend/static';
}
location /api/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
location /admin/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

View File

@ -1,36 +1,40 @@
asgiref==3.4.1 asgiref==3.4.1
astroid==2.9.0 astroid==2.9.0
cachetools==4.2.4 cachetools==4.2.4
certifi==2021.10.8 certifi==2021.10.8
chardet==4.0.0 chardet==4.0.0
charset-normalizer==2.0.8 charset-normalizer==2.0.9
colorama==0.4.4 colorama==0.4.4
dj-database-url==0.5.0 dj-database-url==0.5.0
Django==4.0 Django==3.2.10
django-background-tasks==1.2.5 django-background-tasks==1.2.5
django-compat==1.0.15 django-compat==1.0.15
django-cors-headers==3.10.1 django-cors-headers==3.10.1
django-db-logger==0.1.11 django-db-logger==0.1.11
djangorestframework==3.12.4 djangorestframework==3.12.4
google-auth==2.3.3 google-auth==2.3.3
idna==3.3 gunicorn==20.1.0
isort==5.10.1 idna==3.3
jsonfield==3.1.0 importlib-metadata==4.8.2
lazy-object-proxy==1.6.0 isort==5.10.1
Markdown==3.3.6 jsonfield==3.1.0
mccabe==0.6.1 lazy-object-proxy==1.6.0
platformdirs==2.4.0 Markdown==3.3.6
psycopg2==2.9.2 mccabe==0.6.1
pyasn1==0.4.8 platformdirs==2.4.0
pyasn1-modules==0.2.8 psycopg2-binary==2.9.2
pylint==2.12.2 pyasn1==0.4.8
pytz==2021.3 pyasn1-modules==0.2.8
requests==2.26.0 pylint==2.12.2
rsa==4.8 python-dotenv==0.19.2
six==1.16.0 pytz==2021.3
sqlparse==0.4.2 requests==2.26.0
toml==0.10.2 rsa==4.8
typing-extensions==4.0.0 six==1.16.0
urllib3==1.26.7 sqlparse==0.4.2
whitenoise==5.3.0 toml==0.10.2
wrapt==1.13.3 typing_extensions==4.0.1
urllib3==1.26.7
whitenoise==5.3.0
wrapt==1.13.3
zipp==3.6.0

22
setup.sh Normal file
View File

@ -0,0 +1,22 @@
python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt
echo "Environment setup complete"
cd CDC_Backend
python3 manage.py flush --no-input
python3 manage.py makemigrations
python3 manage.py migrate
echo "Migrations complete"
python3 manage.py collectstatic --noinput
DIR="./Storage"
if [ -d "$DIR" ]; then
### Take action if $DIR exists ###
echo "${DIR} Directory already exists"
else
### Control will jump here if $DIR does NOT exists ###
echo "Creating ${DIR} Directory..."
mkdir ${DIR}
echo "${DIR} Directory Created"
fi