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 1da9ae2d11
20 changed files with 2112 additions and 391 deletions

View File

@ -1,9 +1,41 @@
from django.contrib import admin
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(Student)
# admin.site.register(Student)
admin.site.register(Admin)
admin.site.register(Placement)
# admin.site.register(Placement)
admin.site.register(PlacementApplication)
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 . import companyViews
from . import adminViews
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 = [
path('addOpening/', companyViews.addOpening, name="Add Opening"),
path('addPlacement/', companyViews.addPlacement, name="Add Placement"),
]

View File

@ -1,120 +1,222 @@
import json
from datetime import datetime
from django.utils.timezone import make_aware
from rest_framework.decorators import api_view
from .models import *
from .utils import *
logger = logging.getLogger('db')
@api_view(['POST'])
@precheck([DESIGNATION, DESCRIPTION, OPENING_TYPE, CITY, CITY_TYPE,
COMPENSATION, COMPENSATION_DETAILS, ALLOWED_BATCH, ALLOWED_BRANCH,
ROUNDS, CO_OP, START_DATE, ADDITIONAL_INFO,
DURATION, ROUND_DETAILS])
def addOpening(request):
@precheck([COMPANY_NAME, ADDRESS, COMPANY_TYPE, NATURE_OF_BUSINESS, WEBSITE, COMPANY_DETAILS, IS_COMPANY_DETAILS_PDF,
CONTACT_PERSON_NAME, PHONE_NUMBER, EMAIL, CITY, STATE, COUNTRY, PINCODE, DESIGNATION, DESCRIPTION,
IS_DESCRIPTION_PDF,
COMPENSATION_CTC, COMPENSATION_GROSS, COMPENSATION_TAKE_HOME, COMPENSATION_BONUS, COMPENSATION_DETAILS,
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:
data = request.data
if data[OPENING_TYPE] == "Placement":
opening = Placement()
else:
raise ValueError("Invalid Opening Type")
files = request.FILES
opening = Placement()
opening.id = generateRandomString()
# Create Company object here for every Opening
# Some new code above
if data[DESIGNATION] != "":
opening.designation = data[DESIGNATION]
# Add a company details in the opening
opening.company_name = data[COMPANY_NAME]
opening.address = data[ADDRESS]
opening.company_type = data[COMPANY_TYPE]
opening.nature_of_business = data[NATURE_OF_BUSINESS]
opening.website = data[WEBSITE]
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:
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]
if data[START_DATE] != "":
opening.description = data[START_DATE]
# Check if is_description_pdf is boolean
if data[IS_DESCRIPTION_PDF] == "true":
opening.is_description_pdf = True
elif data[IS_DESCRIPTION_PDF] == "false":
opening.is_description_pdf = False
else:
raise ValueError(START_DATE + " Not Found")
if data[START_DATE] != "":
opening.start_date = datetime.strptime(data[START_DATE], '%d-%m-%Y')
raise ValueError('Invalid value for is_description_pdf')
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:
raise ValueError(START_DATE + " Not Found")
if data[CITY] != "":
opening.city = data[CITY]
raise ValueError('Compensation CTC must be an integer')
# 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:
raise ValueError(CITY + " Not Found")
if data[CITY_TYPE] != "":
opening.city_type = data[CITY_TYPE]
raise ValueError('Compensation Gross must be an integer')
# 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:
raise ValueError(CITY_TYPE + " Not Found")
if data[COMPENSATION] != "":
opening.compensation = data[COMPENSATION]
raise ValueError('Compensation Take Home must be an integer')
# 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:
raise ValueError(COMPENSATION + " Not Found")
raise ValueError('Compensation Bonus must be an integer')
opening.compensation_details = data[COMPENSATION_DETAILS]
if data[ALLOWED_BATCH] != "":
if set(json.loads(data[ALLOWED_BATCH])).issubset(BATCHES):
opening.allowed_batch = json.loads(data[ALLOWED_BATCH])
else:
raise ValueError(ALLOWED_BATCH + " is Invalid")
# Check if is_compensation_details_pdf is boolean
if data[IS_COMPENSATION_DETAILS_PDF] == "true":
opening.is_compensation_details_pdf = True
elif data[IS_COMPENSATION_DETAILS_PDF] == "false":
opening.is_compensation_details_pdf = False
else:
raise ValueError(ALLOWED_BATCH + " Not Found")
if data[ALLOWED_BRANCH] != "":
if set(json.loads(data[ALLOWED_BRANCH])).issubset(BRANCHES):
opening.allowed_branch = json.loads(data[ALLOWED_BRANCH])
else:
raise ValueError(ALLOWED_BATCH + " is Invalid")
raise ValueError('Invalid value for is_compensation_details_pdf')
if opening.is_compensation_details_pdf:
compensation_details_pdf = []
for file in files.getlist(COMPENSATION_DETAILS_PDF):
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:
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())
files = request.FILES.getlist(ATTACHMENTS)
attachments = []
for file in files:
attachments.append(saveFile(file, STORAGE_DESTINATION_COMPANY_ATTACHMENTS))
# Check if tentative_no_of_offers is integer
if data[TENTATIVE_NO_OF_OFFERS].isdigit():
opening.tentative_no_of_offers = int(data[TENTATIVE_NO_OF_OFFERS])
else:
raise ValueError('Tentative No Of Offers must be an integer')
opening.other_requirements = data[OTHER_REQUIREMENTS]
opening.attachments = attachments
opening.save()
data = {
"designation": opening.designation,
"opening_type": data[OPENING_TYPE],
"opening_link": "google.com", # Some Changes here too
"company_name": opening.company.name
"opening_type": PLACEMENT,
"opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too
"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'
# 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"},
return Response({'action': "Add Placement", 'message': "Placement Added Successfully"},
status=status.HTTP_200_OK)
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)
except:
logger.warning("Add New Opening: " + str(sys.exc_info()))
return Response({'action': "Add Opening", 'message': "Error Occurred {0}".format(
str(sys.exc_info()[1]))},
logger.warning("Add New Placement: " + str(sys.exc_info()))
return Response({'action': "Add Placement", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -1,14 +1,20 @@
BRANCH_CHOICES = [
["CSE", "CSE"],
["EE", "EE"],
["ME", "ME"]
["ME", "ME"],
['EP', 'EP'],
]
BRANCHES = [
"CSE",
"EE",
"ME",
"EP"
]
BATCH_CHOICES = [
["FIRST", "First"],
["SECOND", "Second"],
["THIRD", "Third"],
["FOURTH", "Fourth"]
["2021", "2021"],
["2020", "2020"],
["2019", "2019"],
["2018", "2018"]
]
OFFER_CITY_TYPE = [
@ -26,70 +32,105 @@ TIERS = [
['6', 'Tier 6']
]
TOTAL_BRANCHES = 3 # Total No of Branches
TOTAL_BRANCHES = 4 # Total No of Branches
TOTAL_BATCHES = 4 # Total No of Batches
# To be Configured Properly
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"
EMAIL = "email"
STUDENT = 'student'
ADMIN = 'Admin'
ADMIN = 'admin'
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_APPLICATION_CSV = './Storage/Application_CSV/'
RESUME_FILE_NAME = 'resume_file_name'
APPLICATION_ID = "application_id"
OPENING_ID = "opening_id"
STUDENT_ID = "student_id"
ADDITIONAL_INFO = "additional_info"
STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications"
PLACEMENT = "Placement"
COMPANY_WEBSITE = 'website'
COMPANY_ADDRESS = 'address'
COMPANY_NAME = "company_name"
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'
CONTACT_PERSON_NAME = 'contact_person_name'
CITY = 'city'
STATE = 'state'
COUNTRY = 'country'
PINCODE = 'pincode'
DESIGNATION = 'designation'
DESCRIPTION = 'description'
DESCRIPTION_PDF = 'description_pdf'
DESCRIPTION_PDF_NAMES = 'description_pdf_names'
IS_DESCRIPTION_PDF = 'is_description_pdf'
OPENING_TYPE = 'opening_type'
CITY = 'city'
CITY_TYPE = 'city_type'
COMPENSATION = 'compensation'
COMPENSATION_CTC = 'compensation_ctc'
COMPENSATION_GROSS = 'compensation_gross'
COMPENSATION_TAKE_HOME = 'compensation_take_home'
COMPENSATION_BONUS = 'compensation_bonus'
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_BRANCH = 'allowed_branch'
ATTACHMENTS = 'attachments'
ROUNDS = 'rounds'
ROUND_DETAILS = 'round_details'
DURATION = 'duration'
CO_OP = 'co_op'
START_DATE = "start_date"
BOND_DETAILS = 'bond_details'
SELECTION_PROCEDURE_ROUNDS = 'selection_procedure_rounds'
SELECTION_PROCEDURE_DETAILS = 'selection_procedure_details'
SELECTION_PROCEDURE_DETAILS_PDF = 'selection_procedure_details_pdf'
SELECTION_PROCEDURE_DETAILS_PDF_NAMES = 'selection_procedure_details_pdf_names'
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_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"
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'
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.utils import timezone
from .constants import *
# from .utils import *
class User(models.Model):
@ -26,58 +28,80 @@ class Admin(models.Model):
name = models.CharField(blank=False, max_length=50)
def two_day_after_today():
return timezone.now() + timezone.timedelta(days=2)
class Placement(models.Model):
id = models.CharField(blank=False, primary_key=True, max_length=15)
name = models.CharField(blank=False, max_length=50, default="")
address = models.CharField(blank=False, max_length=150, default="")
companyType = models.CharField(blank=False, max_length=50, default="")
website = models.CharField(blank=True, max_length=50, default="")
contact_person_name = models.CharField(blank=False, max_length=50, default="")
phone_number = models.PositiveBigIntegerField(blank=False, default=0)
designation = models.CharField(blank=False, max_length=25, default=None, null=True)
description = models.CharField(blank=False, max_length=200)
start_date = models.DateField(blank=False, verbose_name="Start Date")
# Company Details
company_name = models.CharField(blank=False, max_length=50)
address = models.CharField(blank=False, max_length=150)
company_type = models.CharField(blank=False, max_length=50)
nature_of_business = models.CharField(blank=False, max_length=50, default="")
website = models.CharField(blank=True, max_length=50)
company_details = models.CharField(blank=False, max_length=500, default=None, null=True)
company_details_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, default=list, blank=True)
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="")
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)
compensation = models.IntegerField(blank=False) # Job - Per Year
compensation_details = models.CharField(blank=True, max_length=200)
# Job Details
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)
tentative_date_of_joining = models.DateField(blank=False, verbose_name="Tentative Date", default=timezone.now)
allowed_batch = ArrayField(
models.CharField(max_length=10, choices=BATCH_CHOICES),
size=TOTAL_BATCHES,
default=list
)
allowed_branch = ArrayField(
models.CharField(choices=BRANCH_CHOICES, blank=False, max_length=10),
size=TOTAL_BRANCHES,
default=list
)
attachments = ArrayField(
models.CharField(max_length=100, blank=True),
size=10,
blank=True
)
rounds = ArrayField(
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)
tentative_no_of_offers = models.IntegerField(blank=False, default=1)
other_requirements = models.CharField(blank=True, max_length=200, default="")
additional_info = ArrayField(models.CharField(blank=True, max_length=200), size=15, default=list, blank=True)
email_verified = models.BooleanField(blank=False, default=False)
offer_accepted = models.BooleanField(blank=False, default=None, null=True)
deadline_datetime = models.DateTimeField(blank=False, verbose_name="Deadline Date", default=two_day_after_today)
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):
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)
student = models.ForeignKey(Student, blank=False, on_delete=models.CASCADE)
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, default=None, null=True)
additional_info = models.JSONField(blank=True, null=True, default=None)
selected = models.BooleanField(null=True, default=None, blank=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 .models import *
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:
model = Student
fields = '__all__'
# exclude = ['id']
exclude = ['resumes']
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):
company_details = 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
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:
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
class PlacementApplicationSerializer(serializers.ModelSerializer):
application_status = serializers.SerializerMethodField()
company_details = serializers.SerializerMethodField()
placement = serializers.SerializerMethodField()
resume_link = serializers.SerializerMethodField()
def get_application_status(self, obj):
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,
}
def get_placement(self, obj):
data = PlacementSerializerForStudent(obj.placement).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 = ['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
from os import path, remove
import json
from datetime import datetime
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},
status=status.HTTP_200_OK)
except:
return Response({'action': "Login", 'message': "Error Occurred {0}".format(
str(sys.exc_info()[1]))},
return Response({'action': "Login", 'message': "Something Went Wrong"},
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},
status=status.HTTP_200_OK)
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)
@ -41,20 +41,12 @@ def addResume(request, id, email, user_type):
destination_path = ""
try:
student = get_object_or_404(Student, id=id)
prefix = generateRandomString()
files = request.FILES
file_name = prefix + "_" + files['file'].name
print(file_name)
student.resumes.append(file_name)
file = files['file']
destination_path = STORAGE_DESTINATION + str(file_name)
if path.exists(destination_path):
remove(destination_path)
with open(destination_path, 'wb+') as destination:
for chunk in file.chunks():
destination.write(chunk)
destination_path = STORAGE_DESTINATION_RESUMES + id + "/"
file_name = saveFile(file, destination_path)
student.resumes.append(file_name)
student.save()
return Response({'action': "Upload Resume", 'message': "Resume Added"},
@ -68,8 +60,7 @@ def addResume(request, id, email, user_type):
remove(destination_path)
else:
logger.warning("Upload Resume: " + str(sys.exc_info()))
return Response({'action': "Upload Resume", 'message': "Error Occurred {0}".format(
str(sys.exc_info()[1]))},
return Response({'action': "Upload Resume", 'message': "Something Went Wrong"},
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],
allowed_branch__contains=[studentDetails.branch],
status=STATUS_ACCEPTING_APPLICATIONS)
placementsdata = PlacementSerializer(placements, many=True).data
deadline_datetime__gte=datetime.now(),
offer_accepted=True, email_verified=True).order_by('deadline_datetime')
placementsdata = PlacementSerializerForStudent(placements, many=True).data
placementApplications = PlacementApplication.objects.filter(student_id=id)
placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data
return Response(
{'action': "Placement and Internships", 'message': "Data Found", "placements": placementsdata,
{'action': "Get Dashboard - Student", 'message': "Data Found", "placements": placementsdata,
'placementApplication': placementApplications},
status=status.HTTP_200_OK)
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)
except:
logger.warning("Placements and Internships: " + str(sys.exc_info()))
return Response({'action': "Placements and Internships", 'message': "Error Occurred {0}".format(
str(sys.exc_info()[1]))},
logger.warning("Get Dashboard -Student: " + str(sys.exc_info()))
return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)
@ -108,7 +99,7 @@ def deleteResume(request, id, email, user_type):
try:
student = get_object_or_404(Student, id=id)
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):
remove(destination_path)
student.resumes.remove(file_name)
@ -125,28 +116,32 @@ def deleteResume(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Delete Resume: " + str(sys.exc_info()))
return Response({'action': "Delete Resume", 'message': "Error Occurred {0}".format(
str(sys.exc_info()))},
return Response({'action': "Delete Resume", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized(allowed_users=[STUDENT])
@precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME,
ADDITIONAL_INFO])
])
def submitApplication(request, id, email, user_type):
try:
data = request.data
student = get_object_or_404(Student, id=id)
# Only Allowing Applications for Placements
if data[OPENING_TYPE] == PLACEMENT:
if not len(PlacementApplication.objects.filter(
student_id=id, placement_id=data[OPENING_ID])):
application = PlacementApplication()
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)
print(cond_stat, cond_msg)
if not cond_stat:
raise PermissionError(cond_msg)
application.placement = opening
@ -162,21 +157,29 @@ def submitApplication(request, id, email, user_type):
application.student = student
application.id = generateRandomString()
additional_info = {}
for i in opening.additional_info:
if i not in data[ADDITIONAL_INFO]:
print(i)
raise AttributeError(i + " not found in Additional Info")
else:
additional_info[i] = data[ADDITIONAL_INFO][i]
application.additional_info = data[ADDITIONAL_INFO]
if not sendApplicationEmail(email, student.name, opening.company.name, data[OPENING_TYPE],
data[ADDITIONAL_INFO]):
logger.error("Submit Application: Unable to Send Email")
# raise RuntimeError("Unable to Send Email")
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)
sendEmail(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)
@ -185,6 +188,5 @@ def submitApplication(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Submit Application: " + str(sys.exc_info()))
return Response({'action': "Submit Application", 'message': "Error Occurred {0}".format(
str(sys.exc_info()[1]))},
return Response({'action': "Submit Application", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -5,6 +5,7 @@ import string
import sys
from os import path, remove
import background_task
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.http import Http404
@ -16,7 +17,8 @@ from google.oauth2 import id_token
from rest_framework import status
from rest_framework.response import Response
from .models import *
from .constants import *
from .models import User, PrePlacementOffer, PlacementApplication
logger = logging.getLogger('db')
@ -78,11 +80,9 @@ def isAuthorized(allowed_users=None):
raise PermissionError("Authorization Header Not Found")
except PermissionError as e:
print(e)
return Response({'action': "Is Authorized?", 'message': str(e)},
status=status.HTTP_401_UNAUTHORIZED)
except Http404:
print('http404')
return Response({'action': "Is Authorized?", 'message': "User Not Found. Contact CDC for more details"},
status=status.HTTP_404_NOT_FOUND)
except ValueError as e:
@ -90,9 +90,10 @@ def isAuthorized(allowed_users=None):
return Response({'action': "Is Authorized?", 'message': str(e)},
status=status.HTTP_401_UNAUTHORIZED)
except:
return Response({'action': "Is Authorized?", 'message': "Error Occurred {0}".format(
str(sys.exc_info()[1]))},
status=status.HTTP_400_BAD_REQUEST)
logger.warning("Is Authorized? " + str(sys.exc_info()))
return Response(
{'action': "Is Authorized?", 'message': "Something went wrong. Contact CDC for more details"},
status=status.HTTP_400_BAD_REQUEST)
return wrapper_func
@ -102,36 +103,12 @@ def isAuthorized(allowed_users=None):
def generateRandomString():
try:
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
except:
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):
prefix = generateRandomString()
file_name = prefix + "_" + file.name
@ -139,7 +116,7 @@ def saveFile(file, location):
if not path.isdir(location):
os.mkdir(location)
destination_path = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + str(file_name)
destination_path = location + str(file_name)
if path.exists(destination_path):
remove(destination_path)
@ -150,6 +127,7 @@ def saveFile(file, location):
return file_name
@background_task.background(schedule=10)
def sendEmail(email_to, subject, data, template):
try:
html_content = render_to_string(template, data) # render with dynamic value
@ -163,17 +141,18 @@ def sendEmail(email_to, subject, data, template):
msg.send()
return True
except:
logger.error("Send Email: " + str(sys.exc_info()))
print(str(sys.exc_info()[1]))
return str(sys.exc_info()[1])
return False
def PlacementApplicationConditions(student, placement):
try:
selected_companies = PlacementApplication.objects.filter(student=student, selected=True)
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")
if len(selected_companies_PSU) > 0:
@ -195,3 +174,41 @@ def PlacementApplicationConditions(student, placement):
print(sys.exc_info())
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
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
from dotenv import load_dotenv
load_dotenv("../dev.env")
# import django_heroku
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
@ -41,6 +43,7 @@ INSTALLED_APPS = [
'rest_framework',
'corsheaders',
'django_db_logger',
'background_task'
]
MIDDLEWARE = [
@ -80,19 +83,15 @@ WSGI_APPLICATION = 'CDC_Backend.wsgi.application'
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'cdc',
'USER': 'postgres',
'PASSWORD': 'root',
'HOST': 'localhost',
'PORT': '5432',
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': os.environ.get("DB_NAME"),
'USER': os.environ.get("DB_USER"),
'PASSWORD': os.environ.get("DB_PASSWORD"),
'HOST': os.environ.get("DB_HOST"),
'PORT': os.environ.get("DB_PORT"),
},
# 'default': {
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
# 'NAME': 'd84i5cbjig5rrf',
@ -159,8 +158,8 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'saisurya3127@gmail.com'#'email here'
EMAIL_HOST_PASSWORD = 'ehwkqmryyqjiifcz'#'password here'
EMAIL_HOST_USER = os.environ.get("EMAIL") # 'email here'
EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_PASSWORD") # 'password here'
LOGGING = {
'version': 1,
@ -178,6 +177,11 @@ LOGGING = {
'level': 'DEBUG',
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
},
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
}
},
'loggers': {
'db': {
@ -187,5 +191,4 @@ LOGGING = {
}
}
# django_heroku.settings(locals())

View File

@ -1,13 +1,23 @@
# API References
1. [**Common APIs**](#common-apis)
1. [**api/login/**](#apilogin)
2. [**Student APIs**](#student-portal-apis)
1. [**api/student/profile/**](#apistudentprofile)
2. [**api/student/getDashboard/**](#apistudentgetdashboard)
3. [**api/student/addResume/**](#apistudentaddresume)
4. [**api/student/deleteResume/**](#apistudentdeleteresume)
5. [**api/student/submitApplication/**](#apistudentsubmitapplication)
3. [**Common Errors**](#common-errors)
1. [**api/student/profile/**](#apistudentprofile)
2. [**api/student/getDashboard/**](#apistudentgetdashboard)
3. [**api/student/addResume/**](#apistudentaddresume)
4. [**api/student/deleteResume/**](#apistudentdeleteresume)
5. [**api/student/submitApplication/**](#apistudentsubmitapplication)
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
{
"action": "Login",
"message": "Verified",
"user_type": [
"student"
]
"action": "Login",
"message": "Verified",
"user_type": [
"student"
]
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
- user_type: Tells us about the role the user possess. Can have these values
- student
- Admin
- student
- Admin
### Status Codes
@ -88,16 +98,26 @@ Response is a Json with these fields
"action": "Student Profile",
"message": "Details Found",
"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,
"name": "Gowtham Sai",
"batch": "THIRD",
"batch": "2019",
"branch": "CSE",
"phone_number": 9390291911,
"resumes": [
"XB85F4RIGBF5VJN_Cv-Gowtham.pdf"
],
"cpi": "9.02"
"cpi": "9.15"
}
}
```
@ -113,7 +133,7 @@ The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 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)
@ -121,11 +141,11 @@ You may see some different errors which can be seen [here](#common-errors)
## `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?
Send a `GET` request to `api/student/Dashboard`<br>
Send a `GET` request to `api/student/getDashboard`<br>
Request_Body:
@ -136,88 +156,215 @@ Request_Body:
> Headers <br>
> Authorization: "Bearer {tokenID}"
> Only users with `student` role can access this Api.
### Response
Response is a Json with these fields
```json
{
"action": "Placement and Internships",
"action": "Get Dashboard - Student",
"message": "Data Found",
"placements": [
{
"id": "fdgdb121",
"designation": "Software Developer",
"description": "nice job",
"start_date": "2021-06-17",
"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,
"city": "Mumbai",
"state": "Maharashtra",
"country": "India",
"pin_code": 530013,
"city_type": "Domestic",
"compensation": 1200000,
"compensation_details": "",
"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": [
"THIRD",
"FOURTH"
"2018",
"2019"
],
"allowed_branch": [
"CSE",
"EE",
"ME"
],
"attachments": [],
"rounds": [
"Resume Shortlisting",
"Technical Test",
"Interview"
"EE"
],
"tentative_no_of_offers": 5,
"other_requirements": "above 8 cpi",
"additional_info": [
"school",
"place of study",
"language"
"School",
"Home Town"
],
"status": "Resume Shortlisting",
"rounds_details": {
"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": ""
}
"deadline_date": "2021-12-04",
"created_at": "2021-12-02T20:12:21+05:30"
}
],
"placementApplication": [
{
"id": "dsdads",
"application_status": "Resume Shortlisting",
"resume": "XB85F4RIGBF5VJN_Cv-Gowtham.pdf",
"additional_info": {
"school": "Delhi Public School",
"language": "Telugu",
"place of study": "Visakhapatnam"
"id": "LLW4STE76GEJYOR",
"placement": {
"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,
"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,
"placement": "fdgdb121"
"applied_at": "2021-12-02T21:58:18.032466+05:30"
}
]
]
}
```
- action: Tells us about the message creator<Br>
- message: Tells us what happened with our Request.
- placements: Has the placements data.
- internships: Has the internships data.
- 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
- placements: Array of Placement Objects
- placementApplication: Array of Placement Application Objects
### Status Codes
@ -225,8 +372,9 @@ The possible responses for this api request are as follows
| Status Codes | Possible Messages |
| --------------- | ------------------------ |
| 200 OK | `Resume Added` |
| 400 BAD_REQUEST | `Error Occurred {error}` |
| 200 OK | `Data Found` |
| 404 Not Found | `Student Not Found` |
| 400 BAD_REQUEST | `Something Went Wrong` |
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/`
This Api is used to submit application to Internships/Placements.
This Api is used to submit application to Placements.
### How to Use?
@ -343,24 +491,23 @@ Request_Body:
```json
{
"opening_type": "Placement",
"opening_id": "fgervsdgdsf",
"resume_file_name": "1FYE0PQZZ508HR6_Resume for Google STEP.pdf",
"additional_info": {
"school": "Narayana English Medium",
"place of study": "Vizag",
"language": "Telugu"
}
"opening_type": "Placement",
"opening_id": "Q54IRZZMC3RP8F6",
"resume_file_name": "8KIOT3PW1JIS718_CSE-V-SEM.pdf",
"additional_info": {
"School": "Narayana English Medium High School",
"Home Town": "Vizag"
}
}
```
> Headers <br>
> Authorization: "Bearer {tokenID}"
- opening_type: Can be Placement/Internship
- opening_type: Can be Placement
- 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
asked and sent. These fields can be found in the Internship Details.
- 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 Placement Details.
### Response
@ -384,12 +531,559 @@ The possible responses for this api request are as follows
| ------------- | ---------------------------------- |
| 200 OK | `Application Submitted` |
| 403 FORBIDDEN | `Application is already Submitted` |
| 403 FORBIDDEN | `Placement Not Approved` |
| 404 NOT FOUND | `RESUME_FILE_NAME Not Found` |
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`
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 | `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 |
| 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;
">Hello there, {{ name }}</h1>
<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>
. We received these additional details<br>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family:

View File

@ -37,3 +37,5 @@
### 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)

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