Merge branch 'main' into Abhishek28112002-patch-1
This commit is contained in:
commit
b06455cf5b
|
@ -139,3 +139,4 @@ dmypy.json
|
|||
/CDC_Backend/Storage/
|
||||
.idea
|
||||
*.pyc
|
||||
dev.env
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -4,10 +4,50 @@ from django.shortcuts import resolve_url
|
|||
from django.utils.html import format_html
|
||||
from django.utils.safestring import SafeText
|
||||
|
||||
from simple_history.admin import SimpleHistoryAdmin
|
||||
from import_export.admin import ImportExportMixin, ExportMixin
|
||||
from import_export import resources
|
||||
|
||||
from .models import *
|
||||
|
||||
admin.site.register(User)
|
||||
admin.site.register(Admin)
|
||||
|
||||
class ArrayFieldListFilter(admin.SimpleListFilter):
|
||||
"""This is a list filter based on the values
|
||||
from a model's `keywords` ArrayField. """
|
||||
|
||||
title = 'Roles'
|
||||
parameter_name = 'user_type'
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
# Very similar to our code above, but this method must return a
|
||||
# list of tuples: (lookup_value, human-readable value). These
|
||||
# appear in the admin's right sidebar
|
||||
|
||||
keywords = User.objects.values_list("user_type", flat=True)
|
||||
keywords = [(kw, kw) for sublist in keywords for kw in sublist if kw]
|
||||
keywords = sorted(set(keywords))
|
||||
return keywords
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
# when a user clicks on a filter, this method gets called. The
|
||||
# provided queryset with be a queryset of Items, so we need to
|
||||
# filter that based on the clicked keyword.
|
||||
|
||||
lookup_value = self.value() # The clicked keyword. It can be None!
|
||||
if lookup_value:
|
||||
# the __contains lookup expects a list, so...
|
||||
queryset = queryset.filter(user_type__contains=[lookup_value])
|
||||
return queryset
|
||||
|
||||
|
||||
class UserAdmin(ImportExportMixin, SimpleHistoryAdmin):
|
||||
list_display = ('email', 'user_type', 'last_login_time')
|
||||
list_filter = (ArrayFieldListFilter, 'last_login_time')
|
||||
search_fields = ('email', 'user_type')
|
||||
ordering = ('email', 'user_type')
|
||||
|
||||
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
admin.site.site_header = "CDC Recruitment Portal"
|
||||
|
||||
|
@ -17,8 +57,12 @@ def model_admin_url(obj, name=None) -> str:
|
|||
return format_html('<a href="{}">{}</a>', url, name or str(obj))
|
||||
|
||||
|
||||
class StudentAdmin(ImportExportMixin, SimpleHistoryAdmin):
|
||||
pass
|
||||
|
||||
|
||||
@admin.register(Student)
|
||||
class Student(admin.ModelAdmin):
|
||||
class Student(StudentAdmin):
|
||||
list_display = ("roll_no", "name", "batch", "branch", "phone_number", 'can_apply')
|
||||
search_fields = ("roll_no", "name", "phone_number")
|
||||
ordering = ("roll_no", "name", "batch", "branch", "phone_number")
|
||||
|
@ -35,17 +79,57 @@ class Student(admin.ModelAdmin):
|
|||
queryset.update(can_apply=True)
|
||||
self.message_user(request, "Registered the users")
|
||||
|
||||
class PlacementResources(resources.ModelResource):
|
||||
class Meta:
|
||||
model = Placement
|
||||
exclude = ('id','changed_by', 'is_company_details_pdf', 'is_description_pdf',
|
||||
'is_compensation_details_pdf', 'is_selection_procedure_details_pdf')
|
||||
class AdminAdmin(ExportMixin, SimpleHistoryAdmin):
|
||||
resource_class = PlacementResources
|
||||
|
||||
|
||||
class PlacementResources(resources.ModelResource):
|
||||
class Meta:
|
||||
model = Placement
|
||||
exclude = ('id', 'changed_by', 'is_company_details_pdf', 'is_description_pdf',
|
||||
'is_compensation_details_pdf', 'is_selection_procedure_details_pdf')
|
||||
|
||||
|
||||
class AdminAdmin(ExportMixin, SimpleHistoryAdmin):
|
||||
resource_class = PlacementResources
|
||||
|
||||
|
||||
class PlacementResources(resources.ModelResource):
|
||||
class Meta:
|
||||
model = Placement
|
||||
exclude = ('id', 'changed_by', 'is_company_details_pdf', 'is_description_pdf',
|
||||
'is_compensation_details_pdf', 'is_selection_procedure_details_pdf')
|
||||
|
||||
|
||||
class AdminAdmin(ExportMixin, SimpleHistoryAdmin):
|
||||
resource_class = PlacementResources
|
||||
|
||||
|
||||
@admin.register(Placement)
|
||||
class Placement(admin.ModelAdmin):
|
||||
class Placement(AdminAdmin):
|
||||
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',)
|
||||
|
||||
|
||||
class PlacementApplicationResources(resources.ModelResource):
|
||||
class Meta:
|
||||
model = PlacementApplication
|
||||
exclude = ('id', 'changed_by')
|
||||
|
||||
|
||||
class PlacementAdmin(ExportMixin, SimpleHistoryAdmin):
|
||||
resource_class = PlacementApplicationResources
|
||||
|
||||
|
||||
@admin.register(PlacementApplication)
|
||||
class PlacementApplication(admin.ModelAdmin):
|
||||
class PlacementApplication(PlacementAdmin):
|
||||
list_display = ('id', 'Placement', 'Student', 'selected')
|
||||
search_fields = ('id',)
|
||||
ordering = ('id',)
|
||||
|
@ -58,8 +142,18 @@ class PlacementApplication(admin.ModelAdmin):
|
|||
return model_admin_url(obj.student)
|
||||
|
||||
|
||||
class PrePlacementResources(resources.ModelResource):
|
||||
class Meta:
|
||||
model = PrePlacementOffer
|
||||
exclude = ('id', 'changed_by')
|
||||
|
||||
|
||||
class PrePlacementOfferAdmin(ExportMixin, SimpleHistoryAdmin):
|
||||
resource_class = PrePlacementResources
|
||||
|
||||
|
||||
@admin.register(PrePlacementOffer)
|
||||
class PrePlacementOffer(admin.ModelAdmin):
|
||||
class PrePlacementOffer(PrePlacementOfferAdmin):
|
||||
list_display = ('company', 'Student', 'accepted')
|
||||
search_fields = ('company',)
|
||||
ordering = ('company',)
|
||||
|
|
|
@ -8,10 +8,12 @@ urlpatterns = [
|
|||
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('deleteAdditionalInfo/', adminViews.deleteAdditionalInfo, name="Delete Additional Info"),
|
||||
path('addAdditionalInfo/', adminViews.addAdditionalInfo, name="Add Additional Info"),
|
||||
path('getApplications/', adminViews.getApplications, name="Get Applications"),
|
||||
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"),
|
||||
path('getStats/', adminViews.getStats, name="Get Stats"),
|
||||
]
|
||||
|
|
|
@ -39,6 +39,7 @@ def markStatus(request, id, email, user_type):
|
|||
sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE)
|
||||
else:
|
||||
sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE)
|
||||
application.chaged_by = get_object_or_404(User, id=id)
|
||||
application.save()
|
||||
else:
|
||||
raise ValueError("Student - " + i[STUDENT_ID] + " didn't apply for this opening")
|
||||
|
@ -89,6 +90,7 @@ def updateDeadline(request, id, email, user_type):
|
|||
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
|
||||
# Updating deadline date with correct format in datetime field
|
||||
opening.deadline_datetime = datetime.datetime.strptime(data[DEADLINE_DATETIME], '%Y-%m-%d %H:%M:%S %z')
|
||||
opening.changed_by = get_object_or_404(User, id=id)
|
||||
opening.save()
|
||||
return Response({'action': "Update Deadline", 'message': "Deadline Updated"},
|
||||
status=status.HTTP_200_OK)
|
||||
|
@ -102,21 +104,30 @@ def updateDeadline(request, id, email, user_type):
|
|||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized([ADMIN])
|
||||
@isAuthorized([SUPER_ADMIN])
|
||||
@precheck([OPENING_ID, OFFER_ACCEPTED])
|
||||
def updateOfferAccepted(request, id, email, user_type):
|
||||
try:
|
||||
data = request.data
|
||||
print(data)
|
||||
offer_accepted = data[OFFER_ACCEPTED]
|
||||
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
|
||||
opening.offer_accepted = True if data[OFFER_ACCEPTED] == True else False
|
||||
print(opening.offer_accepted)
|
||||
opening.save()
|
||||
if opening.offer_accepted is None:
|
||||
opening.offer_accepted = offer_accepted == "true"
|
||||
opening.changed_by = get_object_or_404(User, id=id)
|
||||
opening.save()
|
||||
if opening.offer_accepted:
|
||||
send_opening_notifications(opening.id)
|
||||
else:
|
||||
raise ValueError("Offer Status already updated")
|
||||
|
||||
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 ValueError as e:
|
||||
return Response({'action': "Update Offer Accepted", 'message': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except:
|
||||
logger.warning("Update Offer Accepted: " + str(sys.exc_info()))
|
||||
return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"},
|
||||
|
@ -131,6 +142,7 @@ def updateEmailVerified(request, id, email, user_type):
|
|||
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.changed_by = get_object_or_404(User, id=id)
|
||||
opening.save()
|
||||
return Response({'action': "Update Email Verified", 'message': "Email Verified Updated"},
|
||||
status=status.HTTP_200_OK)
|
||||
|
@ -145,29 +157,55 @@ def updateEmailVerified(request, id, email, user_type):
|
|||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized([ADMIN])
|
||||
@precheck([OPENING_ID, ADDITIONAL_INFO])
|
||||
def updateAdditionalInfo(request, id, email, user_type):
|
||||
@precheck([OPENING_ID, FIELD])
|
||||
def deleteAdditionalInfo(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]
|
||||
if data[FIELD] in opening.additional_info:
|
||||
opening.additional_info.remove(data[FIELD])
|
||||
opening.changed_by = get_object_or_404(User, id=id)
|
||||
opening.save()
|
||||
return Response({'action': "Delete Additional Info", 'message': "Additional Info Deleted"},
|
||||
status=status.HTTP_200_OK)
|
||||
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)
|
||||
raise ValueError("Additional Info Not Found")
|
||||
except Http404:
|
||||
return Response({'action': "Update Additional Info", 'message': 'Opening Not Found'},
|
||||
return Response({'action': "Delete 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"},
|
||||
return Response({'action': "Delete Additional Info", 'message': "Additional Info not found"},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except Exception as e:
|
||||
logger.warning("Delete Additional Info: " + str(e))
|
||||
return Response({'action': "Delete Additional Info", 'message': "Something went wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized([ADMIN])
|
||||
@precheck([OPENING_ID, FIELD])
|
||||
def addAdditionalInfo(request, id, email, user_type):
|
||||
try:
|
||||
data = request.data
|
||||
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
|
||||
if data[FIELD] not in opening.additional_info:
|
||||
opening.additional_info.append(data[FIELD])
|
||||
opening.save()
|
||||
return Response({'action': "Add Additional Info", 'message': "Additional Info Added"},
|
||||
status=status.HTTP_200_OK)
|
||||
else:
|
||||
raise ValueError("Additional Info Found")
|
||||
|
||||
except Http404:
|
||||
return Response({'action': "Add Additional Info", 'message': 'Opening Not Found'},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except ValueError:
|
||||
return Response({'action': "Add Additional Info", 'message': "Additional Info already found"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except Exception as e:
|
||||
logger.warning("Update Additional Info: " + str(e))
|
||||
return Response({'action': "Update Additional Info", 'message': "Something went wrong"},
|
||||
logger.warning("Add Additional Info: " + str(e))
|
||||
return Response({'action': "Add Additional Info", 'message': "Something went wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
|
@ -199,7 +237,7 @@ def submitApplication(request, id, email, user_type):
|
|||
data = request.data
|
||||
student = get_object_or_404(Student, pk=data[STUDENT_ID])
|
||||
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
|
||||
|
||||
student_user = get_object_or_404(User, id=student.id)
|
||||
if data[APPLICATION_ID] == "":
|
||||
application = PlacementApplication()
|
||||
application.id = generateRandomString()
|
||||
|
@ -216,7 +254,16 @@ def submitApplication(request, id, email, user_type):
|
|||
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": "Placement",
|
||||
"additional_info": dict(json.loads(application.additional_info)),
|
||||
}
|
||||
subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
|
||||
application.changed_by = get_object_or_404(User, id=id)
|
||||
application.save()
|
||||
sendEmail(student_user.email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
|
||||
return Response({'action': "Add Student Application", 'message': "Application added"},
|
||||
status=status.HTTP_200_OK)
|
||||
else:
|
||||
|
@ -235,7 +282,17 @@ def submitApplication(request, id, email, user_type):
|
|||
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": "Placement",
|
||||
"resume": application.resume[16:],
|
||||
"additional_info_items": dict(json.loads(application.additional_info)),
|
||||
}
|
||||
subject = STUDENT_APPLICATION_UPDATED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
|
||||
application.changed_by = get_object_or_404(User, id=id)
|
||||
application.save()
|
||||
sendEmail(student_user.email, subject, data, STUDENT_APPLICATION_UPDATED_TEMPLATE)
|
||||
return Response({'action': "Add Student Application", 'message': "Application updated"},
|
||||
status=status.HTTP_200_OK)
|
||||
else:
|
||||
|
@ -300,7 +357,6 @@ def generateCSV(request, id, email, user_type):
|
|||
status=status.HTTP_200_OK)
|
||||
except:
|
||||
logger.warning("Create csv: " + str(sys.exc_info()))
|
||||
print(sys.exc_info())
|
||||
return Response({'action': "Create csv", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
@ -313,7 +369,7 @@ def addPPO(request, id, email, user_type):
|
|||
data = request.data
|
||||
PPO = PrePlacementOffer()
|
||||
PPO.company = data[COMPANY_NAME]
|
||||
PPO.compensation = data[COMPENSATION_GROSS]
|
||||
PPO.compensation = int(data[COMPENSATION_GROSS])
|
||||
if data[OFFER_ACCEPTED] == "true":
|
||||
PPO.accepted = True
|
||||
elif data[OFFER_ACCEPTED] == "false":
|
||||
|
@ -322,15 +378,15 @@ def addPPO(request, id, email, user_type):
|
|||
PPO.accepted = None
|
||||
PPO.student = get_object_or_404(Student, id=data[STUDENT_ID])
|
||||
PPO.designation = data[DESIGNATION]
|
||||
PPO.tier = data[TIER]
|
||||
PPO.tier = int(data[TIER])
|
||||
if COMPENSATION_DETAILS in data:
|
||||
PPO.compensation_details = data[COMPENSATION_DETAILS]
|
||||
PPO.changed_by = get_object_or_404(User, id=id)
|
||||
PPO.save()
|
||||
return Response({'action': "Add PPO", 'message': "PPO added"},
|
||||
status=status.HTTP_200_OK)
|
||||
except:
|
||||
logger.warning("Add PPO: " + str(sys.exc_info()))
|
||||
print(sys.exc_info())
|
||||
return Response({'action': "Add PPO", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
@ -373,3 +429,205 @@ def getStudentApplication(request, id, email, user_type):
|
|||
logger.warning("Get Student Application: " + str(sys.exc_info()))
|
||||
return Response({'action': "Get Student Application", 'message': "Something Went Wrong"},
|
||||
status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@api_view(['GET'])
|
||||
@isAuthorized(allowed_users=[ADMIN])
|
||||
def getStats(request, id, email, user_type):
|
||||
try:
|
||||
stats = []
|
||||
placement_ids = {}
|
||||
|
||||
tier_count = {
|
||||
"CSE": {
|
||||
"1":0,
|
||||
"2":0,
|
||||
"3":0,
|
||||
"4":0,
|
||||
"5":0,
|
||||
"6":0,
|
||||
"7":0,
|
||||
"psu":0,
|
||||
},
|
||||
"EE": {
|
||||
"1":0,
|
||||
"2":0,
|
||||
"3":0,
|
||||
"4":0,
|
||||
"5":0,
|
||||
"6":0,
|
||||
"7":0,
|
||||
"psu":0,
|
||||
},
|
||||
"MMAE": {
|
||||
"1":0,
|
||||
"2":0,
|
||||
"3":0,
|
||||
"4":0,
|
||||
"5":0,
|
||||
"6":0,
|
||||
"7":0,
|
||||
"psu":0,
|
||||
|
||||
},
|
||||
"Total": {
|
||||
"1":0,
|
||||
"2":0,
|
||||
"3":0,
|
||||
"4":0,
|
||||
"5":0,
|
||||
"6":0,
|
||||
"7":0,
|
||||
"psu":0,
|
||||
},
|
||||
}
|
||||
number_of_students_placed = {
|
||||
"CSE": 0,
|
||||
"EE": 0,
|
||||
"MMAE": 0,
|
||||
"Total": 0,
|
||||
}
|
||||
number_of_students_with_multiple_offers = 0
|
||||
number_of_students_with_no_offers = {
|
||||
"CSE": 0,
|
||||
"EE": 0,
|
||||
"MMAE": 0,
|
||||
"Total": 0,
|
||||
}
|
||||
max_CTC = {
|
||||
"CSE": 0,
|
||||
"EE": 0,
|
||||
"MMAE": 0
|
||||
}
|
||||
average_CTC = {
|
||||
"CSE": 0,
|
||||
"EE": 0,
|
||||
"MMAE": 0
|
||||
}
|
||||
count = {
|
||||
"CSE": 0,
|
||||
"EE": 0,
|
||||
"MMAE": 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
students = Student.objects.all().order_by("roll_no")
|
||||
for student in students.iterator():
|
||||
|
||||
applications = PlacementApplication.objects.filter(student=student, selected=True)
|
||||
ppos = PrePlacementOffer.objects.filter(student=student, accepted=True)
|
||||
|
||||
first_offer_data = None
|
||||
|
||||
second_offer_data = None
|
||||
|
||||
# get the first and second offer
|
||||
offers = []
|
||||
offers.extend(applications)
|
||||
offers.extend(ppos)
|
||||
|
||||
if len(offers) == 0:
|
||||
number_of_students_with_no_offers[student.branch] += 1
|
||||
number_of_students_with_no_offers["Total"] += 1
|
||||
else:
|
||||
number_of_students_placed[student.branch] += 1
|
||||
number_of_students_placed["Total"] += 1
|
||||
if len(offers) > 1:
|
||||
number_of_students_with_multiple_offers += 1
|
||||
|
||||
|
||||
|
||||
for offer in offers:
|
||||
if type(offer) == PrePlacementOffer:
|
||||
if first_offer_data is None:
|
||||
first_offer_data = {
|
||||
"id": offer.id,
|
||||
"company": offer.company,
|
||||
"compensation": offer.compensation,
|
||||
"tier": offer.tier,
|
||||
"type": "PPO",
|
||||
}
|
||||
elif second_offer_data is None:
|
||||
second_offer_data = {
|
||||
"id": offer.id,
|
||||
"company": offer.company,
|
||||
"compensation": offer.compensation,
|
||||
"tier": offer.tier,
|
||||
"type": "PPO",
|
||||
}
|
||||
elif type(offer) == PlacementApplication:
|
||||
if first_offer_data is None:
|
||||
first_offer_data = {
|
||||
"id": offer.placement.id,
|
||||
"company": offer.placement.company_name,
|
||||
"compensation": offer.placement.compensation_CTC,
|
||||
"tier": offer.placement.tier,
|
||||
"type": "Placement",
|
||||
}
|
||||
elif second_offer_data is None:
|
||||
second_offer_data = {
|
||||
"id": offer.placement.id,
|
||||
"company": offer.placement.company_name,
|
||||
"compensation": offer.placement.compensation_CTC,
|
||||
"tier": offer.placement.tier,
|
||||
"type": "Placement",
|
||||
}
|
||||
|
||||
data = {
|
||||
"id": student.id,
|
||||
"name": student.name,
|
||||
"roll_no": student.roll_no,
|
||||
"batch": student.batch,
|
||||
"branch": student.branch,
|
||||
"cpi": student.cpi,
|
||||
"first_offer": first_offer_data['company'] if first_offer_data is not None else None,
|
||||
"first_offer_tier": first_offer_data['tier'] if first_offer_data is not None else None,
|
||||
"first_offer_compensation": first_offer_data['compensation'] if first_offer_data is not None else None,
|
||||
|
||||
"second_offer": second_offer_data['company'] if second_offer_data is not None else None,
|
||||
"second_offer_tier": second_offer_data['tier'] if second_offer_data is not None else None,
|
||||
"second_offer_compensation": second_offer_data['compensation'] if second_offer_data is not None else None,
|
||||
}
|
||||
if first_offer_data is not None:
|
||||
tier_count[student.branch][first_offer_data['tier']] += 1
|
||||
tier_count['Total'][first_offer_data['tier']] += 1
|
||||
max_CTC[student.branch] = max(max_CTC[student.branch], first_offer_data['compensation'])
|
||||
average_CTC[student.branch] += first_offer_data['compensation']
|
||||
count[student.branch] += 1
|
||||
|
||||
if first_offer_data['type'] == "Placement":
|
||||
placement_ids[first_offer_data['company']] = first_offer_data['id']
|
||||
|
||||
if second_offer_data is not None:
|
||||
tier_count[student.branch][second_offer_data['tier']] += 1
|
||||
tier_count['Total'][second_offer_data['tier']] += 1
|
||||
max_CTC[student.branch] = max(max_CTC[student.branch], second_offer_data['compensation'])
|
||||
average_CTC[student.branch] += second_offer_data['compensation']
|
||||
count[student.branch] += 1
|
||||
|
||||
if second_offer_data['type'] == "Placement":
|
||||
placement_ids[second_offer_data['company']] = second_offer_data['id']
|
||||
|
||||
stats.append(data)
|
||||
|
||||
for branch in average_CTC:
|
||||
if count[branch] > 0:
|
||||
average_CTC[branch] /= count[branch]
|
||||
# round off to 2 decimal places
|
||||
average_CTC[branch] = round(average_CTC[branch], 2)
|
||||
else:
|
||||
average_CTC[branch] = 0
|
||||
return Response({'action': "Get Stats", 'message': "Stats fetched", 'stats': stats, 'placement_ids': placement_ids,
|
||||
"tier_count": {br: tier_count[br].values() for br in tier_count},
|
||||
"number_of_students_placed": number_of_students_placed,
|
||||
"number_of_students_with_multiple_offers": number_of_students_with_multiple_offers,
|
||||
"number_of_students_with_no_offers": number_of_students_with_no_offers,
|
||||
"max_CTC": max_CTC,
|
||||
"average_CTC": average_CTC,
|
||||
},
|
||||
status=status.HTTP_200_OK)
|
||||
except:
|
||||
logger.warning("Get Stats: " + str(sys.exc_info()))
|
||||
print(sys.exc_info())
|
||||
return Response({'action': "Get Stats", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
|
|
@ -194,7 +194,7 @@ def addPlacement(request):
|
|||
'%d-%m-%Y').date()
|
||||
|
||||
# Only Allowing Fourth Year for Placement
|
||||
opening.allowed_batch = [FOURTH_YEAR, ]
|
||||
opening.allowed_batch = [2017, 2018, 2019, 2020, 2021]
|
||||
# Check if allowed_branch are valid
|
||||
if data[ALLOWED_BRANCH] is None:
|
||||
raise ValueError('Allowed Branch cannot be empty')
|
||||
|
@ -230,9 +230,14 @@ def addPlacement(request):
|
|||
status=status.HTTP_200_OK)
|
||||
|
||||
except ValueError as e:
|
||||
store_all_files(request)
|
||||
exception_email(data)
|
||||
logger.info("ValueError in addPlacement: " + str(e))
|
||||
return Response({'action': "Add Placement", 'message': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except:
|
||||
store_all_files(request)
|
||||
exception_email(data)
|
||||
logger.warning("Add New Placement: " + str(sys.exc_info()))
|
||||
return Response({'action': "Add Placement", 'message': "Something went wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
@ -276,11 +281,9 @@ def verifyEmail(request):
|
|||
data = {
|
||||
"designation": opening.designation,
|
||||
"opening_type": PLACEMENT,
|
||||
"opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too
|
||||
"company_name": opening.company_name,
|
||||
}
|
||||
json_data = json.dumps(data, default=str)
|
||||
sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), json_data,
|
||||
sendEmail([opening.email, CDC_MAIl_ADDRESS], COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data,
|
||||
COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone)
|
||||
|
||||
return Response({'action': "Verify Email", 'message': "Email Verified Successfully"},
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
import os
|
||||
|
||||
BRANCH_CHOICES = [
|
||||
["CSE", "CSE"],
|
||||
["EE", "EE"],
|
||||
["ME", "ME"],
|
||||
['MMAE', 'MMAE'],
|
||||
['EP', 'EP'],
|
||||
]
|
||||
BRANCHES = [
|
||||
"CSE",
|
||||
"EE",
|
||||
"ME",
|
||||
"MMAE",
|
||||
"EP"
|
||||
]
|
||||
BATCH_CHOICES = [
|
||||
["2021", "2021"],
|
||||
["2020", "2020"],
|
||||
["2019", "2019"],
|
||||
["2018", "2018"]
|
||||
["2018", "2018"],
|
||||
["2017", "2017"],
|
||||
]
|
||||
|
||||
OFFER_CITY_TYPE = [
|
||||
|
@ -29,31 +33,42 @@ TIERS = [
|
|||
['3', 'Tier 3'],
|
||||
['4', 'Tier 4'],
|
||||
['5', 'Tier 5'],
|
||||
['6', 'Tier 6']
|
||||
['6', 'Tier 6'],
|
||||
['7', 'Tier 7'],
|
||||
]
|
||||
|
||||
DEGREE_CHOICES = [
|
||||
['bTech', 'B.Tech'],
|
||||
['ms/phd', 'MS/ PhD'],
|
||||
]
|
||||
|
||||
TOTAL_BRANCHES = 4 # Total No of Branches
|
||||
TOTAL_BATCHES = 4 # Total No of Batches
|
||||
TOTAL_BATCHES = 5 # Total No of Batches
|
||||
|
||||
CDC_MAIl_ADDRESS = 'cdc@iitdh.ac.in'
|
||||
|
||||
# To be Configured Properly
|
||||
CLIENT_ID = "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com" # Google Login Client ID
|
||||
CLIENT_ID = os.environ.get('GOOGLE_OAUTH_CLIENT_ID') # Google Login Client ID
|
||||
|
||||
# To be Configured Properly
|
||||
PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}" # On frontend, this is the URL to be opened
|
||||
LINK_TO_STORAGE_COMPANY_ATTACHMENT = "http://localhost/storage/Company_Attachments/"
|
||||
LINK_TO_STORAGE_RESUME = "http://localhost/storage/Resumes/"
|
||||
LINK_TO_APPLICATIONS_CSV = "http://localhost/storage/Application_CSV/"
|
||||
LINK_TO_EMAIl_VERIFICATION_API = "http://localhost:3000/company/verifyEmail?token={token}"
|
||||
PLACEMENT_OPENING_URL = "https://cdc.iitdh.ac.in/portal/student/dashboard/placements/{id}" # On frontend, this is the URL to be opened
|
||||
LINK_TO_STORAGE_COMPANY_ATTACHMENT = "https://cdc.iitdh.ac.in/storage/Company_Attachments/"
|
||||
LINK_TO_STORAGE_RESUME = "https://cdc.iitdh.ac.in/storage/Resumes/"
|
||||
LINK_TO_APPLICATIONS_CSV = "https://cdc.iitdh.ac.in/storage/Application_CSV/"
|
||||
LINK_TO_EMAIl_VERIFICATION_API = "https://cdc.iitdh.ac.in/portal/company/verifyEmail?token={token}"
|
||||
PDF_FILES_SERVING_ENDPOINT = 'https://cdc.iitdh.ac.in/storage/Company_Attachments/' # TODO: Change this to actual URL
|
||||
|
||||
EMAIL = "email"
|
||||
|
||||
STUDENT = 'student'
|
||||
ADMIN = 'admin'
|
||||
COMPANY = ''
|
||||
SUPER_ADMIN = 's_admin'
|
||||
COMPANY = 'company'
|
||||
TIER = 'tier'
|
||||
# To be Configured Properly
|
||||
FOURTH_YEAR = '2019'
|
||||
MAX_OFFERS_PER_STUDENT = 2
|
||||
MAX_RESUMES_PER_STUDENT = 3
|
||||
EMAIL_VERIFICATION_TOKEN_TTL = 48 # in hours
|
||||
JNF_TEXT_MAX_CHARACTER_COUNT = 100
|
||||
JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT = 200
|
||||
|
@ -70,6 +85,7 @@ RESUME_FILE_NAME = 'resume_file_name'
|
|||
APPLICATION_ID = "application_id"
|
||||
OPENING_ID = "opening_id"
|
||||
ADDITIONAL_INFO = "additional_info"
|
||||
FIELD = "field"
|
||||
|
||||
STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications"
|
||||
|
||||
|
@ -133,21 +149,25 @@ EXCLUDE_IN_PDF = ['id', 'is_company_details_pdf', 'offer_accepted', 'is_descript
|
|||
'email_verified', 'created_at']
|
||||
SPECIAL_FORMAT_IN_PDF = ['website', 'company_details_pdf_names', 'description_pdf_names',
|
||||
'compensation_details_pdf_names',
|
||||
'selection_procedure_pdf_names']
|
||||
'selection_procedure_details_pdf_names']
|
||||
|
||||
COMPANY_OPENING_ERROR_TEMPLATE = "Alert! Error submitting opening for {company_name}."
|
||||
COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - Career Development Cell, IIT Dharwad"
|
||||
STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}'
|
||||
STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status - {company_name} - {id}'
|
||||
STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - {company_name}'
|
||||
STUDENT_APPLICATION_UPDATED_TEMPLATE_SUBJECT = 'CDC - Application Updated - {company_name}'
|
||||
COMPANY_EMAIl_VERIFICATION_TEMPLATE_SUBJECT = 'Email Verification - Career Development Cell, IIT Dharwad'
|
||||
NOTIFY_STUDENTS_OPENING_TEMPLATE_SUBJECT = 'Placement Opportunity at {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'
|
||||
STUDENT_APPLICATION_UPDATED_TEMPLATE = 'student_application_updated.html'
|
||||
COMPANY_EMAIL_VERIFICATION_TEMPLATE = 'company_email_verification.html'
|
||||
COMPANY_JNF_RESPONSE_TEMPLATE = 'company_jnf_response.html'
|
||||
NOTIFY_STUDENTS_OPENING_TEMPLATE = 'notify_students_new_opening.html'
|
||||
|
||||
APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI',
|
||||
'Resume', 'Selected', ]
|
||||
|
||||
PDF_FILES_SERVING_ENDPOINT = 'http://localhost/storage/Company_Attachments/' # TODO: Change this to actual URL
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from simple_history.models import HistoricalRecords
|
||||
|
||||
from .constants import *
|
||||
|
||||
|
@ -10,9 +11,10 @@ from .constants import *
|
|||
|
||||
class User(models.Model):
|
||||
email = models.EmailField(primary_key=True, blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT)
|
||||
id = models.CharField(blank=False, max_length=25)
|
||||
id = models.CharField(blank=False, max_length=25, db_index=True)
|
||||
user_type = ArrayField(models.CharField(blank=False, max_length=10), size=4, default=list, blank=False)
|
||||
last_login_time = models.DateTimeField(default=timezone.now)
|
||||
history = HistoricalRecords()
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "User"
|
||||
|
@ -30,18 +32,46 @@ class Student(models.Model):
|
|||
default=list, blank=True)
|
||||
cpi = models.DecimalField(decimal_places=2, max_digits=4)
|
||||
can_apply = models.BooleanField(default=True, verbose_name='Registered')
|
||||
changed_by = models.ForeignKey(User, blank=True, on_delete=models.RESTRICT, default=None, null=True)
|
||||
degree = models.CharField(choices=DEGREE_CHOICES, blank=False, max_length=10, default=DEGREE_CHOICES[0][0])
|
||||
history = HistoricalRecords(user_model=User)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.roll_no)
|
||||
|
||||
@property
|
||||
def _history_user(self):
|
||||
return self.changed_by
|
||||
|
||||
@_history_user.setter
|
||||
def _history_user(self, value):
|
||||
if isinstance(value, User):
|
||||
self.changed_by = value
|
||||
else:
|
||||
self.changed_by = None
|
||||
|
||||
|
||||
class Admin(models.Model):
|
||||
id = models.CharField(blank=False, max_length=15, primary_key=True)
|
||||
name = models.CharField(blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT)
|
||||
changed_by = models.ForeignKey(User, blank=True, on_delete=models.RESTRICT, default=None, null=True)
|
||||
history = HistoricalRecords(user_model=User)
|
||||
|
||||
@property
|
||||
def _history_user(self):
|
||||
return self.changed_by
|
||||
|
||||
@_history_user.setter
|
||||
def _history_user(self, value):
|
||||
if isinstance(value, User):
|
||||
self.changed_by = value
|
||||
else:
|
||||
self.changed_by = None
|
||||
|
||||
|
||||
def two_day_after_today():
|
||||
return timezone.now() + timezone.timedelta(days=2)
|
||||
# round off to nearest day
|
||||
return timezone.now().replace(hour=0, minute=0, second=0, microsecond=0) + timezone.timedelta(days=2)
|
||||
|
||||
|
||||
class Placement(models.Model):
|
||||
|
@ -53,7 +83,7 @@ class Placement(models.Model):
|
|||
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 = models.CharField(max_length=JNF_TEXTAREA_MAX_CHARACTER_COUNT, default=None, null=True, blank=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)
|
||||
|
@ -114,6 +144,8 @@ class Placement(models.Model):
|
|||
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)
|
||||
changed_by = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
|
||||
history = HistoricalRecords(user_model=User)
|
||||
|
||||
def format(self):
|
||||
if self.company_name is not None:
|
||||
|
@ -156,7 +188,19 @@ class Placement(models.Model):
|
|||
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)]
|
||||
self.additional_info = [info.strip()[:JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT] for info in
|
||||
list(self.additional_info)]
|
||||
|
||||
@property
|
||||
def _history_user(self):
|
||||
return self.changed_by
|
||||
|
||||
@_history_user.setter
|
||||
def _history_user(self, value):
|
||||
if isinstance(value, User):
|
||||
self.changed_by = value
|
||||
else:
|
||||
self.changed_by = None
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
''' On save, add timestamps '''
|
||||
|
@ -179,6 +223,8 @@ class PlacementApplication(models.Model):
|
|||
selected = models.BooleanField(null=True, default=None, blank=True)
|
||||
applied_at = models.DateTimeField(blank=False, default=None, null=True)
|
||||
updated_at = models.DateTimeField(blank=False, default=None, null=True)
|
||||
changed_by = models.ForeignKey(User, blank=False, on_delete=models.RESTRICT, default=None, null=True)
|
||||
history = HistoricalRecords(user_model=User)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
''' On save, add timestamps '''
|
||||
|
@ -188,6 +234,17 @@ class PlacementApplication(models.Model):
|
|||
|
||||
return super(PlacementApplication, self).save(*args, **kwargs)
|
||||
|
||||
@property
|
||||
def _history_user(self):
|
||||
return self.changed_by
|
||||
|
||||
@_history_user.setter
|
||||
def _history_user(self, value):
|
||||
if isinstance(value, User):
|
||||
self.changed_by = value
|
||||
else:
|
||||
self.changed_by = None
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Placement Applications"
|
||||
unique_together = ('placement_id', 'student_id')
|
||||
|
@ -204,5 +261,31 @@ class PrePlacementOffer(models.Model):
|
|||
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)
|
||||
designation = models.CharField(blank=False, max_length=25, default=None, null=True)
|
||||
designation = models.CharField(blank=False, max_length=100, default=None, null=True)
|
||||
accepted = models.BooleanField(default=None, null=True)
|
||||
changed_by = models.ForeignKey(User, blank=False, on_delete=models.RESTRICT, default=None, null=True)
|
||||
history = HistoricalRecords(user_model=User)
|
||||
|
||||
@property
|
||||
def _history_user(self):
|
||||
return self.changed_by
|
||||
|
||||
@_history_user.setter
|
||||
def _history_user(self, value):
|
||||
if isinstance(value, User):
|
||||
self.changed_by = value
|
||||
else:
|
||||
self.changed_by = None
|
||||
|
||||
|
||||
class Contributor(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
name = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="")
|
||||
email = models.EmailField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", unique=True)
|
||||
github_id = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", unique=True)
|
||||
linkedin = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, unique=True, null=True)
|
||||
commits = models.IntegerField(blank=False, default=0)
|
||||
image = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
|
@ -162,7 +162,8 @@ class PlacementApplicationSerializer(serializers.ModelSerializer):
|
|||
return data
|
||||
|
||||
def get_resume_link(self, obj):
|
||||
ele = {'link': LINK_TO_STORAGE_RESUME + urllib.parse.quote(obj.id + "/" + obj.resume), 'name': obj.resume}
|
||||
ele = {'link': LINK_TO_STORAGE_RESUME + urllib.parse.quote(str(obj.student.roll_no) + "/" + obj.resume),
|
||||
'name': obj.resume}
|
||||
return ele
|
||||
|
||||
class Meta:
|
||||
|
@ -185,3 +186,9 @@ class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = PlacementApplication
|
||||
exclude = ['placement', 'resume']
|
||||
|
||||
|
||||
class ContributorSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Contributor
|
||||
fields = '__all__'
|
||||
|
|
|
@ -9,4 +9,6 @@ urlpatterns = [
|
|||
path("addResume/", studentViews.addResume, name="Upload Resume"),
|
||||
path("deleteResume/", studentViews.deleteResume, name="Upload Resume"),
|
||||
path("submitApplication/", studentViews.submitApplication, name="Submit Application"),
|
||||
path("deleteApplication/", studentViews.deleteApplication, name="Delete Application"),
|
||||
path("getContributorStats/", studentViews.getContributorStats, name="Get Contributor Stats"),
|
||||
]
|
||||
|
|
|
@ -40,17 +40,23 @@ def addResume(request, id, email, user_type):
|
|||
student = get_object_or_404(Student, id=id)
|
||||
files = request.FILES
|
||||
|
||||
if len(student.resumes) >= MAX_RESUMES_PER_STUDENT:
|
||||
raise PermissionError('Max Number of Resumes limit reached')
|
||||
|
||||
file = files['file']
|
||||
destination_path = STORAGE_DESTINATION_RESUMES + str(student.roll_no) + "/"
|
||||
file_name = saveFile(file, destination_path)
|
||||
student.resumes.append(file_name)
|
||||
|
||||
student.changed_by = get_object_or_404(User, id=id)
|
||||
student.save()
|
||||
return Response({'action': "Upload Resume", 'message': "Resume Added"},
|
||||
status=status.HTTP_200_OK)
|
||||
except Http404:
|
||||
return Response({'action': "Upload Resume", 'message': 'Student Not Found'},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except PermissionError:
|
||||
return Response({'action': "Upload Resume", 'message': 'Max Number of Resumes limit reached'},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except:
|
||||
if path.exists(destination_path):
|
||||
logger.error("Upload Resume: Error in Saving Resume")
|
||||
|
@ -71,7 +77,10 @@ def getDashboard(request, id, email, user_type):
|
|||
allowed_branch__contains=[studentDetails.branch],
|
||||
deadline_datetime__gte=datetime.datetime.now(),
|
||||
offer_accepted=True, email_verified=True).order_by('deadline_datetime')
|
||||
placementsdata = PlacementSerializerForStudent(placements, many=True).data
|
||||
filtered_placements = placement_eligibility_filters(studentDetails, placements)
|
||||
|
||||
placementsdata = PlacementSerializerForStudent(filtered_placements, many=True).data
|
||||
|
||||
placementApplications = PlacementApplication.objects.filter(student_id=id)
|
||||
placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data
|
||||
return Response(
|
||||
|
@ -83,7 +92,6 @@ def getDashboard(request, id, email, user_type):
|
|||
status=status.HTTP_404_NOT_FOUND)
|
||||
except:
|
||||
logger.warning("Get Dashboard -Student: " + str(sys.exc_info()))
|
||||
print(sys.exc_info())
|
||||
|
||||
return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
@ -104,6 +112,7 @@ def deleteResume(request, id, email, user_type):
|
|||
if path.exists(destination_path):
|
||||
# remove(destination_path)
|
||||
student.resumes.remove(file_name)
|
||||
student.changed_by = get_object_or_404(User, id=id)
|
||||
student.save()
|
||||
return Response({'action': "Delete Resume", 'message': "Resume Deleted"},
|
||||
status=status.HTTP_200_OK)
|
||||
|
@ -177,7 +186,7 @@ def submitApplication(request, id, email, user_type):
|
|||
}
|
||||
subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
|
||||
sendEmail(email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
|
||||
|
||||
application.changed_by = get_object_or_404(User, id=id)
|
||||
application.save()
|
||||
return Response({'action': "Submit Application", 'message': "Application Submitted"},
|
||||
status=status.HTTP_200_OK)
|
||||
|
@ -192,8 +201,49 @@ def submitApplication(request, id, email, user_type):
|
|||
status=status.HTTP_404_NOT_FOUND)
|
||||
except:
|
||||
logger.warning("Submit Application: " + str(sys.exc_info()))
|
||||
print(traceback.format_exc())
|
||||
|
||||
print(sys.exc_info())
|
||||
return Response({'action': "Submit Application", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized(allowed_users=[STUDENT])
|
||||
@precheck(required_data=[APPLICATION_ID])
|
||||
def deleteApplication(request, id, email, user_type):
|
||||
try:
|
||||
data = request.data
|
||||
application = get_object_or_404(PlacementApplication, id=data[APPLICATION_ID],
|
||||
student_id=id)
|
||||
if application.placement.deadline_datetime < timezone.now():
|
||||
raise PermissionError("Deadline Passed")
|
||||
|
||||
application.delete()
|
||||
return Response({'action': "Delete Application", 'message': "Application Deleted"},
|
||||
status=status.HTTP_200_OK)
|
||||
except Http404 as e:
|
||||
return Response({'action': "Delete Application", 'message': str(e)},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except PermissionError as e:
|
||||
return Response({'action': "Delete Application", 'message': str(e)},
|
||||
status=status.HTTP_403_FORBIDDEN)
|
||||
except:
|
||||
logger.warning("Delete Application: " + str(sys.exc_info()))
|
||||
|
||||
return Response({'action': "Delete Application", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@isAuthorized(allowed_users='*')
|
||||
def getContributorStats(request, id, email, user_type):
|
||||
try:
|
||||
contributors = Contributor.objects.all()
|
||||
serialized_data = ContributorSerializer(contributors, many=True).data
|
||||
return Response({'action': "Get Contributor Stats", 'message': "Contributor Stats Fetched",
|
||||
'data': serialized_data},
|
||||
status=status.HTTP_200_OK)
|
||||
except:
|
||||
logger.warning("Get Contributor Stats: " + str(sys.exc_info()))
|
||||
|
||||
return Response({'action': "Get Contributor Stats", 'message': "Something Went Wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
|
@ -12,6 +12,7 @@ from os import path, remove
|
|||
import background_task
|
||||
import jwt
|
||||
import pdfkit
|
||||
import pytz
|
||||
import requests as rq
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
|
@ -27,7 +28,7 @@ from rest_framework import status
|
|||
from rest_framework.response import Response
|
||||
|
||||
from .constants import *
|
||||
from .models import User, PrePlacementOffer, PlacementApplication, Placement
|
||||
from .models import User, PrePlacementOffer, PlacementApplication, Placement, Student
|
||||
|
||||
logger = logging.getLogger('db')
|
||||
|
||||
|
@ -57,6 +58,7 @@ def precheck(required_data=None):
|
|||
|
||||
return view_func(request, *args, **kwargs)
|
||||
except:
|
||||
logger.warning("Pre check: " + str(sys.exc_info()))
|
||||
return Response({'action': "Pre check", 'message': "Something went wrong"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
@ -77,7 +79,6 @@ def isAuthorized(allowed_users=None):
|
|||
token_id = headers['HTTP_AUTHORIZATION'][7:]
|
||||
idinfo = id_token.verify_oauth2_token(token_id, requests.Request(), CLIENT_ID)
|
||||
email = idinfo[EMAIL]
|
||||
print(email)
|
||||
user = get_object_or_404(User, email=email)
|
||||
if user:
|
||||
user.last_login_time = timezone.now()
|
||||
|
@ -138,7 +139,7 @@ def saveFile(file, location):
|
|||
return file_name
|
||||
|
||||
|
||||
@background_task.background(schedule=5)
|
||||
@background_task.background(schedule=2)
|
||||
def sendEmail(email_to, subject, data, template, attachment_jnf_response=None):
|
||||
try:
|
||||
if not isinstance(data, dict):
|
||||
|
@ -147,12 +148,15 @@ def sendEmail(email_to, subject, data, template, attachment_jnf_response=None):
|
|||
text_content = strip_tags(html_content)
|
||||
|
||||
email_from = settings.EMAIL_HOST_USER
|
||||
recipient_list = [str(email_to), ]
|
||||
if type(email_to) is list:
|
||||
recipient_list = [str(email) for email in email_to]
|
||||
else:
|
||||
recipient_list = [str(email_to), ]
|
||||
|
||||
msg = EmailMultiAlternatives(subject, text_content, email_from, recipient_list)
|
||||
msg.attach_alternative(html_content, "text/html")
|
||||
if attachment_jnf_response:
|
||||
logger.info(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_response['name'], pdf, 'application/pdf')
|
||||
|
@ -160,7 +164,6 @@ def sendEmail(email_to, subject, data, template, attachment_jnf_response=None):
|
|||
return True
|
||||
except:
|
||||
logger.error("Send Email: " + str(sys.exc_info()))
|
||||
print(str(sys.exc_info()[1]))
|
||||
return False
|
||||
|
||||
|
||||
|
@ -169,31 +172,36 @@ def PlacementApplicationConditions(student, placement):
|
|||
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(student=student, accepted=True)
|
||||
# find lenght of PPO
|
||||
print(PPO)
|
||||
print(len(PPO), "ere")
|
||||
PPO_PSU = [i for i in PPO if i.tier == 'psu']
|
||||
# find length of PPO
|
||||
if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT:
|
||||
raise PermissionError("Max Applications Reached for the Season")
|
||||
|
||||
if len(selected_companies_PSU) > 0:
|
||||
raise PermissionError('Selected for PSU Can\'t apply anymore')
|
||||
|
||||
if len(PPO_PSU) > 0:
|
||||
raise PermissionError('Selected for PSU Can\'t apply anymore')
|
||||
|
||||
if placement.tier == 'psu':
|
||||
return True, "Conditions Satisfied"
|
||||
|
||||
for i in selected_companies:
|
||||
print(int(i.placement.tier) < int(placement.tier), int(i.placement.tier), int(placement.tier))
|
||||
if int(i.placement.tier) < int(placement.tier):
|
||||
return False, "Can't apply for this tier"
|
||||
|
||||
for i in PPO:
|
||||
if int(i.tier) < int(placement.tier):
|
||||
return False, "Can't apply for this tier"
|
||||
|
||||
if student.degree != 'bTech' and not placement.rs_eligible:
|
||||
raise PermissionError("Can't apply for this placement")
|
||||
|
||||
return True, "Conditions Satisfied"
|
||||
|
||||
except PermissionError as e:
|
||||
return False, e
|
||||
except:
|
||||
print(sys.exc_info())
|
||||
print(traceback.format_exc())
|
||||
|
||||
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
|
||||
return False, "_"
|
||||
|
||||
|
@ -231,7 +239,6 @@ def getTier(compensation_gross, is_psu=False):
|
|||
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, "_"
|
||||
|
||||
|
@ -248,36 +255,35 @@ def generateOneTimeVerificationLink(email, opening_id, opening_type):
|
|||
link = LINK_TO_EMAIl_VERIFICATION_API.format(token=token)
|
||||
return True, link
|
||||
except:
|
||||
print(sys.exc_info())
|
||||
logger.warning("Utils - generateOneTimeVerificationLink: " + str(sys.exc_info()))
|
||||
return False, "_"
|
||||
|
||||
|
||||
def verify_recaptcha(request):
|
||||
try:
|
||||
print(settings.RECAPTCHA_SECRET_KEY)
|
||||
data = {
|
||||
'secret': settings.RECAPTCHA_SECRET_KEY,
|
||||
'response': request
|
||||
}
|
||||
print(data)
|
||||
r = rq.post('https://www.google.com/recaptcha/api/siteverify', data=data)
|
||||
result = r.json()
|
||||
# logger.info("Recaptcha Response: " + str(result)+"request: "+str(data))
|
||||
|
||||
print(result, "Result")
|
||||
if not result['success']:
|
||||
logger.warning("Utils - verify_recaptcha: " + str(result))
|
||||
return result['success']
|
||||
except:
|
||||
# get exception line number
|
||||
print(sys.exc_info())
|
||||
print(traceback.format_exc())
|
||||
logger.warning("Utils - verify_recaptcha: " + str(sys.exc_info()))
|
||||
return False, "_"
|
||||
|
||||
|
||||
def opening_description_table_html(opening):
|
||||
details = model_to_dict(opening, fields=[field.name for field in Placement._meta.fields],
|
||||
exclude=EXCLUDE_IN_PDF)
|
||||
# check typing of opening
|
||||
if isinstance(opening, Placement):
|
||||
details = model_to_dict(opening, fields=[field.name for field in Placement._meta.fields],
|
||||
exclude=EXCLUDE_IN_PDF)
|
||||
# check typing of opening is query dict
|
||||
else: # if isinstance(opening, QueryDict):
|
||||
details = opening
|
||||
keys = list(details.keys())
|
||||
newdetails = {}
|
||||
for key in keys:
|
||||
|
@ -287,7 +293,7 @@ def opening_description_table_html(opening):
|
|||
if key == |