From db025d025945aad74204aa2235ea59a12ba8c3ef Mon Sep 17 00:00:00 2001 From: karthik mv Date: Tue, 24 May 2022 15:07:32 +0530 Subject: [PATCH] new endpoints (#109) * added getstudentapplication and editstudentapplication endpoints - for admin views * added student data to send * format placement added. * changed submitApplication * merge fixes * made refractorings * minor changes in placement model * Added updated at for applications * removed log Co-authored-by: gowtham --- CDC_Backend/APIs/adminUrls.py | 1 + CDC_Backend/APIs/adminViews.py | 135 +++++++++++------- CDC_Backend/APIs/companyViews.py | 25 ++-- CDC_Backend/APIs/constants.py | 16 ++- CDC_Backend/APIs/models.py | 129 ++++++++++++----- CDC_Backend/APIs/serializers.py | 8 +- CDC_Backend/APIs/utils.py | 17 +-- .../templates/company_email_verification.html | 2 +- .../templates/company_jnf_response.html | 2 +- 9 files changed, 220 insertions(+), 115 deletions(-) diff --git a/CDC_Backend/APIs/adminUrls.py b/CDC_Backend/APIs/adminUrls.py index 71d0073..90d9c71 100644 --- a/CDC_Backend/APIs/adminUrls.py +++ b/CDC_Backend/APIs/adminUrls.py @@ -13,4 +13,5 @@ urlpatterns = [ path("submitApplication/", adminViews.submitApplication, name="Submit Application"), path('generateCSV/', adminViews.generateCSV, name="Generate CSV"), path('addPPO/', adminViews.addPPO, name="Add PPO"), + path('getStudentApplication/', adminViews.getStudentApplication, name="Get student application"), ] diff --git a/CDC_Backend/APIs/adminViews.py b/CDC_Backend/APIs/adminViews.py index b21eab2..4acf47c 100644 --- a/CDC_Backend/APIs/adminViews.py +++ b/CDC_Backend/APIs/adminViews.py @@ -59,8 +59,8 @@ def markStatus(request, id, email, user_type): def getDashboard(request, id, email, user_type): try: placements = Placement.objects.all().order_by('-created_at') - ongoing = placements.filter(deadline_datetime__gt=datetime.datetime.now(), offer_accepted=True, email_verified=True) - previous = placements.exclude(deadline_datetime__gt=datetime.datetime.now()).filter( + ongoing = placements.filter(deadline_datetime__gt=timezone.now(), offer_accepted=True, email_verified=True) + previous = placements.exclude(deadline_datetime__gt=timezone.now()).filter( offer_accepted=True, email_verified=True) new = placements.filter(offer_accepted__isnull=True, email_verified=True) ongoing = PlacementSerializerForAdmin(ongoing, many=True).data @@ -193,62 +193,55 @@ def getApplications(request, id, email, user_type): @api_view(['POST']) @isAuthorized(allowed_users=[ADMIN]) -@precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME, - STUDENT_ID]) +@precheck(required_data=[APPLICATION_ID, STUDENT_ID, OPENING_ID, ADDITIONAL_INFO, RESUME_FILE_NAME]) def submitApplication(request, id, email, user_type): try: data = request.data - student = get_object_or_404(Student, roll_no=data[STUDENT_ID]) - if data[OPENING_TYPE] != PLACEMENT: - raise ValueError(OPENING_TYPE + " is Invalid") - # Only Allowing Applications for Placements - else: - 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.datetime.now().date() - ) - if not opening.offer_accepted or not opening.email_verified: - raise PermissionError("Placement Not Approved") + student = get_object_or_404(Student, pk=data[STUDENT_ID]) + opening = get_object_or_404(Placement, pk=data[OPENING_ID]) - cond_stat, cond_msg = PlacementApplicationConditions(student, opening) - if not cond_stat: - raise PermissionError(cond_msg) - application.placement = opening + if data[APPLICATION_ID] == "": + application = PlacementApplication() + application.id = generateRandomString() + application.placement = opening + application.student = student + if data[RESUME_FILE_NAME] in student.resumes: + application.resume = data[RESUME_FILE_NAME] else: - raise PermissionError("Application is already Submitted") - - if data[RESUME_FILE_NAME] in student.resumes: - application.resume = data[RESUME_FILE_NAME] + raise FileNotFoundError(RESUME_FILE_NAME + " Not Found") + 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) + application.save() + return Response({'action': "Add Student Application", 'message': "Application added"}, + status=status.HTTP_200_OK) else: - raise FileNotFoundError(RESUME_FILE_NAME + " Not Found") + application = get_object_or_404(PlacementApplication, id=data[APPLICATION_ID]) + if application: + if data[RESUME_FILE_NAME] in student.resumes: + application.resume = data[RESUME_FILE_NAME] + else: + raise FileNotFoundError(RESUME_FILE_NAME + " Not Found") + application.resume = data[RESUME_FILE_NAME] + 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.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") + application.additional_info = json.dumps(additional_info) + application.save() + return Response({'action': "Add Student Application", 'message': "Application updated"}, + status=status.HTTP_200_OK) else: - additional_info[i] = data[ADDITIONAL_INFO][i] + return Response({'action': "Edit Student Application", 'message': "No Application Found"}, + status=status.HTTP_400_BAD_REQUEST) - 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) @@ -308,7 +301,7 @@ def generateCSV(request, id, email, user_type): except: logger.warning("Create csv: " + str(sys.exc_info())) print(sys.exc_info()) - return Response({'action': "Create csv", 'message': "Error Occurred"}, + return Response({'action': "Create csv", 'message': "Something Went Wrong"}, status=status.HTTP_400_BAD_REQUEST) @@ -338,5 +331,45 @@ def addPPO(request, id, email, user_type): except: logger.warning("Add PPO: " + str(sys.exc_info())) print(sys.exc_info()) - return Response({'action': "Add PPO", 'message': "Error Occurred"}, + return Response({'action': "Add PPO", 'message': "Something Went Wrong"}, status=status.HTTP_400_BAD_REQUEST) + + +@api_view(['POST']) +@isAuthorized(allowed_users=[ADMIN]) +@precheck(required_data=[STUDENT_ID, OPENING_ID]) +def getStudentApplication(request, id, email, user_type): + try: + data = request.data + student = get_object_or_404(Student, id=data[STUDENT_ID]) + student_serializer = StudentSerializer(student) + student_details = { + "name": student_serializer.data['name'], + "batch": student.batch, + "branch": student.branch, + "resume_list": student_serializer.data['resume_list'], + } + # search for the application if there or not + application = PlacementApplication.objects.filter(student=student, + placement=get_object_or_404(Placement, id=data[OPENING_ID])) + if application: + serializer = PlacementApplicationSerializer(application[0]) + application_info = { + "id": serializer.data['id'], + "additional_info": serializer.data['additional_info'], + "resume": serializer.data['resume_link'], + } + return Response( + {'action': "Get Student Application", 'application_found': "true", "application_info": application_info, + "student_details": student_details}, status=status.HTTP_200_OK) + else: + return Response( + {'action': "Get Student Application", 'application_found': "false", "student_details": student_details}, + status=status.HTTP_404_NOT_FOUND) + except Http404: + return Response({'action': "Get Student Application", 'message': "Student not found."}, + status.HTTP_404_NOT_FOUND) + except: + logger.warning("Get Student Application: " + str(sys.exc_info())) + return Response({'action': "Get Student Application", 'message': "Something Went Wrong"}, + status.HTTP_400_BAD_REQUEST) diff --git a/CDC_Backend/APIs/companyViews.py b/CDC_Backend/APIs/companyViews.py index 8378a41..2593513 100644 --- a/CDC_Backend/APIs/companyViews.py +++ b/CDC_Backend/APIs/companyViews.py @@ -6,14 +6,14 @@ logger = logging.getLogger('db') @api_view(['POST']) -@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, RECAPTCHA_VALUE +@precheck([COMPANY_NAME, ADDRESS, COMPANY_TYPE, NATURE_OF_BUSINESS, TYPE_OF_ORGANISATION, 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, + IS_COMPENSATION_DETAILS_PDF, ALLOWED_BRANCH, RS_ELIGIBLE, SELECTION_PROCEDURE_ROUNDS, + SELECTION_PROCEDURE_DETAILS, + IS_SELECTION_PROCEDURE_DETAILS_PDF, TENTATIVE_DATE_OF_JOINING, TENTATIVE_NO_OF_OFFERS, OTHER_REQUIREMENTS, + RECAPTCHA_VALUE, JOB_LOCATION ]) def addPlacement(request): try: @@ -29,9 +29,14 @@ def addPlacement(request): opening.address = data[ADDRESS] opening.company_type = data[COMPANY_TYPE] opening.nature_of_business = data[NATURE_OF_BUSINESS] + opening.type_of_organisation = data[TYPE_OF_ORGANISATION] opening.website = data[WEBSITE] opening.company_details = data[COMPANY_DETAILS] opening.is_company_details_pdf = data[IS_COMPANY_DETAILS_PDF] + if data[RS_ELIGIBLE] == 'Yes': + opening.rs_eligible = True + else: + opening.rs_eligible = False if opening.is_company_details_pdf: company_details_pdf = [] @@ -70,7 +75,7 @@ def addPlacement(request): raise ValueError('Pincode should be integer') # If India then set city_type as Domestic else International - if opening.country == 'India': + if opening.country.upper() == 'INDIA': opening.city_type = 'Domestic' else: opening.city_type = 'International' @@ -78,6 +83,7 @@ def addPlacement(request): # Add a designation details in the opening opening.designation = data[DESIGNATION] opening.description = data[DESCRIPTION] + opening.job_location = data[JOB_LOCATION] opening.is_description_pdf = data[IS_DESCRIPTION_PDF] if opening.is_description_pdf: @@ -129,7 +135,6 @@ def addPlacement(request): else: raise ValueError('Compensation Bonus must be an integer') - opening.compensation_details = data[COMPENSATION_DETAILS] opening.is_compensation_details_pdf = data[IS_COMPENSATION_DETAILS_PDF] if opening.is_compensation_details_pdf: diff --git a/CDC_Backend/APIs/constants.py b/CDC_Backend/APIs/constants.py index 3d9d29a..5981cba 100644 --- a/CDC_Backend/APIs/constants.py +++ b/CDC_Backend/APIs/constants.py @@ -55,6 +55,10 @@ TIER = 'tier' FOURTH_YEAR = '2019' MAX_OFFERS_PER_STUDENT = 2 EMAIL_VERIFICATION_TOKEN_TTL = 48 # in hours +JNF_TEXT_MAX_CHARACTER_COUNT = 100 +JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT = 200 +JNF_TEXTAREA_MAX_CHARACTER_COUNT = 1000 +JNF_SMALLTEXT_MAX_CHARACTER_COUNT = 50 STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/" STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/' @@ -75,6 +79,7 @@ COMPANY_NAME = "company_name" ADDRESS = "address" COMPANY_TYPE = "company_type" NATURE_OF_BUSINESS = "nature_of_business" +TYPE_OF_ORGANISATION = "type_of_organisation" WEBSITE = 'website' COMPANY_DETAILS = "company_details" COMPANY_DETAILS_PDF = "company_details_pdf" @@ -93,6 +98,7 @@ DESCRIPTION_PDF = 'description_pdf' DESCRIPTION_PDF_NAMES = 'description_pdf_names' IS_DESCRIPTION_PDF = 'is_description_pdf' OPENING_TYPE = 'opening_type' +JOB_LOCATION = 'job_location' COMPENSATION_CTC = 'compensation_ctc' COMPENSATION_GROSS = 'compensation_gross' COMPENSATION_TAKE_HOME = 'compensation_take_home' @@ -103,6 +109,7 @@ COMPENSATION_DETAILS_PDF_NAMES = 'compensation_details_pdf_names' IS_COMPENSATION_DETAILS_PDF = 'is_compensation_details_pdf' ALLOWED_BATCH = 'allowed_batch' ALLOWED_BRANCH = 'allowed_branch' +RS_ELIGIBLE = 'rs_eligible' BOND_DETAILS = 'bond_details' SELECTION_PROCEDURE_ROUNDS = 'selection_procedure_rounds' SELECTION_PROCEDURE_DETAILS = 'selection_procedure_details' @@ -122,10 +129,11 @@ STUDENT_ID = "student_id" STUDENT_SELECTED = "student_selected" EXCLUDE_IN_PDF = ['id', 'is_company_details_pdf', 'offer_accepted', 'is_description_pdf', - 'is_compensation_details_pdf', 'is_selection_procedure_details_pdf', - 'email_verified', 'created_at'] -SPECIAL_FORMAT_IN_PDF = ['website', 'company_details_pdf_names', 'description_pdf_names', 'compensation_details_pdf_names', - 'selection_procedure_pdf_names'] + 'is_compensation_details_pdf', 'is_selection_procedure_details_pdf', + 'email_verified', 'created_at'] +SPECIAL_FORMAT_IN_PDF = ['website', 'company_details_pdf_names', 'description_pdf_names', + 'compensation_details_pdf_names', + 'selection_procedure_pdf_names'] COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - Career Development Cell, IIT Dharwad" STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}' diff --git a/CDC_Backend/APIs/models.py b/CDC_Backend/APIs/models.py index 6b0bc07..b986089 100644 --- a/CDC_Backend/APIs/models.py +++ b/CDC_Backend/APIs/models.py @@ -9,20 +9,25 @@ from .constants import * class User(models.Model): - email = models.CharField(primary_key=True, blank=False, max_length=50) + email = models.EmailField(primary_key=True, blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) id = models.CharField(blank=False, max_length=25) user_type = ArrayField(models.CharField(blank=False, max_length=10), size=4, default=list, blank=False) last_login_time = models.DateTimeField(default=timezone.now) + class Meta: + verbose_name_plural = "User" + unique_together = ('email', 'id') + class Student(models.Model): id = models.CharField(blank=False, max_length=15, primary_key=True) roll_no = models.IntegerField(blank=False) - name = models.CharField(blank=False, max_length=50) + name = models.CharField(blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) batch = models.CharField(max_length=10, choices=BATCH_CHOICES, blank=False) branch = models.CharField(choices=BRANCH_CHOICES, blank=False, max_length=10) phone_number = models.PositiveBigIntegerField(blank=True, default=None, null=True) - resumes = ArrayField(models.CharField(null=True, default=None, max_length=100), size=10, default=list, blank=True) + resumes = ArrayField(models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), size=10, + default=list, blank=True) cpi = models.DecimalField(decimal_places=2, max_digits=4) can_apply = models.BooleanField(default=True, verbose_name='Registered') @@ -32,7 +37,7 @@ class Student(models.Model): class Admin(models.Model): id = models.CharField(blank=False, max_length=15, primary_key=True) - name = models.CharField(blank=False, max_length=50) + name = models.CharField(blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) def two_day_after_today(): @@ -42,43 +47,49 @@ def two_day_after_today(): class Placement(models.Model): id = models.CharField(blank=False, primary_key=True, max_length=15) # Company Details - company_name = models.CharField(blank=False, max_length=50) - address = models.CharField(blank=False, max_length=500) - 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(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) + company_name = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT) + address = models.CharField(blank=False, max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT) + company_type = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT) + nature_of_business = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="") + type_of_organisation = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="", blank=False) + website = models.CharField(blank=True, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) + company_details = models.CharField(max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT, default=None, null=True) + company_details_pdf_names = ArrayField( + models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), 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) + contact_person_name = models.CharField(blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) 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="") + email = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="") + city = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="") + state = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="") + country = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="") pin_code = models.IntegerField(blank=False, default=None, null=True) city_type = models.CharField(blank=False, max_length=15, choices=OFFER_CITY_TYPE) # Job Details - designation = models.CharField(blank=False, max_length=50, default=None, null=True) - description = models.CharField(blank=False, max_length=500, default=None, null=True) - description_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, default=list, - blank=True) + designation = models.CharField(blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT, default=None, null=True) + description = models.CharField(blank=False, max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT, default=None, null=True) + job_location = models.CharField(blank=False, max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, default="") + description_pdf_names = ArrayField( + models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), 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=500, default=None, null=True) - compensation_details_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), size=5, - default=list, blank=True) + compensation_details_pdf_names = ArrayField( + models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), size=5, + default=list, blank=True) is_compensation_details_pdf = models.BooleanField(blank=False, default=False) - bond_details = models.CharField(blank=True, max_length=500) - 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=500) - selection_procedure_details_pdf_names = ArrayField(models.CharField(null=True, default=None, max_length=100), - size=5, default=list, blank=True) + bond_details = models.CharField(blank=True, max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT) + selection_procedure_rounds = ArrayField( + models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), size=10, + default=list, blank=True) + selection_procedure_details = models.CharField(blank=True, max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT) + selection_procedure_details_pdf_names = ArrayField( + models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), + 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) @@ -94,18 +105,65 @@ class Placement(models.Model): default=list ) tentative_no_of_offers = models.IntegerField(blank=False, default=None, null=True) - 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) + rs_eligible = models.BooleanField(blank=False, default=False) + other_requirements = models.CharField(blank=True, max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT, default="") + additional_info = ArrayField(models.CharField(blank=True, max_length=JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT), 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) + updated_at = models.DateTimeField(blank=False, default=None, null=True) + + def format(self): + if self.company_name is not None: + self.company_name = self.company_name.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.company_type is not None: + self.company_type = self.company_type.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.company_details is not None: + self.company_details = self.company_details.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.address is not None: + self.address = self.address.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.nature_of_business is not None: + self.nature_of_business = self.nature_of_business.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.type_of_organisation is not None: + self.type_of_organisation = self.type_of_organisation.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.website is not None: + self.website = self.website.strip()[:JNF_TEXT_MAX_CHARACTER_COUNT] + if self.contact_person_name is not None: + self.contact_person_name = self.contact_person_name.strip()[:JNF_TEXT_MAX_CHARACTER_COUNT] + if self.email is not None: + self.email = self.email.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.city is not None: + self.city = self.city.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.state is not None: + self.state = self.state.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.country is not None: + self.country = self.country.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.city_type is not None: + self.city_type = self.city_type.strip()[:JNF_SMALLTEXT_MAX_CHARACTER_COUNT] + if self.designation is not None: + self.designation = self.designation.strip()[:JNF_TEXT_MAX_CHARACTER_COUNT] + if self.description is not None: + self.description = self.description.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.job_location is not None: + self.job_location = self.job_location.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.selection_procedure_details is not None: + self.selection_procedure_details = self.selection_procedure_details.strip()[ + :JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.bond_details is not None: + self.bond_details = self.bond_details.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.other_requirements is not None: + self.other_requirements = self.other_requirements.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] + if self.additional_info is not None: + self.additional_info = [info.strip()[:JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT] for info in list(self.additional_info)] def save(self, *args, **kwargs): ''' On save, add timestamps ''' if not self.created_at: self.created_at = timezone.now() - + self.format() + self.updated_at = timezone.now() return super(Placement, self).save(*args, **kwargs) def __str__(self): @@ -116,7 +174,7 @@ 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) + resume = models.CharField(max_length=JNF_TEXT_MAX_CHARACTER_COUNT, blank=False, null=True, default=None) 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) @@ -141,7 +199,8 @@ class PlacementApplication(models.Model): class PrePlacementOffer(models.Model): id = models.AutoField(primary_key=True) student = models.ForeignKey(Student, on_delete=models.CASCADE, blank=False) - company = models.CharField(max_length=50, blank=False, default="", verbose_name="Company Name") + company = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", + verbose_name="Company Name") compensation = models.IntegerField(blank=False) # Job - Per Year compensation_details = models.CharField(blank=True, max_length=200) tier = models.CharField(blank=False, choices=TIERS, max_length=10) diff --git a/CDC_Backend/APIs/serializers.py b/CDC_Backend/APIs/serializers.py index 82af184..f7cc868 100644 --- a/CDC_Backend/APIs/serializers.py +++ b/CDC_Backend/APIs/serializers.py @@ -162,9 +162,7 @@ class PlacementApplicationSerializer(serializers.ModelSerializer): return data def get_resume_link(self, obj): - ele = {} - ele['link'] = LINK_TO_STORAGE_RESUME + urllib.parse.quote(obj.id + "/" + obj.resume) - ele['name'] = obj.resume + ele = {'link': LINK_TO_STORAGE_RESUME + urllib.parse.quote(obj.id + "/" + obj.resume), 'name': obj.resume} return ele class Meta: @@ -181,8 +179,8 @@ class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer): return data def get_resume_link(self, obj): - link = LINK_TO_STORAGE_RESUME + urllib.parse.quote(obj.id + "/" + obj.resume) - return link + ele = {'link': LINK_TO_STORAGE_RESUME + urllib.parse.quote(obj.id + "/" + obj.resume), 'name': obj.resume} + return ele class Meta: model = PlacementApplication diff --git a/CDC_Backend/APIs/utils.py b/CDC_Backend/APIs/utils.py index 827742a..83c2a93 100644 --- a/CDC_Backend/APIs/utils.py +++ b/CDC_Backend/APIs/utils.py @@ -20,6 +20,7 @@ from django.http import Http404 from django.shortcuts import get_object_or_404 from django.template.loader import render_to_string from django.utils.html import strip_tags +from django.utils import timezone from google.auth.transport import requests from google.oauth2 import id_token from rest_framework import status @@ -79,7 +80,7 @@ def isAuthorized(allowed_users=None): print(email) user = get_object_or_404(User, email=email) if user: - user.last_login_time = datetime.datetime.now() + user.last_login_time = timezone.now() user.save() if len(set(user.user_type).intersection(set(allowed_users))) or allowed_users == '*': return view_func(request, user.id, user.email, user.user_type, *args, **kwargs) @@ -120,7 +121,7 @@ def generateRandomString(): def saveFile(file, location): prefix = generateRandomString() - file_name = prefix + "_" + file.name + file_name = prefix + "_" + file.name.strip() file_name = re.sub(r'[\\/:*?"<>|]', '_', file_name) @@ -137,8 +138,8 @@ def saveFile(file, location): return file_name -@background_task.background(schedule=10) -def sendEmail(email_to, subject, data, template, attachment_jnf_respone=None): +@background_task.background(schedule=5) +def sendEmail(email_to, subject, data, template, attachment_jnf_response=None): try: if not isinstance(data, dict): data = json.loads(data) @@ -150,11 +151,11 @@ def sendEmail(email_to, subject, data, template, attachment_jnf_respone=None): msg = EmailMultiAlternatives(subject, text_content, email_from, recipient_list) msg.attach_alternative(html_content, "text/html") - if attachment_jnf_respone: - logger.info(attachment_jnf_respone) - pdf = pdfkit.from_string(attachment_jnf_respone['html'], False, + if attachment_jnf_response: + logger.info(attachment_jnf_response) + pdf = pdfkit.from_string(attachment_jnf_response['html'], False, options={"--enable-local-file-access": "", '--dpi': '96'}) - msg.attach(attachment_jnf_respone['name'], pdf, 'application/pdf') + msg.attach(attachment_jnf_response['name'], pdf, 'application/pdf') msg.send() return True except: diff --git a/CDC_Backend/templates/company_email_verification.html b/CDC_Backend/templates/company_email_verification.html index e4b6b19..16f39d4 100644 --- a/CDC_Backend/templates/company_email_verification.html +++ b/CDC_Backend/templates/company_email_verification.html @@ -44,7 +44,7 @@

- We have received your Job Notification. Kindly verify your email by clicking here.

diff --git a/CDC_Backend/templates/company_jnf_response.html b/CDC_Backend/templates/company_jnf_response.html index 93fd488..6e7191c 100644 --- a/CDC_Backend/templates/company_jnf_response.html +++ b/CDC_Backend/templates/company_jnf_response.html @@ -27,7 +27,7 @@ Document - +
cdc logo