diff --git a/CDC_Backend/APIs/adminUrls.py b/CDC_Backend/APIs/adminUrls.py index 203c0dc..0dbe3b3 100644 --- a/CDC_Backend/APIs/adminUrls.py +++ b/CDC_Backend/APIs/adminUrls.py @@ -1,7 +1,13 @@ 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"), ] diff --git a/CDC_Backend/APIs/adminViews.py b/CDC_Backend/APIs/adminViews.py index e69de29..374266a 100644 --- a/CDC_Backend/APIs/adminViews.py +++ b/CDC_Backend/APIs/adminViews.py @@ -0,0 +1,155 @@ +from datetime import datetime + +from .utils import * +from rest_framework.decorators import api_view + +from .serializers import * + + +@api_view(['POST']) +@isAuthorized([ADMIN]) +@precheck([OPENING_ID, STUDENT_LIST]) +def markStatus(request, id, email, user_type): + try: + data = request.data + # Getting all application from db for this opening + applications = PlacementApplication.objects.filter(placement_id=data[OPENING_ID]) + for i in data[STUDENT_LIST]: + application = applications.filter(student_id=i[STUDENT_ID]) # Filtering student's application + if len(application) > 0: + application = application[0] + application.selected = True if i[STUDENT_SELECTED] == "true" else False + + email = str(application.student.roll_no) + "@iitdh.ac.in" # Only allowing for IITDh emails + subject = STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT.format(company_name=application.placement.company_name, + id=application.id) + data = { + "company_name": application.placement.company_name, + "designation": application.placement.designation, + "student_name": application.student.name + } + if application.selected: # Sending corresponding email to students + sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE) + else: + sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE) + application.save() + else: + raise ValueError("Student - " + i[STUDENT_ID] + " didn't apply for this opening") + return Response({'action': "Mark Status", 'message': "Marked Status"}, + status=status.HTTP_200_OK) + + except ValueError as e: + return Response({'action': "Mark Status", 'message': str(e)}, + status=status.HTTP_400_BAD_REQUEST) + except: + logger.warning("Mark Status: " + str(sys.exc_info())) + return Response({'action': "Mark Status", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) + + +@api_view(['GET']) +@isAuthorized([ADMIN]) +def getDashboard(request, id, email, user_type): + try: + placements = Placement.objects.all().order_by('-created_at') + ongoing = placements.filter(deadline_datetime__gt=datetime.now()) + previous = placements.exclude(deadline_datetime__gt=datetime.now()) + ongoing = PlacementSerializerForAdmin(ongoing, many=True).data + previous = PlacementSerializerForAdmin(previous, many=True).data + + return Response( + {'action': "Get Dashboard - Admin", 'message': "Data Found", "ongoing": ongoing, "previous": previous}, + status=status.HTTP_200_OK) + except Http404: + return Response({'action': "Get Dashboard - Admin", 'message': 'Student Not Found'}, + status=status.HTTP_404_NOT_FOUND) + except: + logger.warning("Get Dashboard - Admin: " + str(sys.exc_info())) + return Response({'action': "Get Dashboard - Admin", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) + + +@api_view(['POST']) +@isAuthorized([ADMIN]) +@precheck([OPENING_ID, DEADLINE_DATETIME]) +def updateDeadline(request, id, email, user_type): + try: + data = request.data + opening = get_object_or_404(Placement, pk=data[OPENING_ID]) + # Updating deadline date with correct format in datetime field + opening.deadline_datetime = datetime.strptime(data[DEADLINE_DATETIME], '%Y-%m-%d %H:%M:%S %z') + opening.save() + return Response({'action': "Update Deadline", 'message': "Deadline Updated"}, + status=status.HTTP_200_OK) + except Http404: + return Response({'action': "Update Deadline", 'message': 'Opening Not Found'}, + status=status.HTTP_404_NOT_FOUND) + except: + logger.warning("Update Deadline: " + str(sys.exc_info())) + return Response({'action': "Update Deadline", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) + +@api_view(['POST']) +@isAuthorized([ADMIN]) +@precheck([OPENING_ID, OFFER_ACCEPTED]) +def updateOfferAccepted(request, id, email, user_type): + try: + data = request.data + opening = get_object_or_404(Placement, pk=data[OPENING_ID]) + opening.offer_accepted = True if data[OFFER_ACCEPTED] == "true" else False + opening.save() + return Response({'action': "Update Offer Accepted", 'message': "Offer Accepted Updated"}, + status=status.HTTP_200_OK) + except Http404: + return Response({'action': "Update Offer Accepted", 'message': 'Opening Not Found'}, + status=status.HTTP_404_NOT_FOUND) + except: + logger.warning("Update Offer Accepted: " + str(sys.exc_info())) + return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) + +@api_view(['POST']) +@isAuthorized([ADMIN]) +@precheck([OPENING_ID, EMAIL_VERIFIED]) +def updateEmailVerified(request, id, email, user_type): + try: + data = request.data + opening = get_object_or_404(Placement, pk=data[OPENING_ID]) + opening.email_verified = True if data[EMAIL_VERIFIED] == "true" else False + opening.save() + return Response({'action': "Update Email Verified", 'message': "Email Verified Updated"}, + status=status.HTTP_200_OK) + except Http404: + return Response({'action': "Update Email Verified", 'message': 'Opening Not Found'}, + status=status.HTTP_404_NOT_FOUND) + except: + logger.warning("Update Email Verified: " + str(sys.exc_info())) + return Response({'action': "Update Email Verified", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) + +@api_view(['POST']) +@isAuthorized([ADMIN]) +@precheck([OPENING_ID, ADDITIONAL_INFO]) +def updateAdditionalInfo(request, id, email, user_type): + try: + data = request.data + opening = get_object_or_404(Placement, pk=data[OPENING_ID]) + if data[ADDITIONAL_INFO] == "": + opening.additional_info = [] + elif isinstance(data[ADDITIONAL_INFO], list): + opening.additional_info = data[ADDITIONAL_INFO] + else: + raise ValueError("Additional Info must be a list") + opening.save() + return Response({'action': "Update Additional Info", 'message': "Additional Info Updated"}, + status=status.HTTP_200_OK) + except Http404: + return Response({'action': "Update Additional Info", 'message': 'Opening Not Found'}, + status=status.HTTP_404_NOT_FOUND) + except ValueError: + return Response({'action': "Update Additional Info", 'message': "Additional Info must be a list"}, + status=status.HTTP_400_BAD_REQUEST) + except: + logger.warning("Update Additional Info: " + str(sys.exc_info())) + return Response({'action': "Update Additional Info", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/CDC_Backend/APIs/companyUrls.py b/CDC_Backend/APIs/companyUrls.py index f175144..5cda889 100644 --- a/CDC_Backend/APIs/companyUrls.py +++ b/CDC_Backend/APIs/companyUrls.py @@ -3,5 +3,5 @@ from . import companyViews urlpatterns = [ - path('addOpening/', companyViews.addOpening, name="Add Opening"), + path('addPlacement/', companyViews.addPlacement, name="Add Placement"), ] diff --git a/CDC_Backend/APIs/companyViews.py b/CDC_Backend/APIs/companyViews.py index 92c7eac..7d7d50b 100644 --- a/CDC_Backend/APIs/companyViews.py +++ b/CDC_Backend/APIs/companyViews.py @@ -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) diff --git a/CDC_Backend/APIs/constants.py b/CDC_Backend/APIs/constants.py index 7a4b25b..fa9790e 100644 --- a/CDC_Backend/APIs/constants.py +++ b/CDC_Backend/APIs/constants.py @@ -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,102 @@ 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/" + + 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/' 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' + diff --git a/CDC_Backend/APIs/models.py b/CDC_Backend/APIs/models.py index 7203738..d8c9080 100644 --- a/CDC_Backend/APIs/models.py +++ b/CDC_Backend/APIs/models.py @@ -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) diff --git a/CDC_Backend/APIs/serializers.py b/CDC_Backend/APIs/serializers.py index 62f9ef7..787de1e 100644 --- a/CDC_Backend/APIs/serializers.py +++ b/CDC_Backend/APIs/serializers.py @@ -1,56 +1,162 @@ +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'] diff --git a/CDC_Backend/APIs/studentViews.py b/CDC_Backend/APIs/studentViews.py index d709576..329f5c3 100644 --- a/CDC_Backend/APIs/studentViews.py +++ b/CDC_Backend/APIs/studentViews.py @@ -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': "Student Not Found"}, + 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) diff --git a/CDC_Backend/APIs/utils.py b/CDC_Backend/APIs/utils.py index 422cec1..d7ea9fb 100644 --- a/CDC_Backend/APIs/utils.py +++ b/CDC_Backend/APIs/utils.py @@ -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 @@ -108,30 +109,6 @@ def generateRandomString(): 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, "_" diff --git a/CDC_Backend/CDC_Backend/settings.py b/CDC_Backend/CDC_Backend/settings.py index e2b812b..7c0a6f1 100644 --- a/CDC_Backend/CDC_Backend/settings.py +++ b/CDC_Backend/CDC_Backend/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ 'rest_framework', 'corsheaders', 'django_db_logger', + 'background_task' ] MIDDLEWARE = [ @@ -160,7 +161,7 @@ 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_PASSWORD = 'yeylqcnsyjfpzsew'#'password here' LOGGING = { 'version': 1, diff --git a/CDC_Backend/templates/company_opening_submitted.html b/CDC_Backend/templates/company_opening_submitted.html new file mode 100644 index 0000000..88147e0 --- /dev/null +++ b/CDC_Backend/templates/company_opening_submitted.html @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ +
+ + + + + +
+

Thank You for filling the form

+

+ We have received your {{ opening_type }} notification for a {{ designation }} offer at + {{ company_name }}. Click here to view your notification. +

+ +

+ We will keep you informed with the updates. If you have any queries, please + feel to + write to + cdc@iitdh.ac.in +

+
+
+ + + + + + + +
+

+ ® CDC,IIT Dharwad,2021
+

+
+
+
+ + \ No newline at end of file diff --git a/CDC_Backend/templates/student_application_status_not_selected.html b/CDC_Backend/templates/student_application_status_not_selected.html new file mode 100644 index 0000000..ee01642 --- /dev/null +++ b/CDC_Backend/templates/student_application_status_not_selected.html @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + + + +
+

Hey, {{ student_name }}

+

+ We regret to inform you that you have not been selected for {{ designation }} role at {{ company_name }}. + CDC will keep bringing more such opportunities for you in the future. +

+ + + + +
+
+
+
+ + + + +
+

+ ® CDC,IIT Dharwad,2021
+

+
+
+
+ + diff --git a/CDC_Backend/templates/student_application_status_selected.html b/CDC_Backend/templates/student_application_status_selected.html new file mode 100644 index 0000000..0cd439f --- /dev/null +++ b/CDC_Backend/templates/student_application_status_selected.html @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + +
+ +
+ + + + + + + +
+

Hey, {{ student_name }}

+

+ Congratulations, You have been selected for the {{ designation }} at {{ company_name }}.
+

+ + + + +
+
+
+
+ + + + +
+

+ ® CDC,IIT Dharwad,2021
+

+
+
+
+ + diff --git a/CDC_Backend/templates/student_application_submitted.html b/CDC_Backend/templates/student_application_submitted.html index 805edee..eaeb123 100644 --- a/CDC_Backend/templates/student_application_submitted.html +++ b/CDC_Backend/templates/student_application_submitted.html @@ -44,7 +44,7 @@

Hello there, {{ name }}

- We have received your application for a {{ applicaton_type }} offer at + We have received your application for a {{ application_type }} offer at {{ company_name }} . We received these additional details