Merge branch 'main' into Abhishek28112002-patch-1

This commit is contained in:
karthik mv 2023-05-30 15:03:39 +05:30 committed by GitHub
commit b06455cf5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 995 additions and 131 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

1
.gitignore vendored
View File

@ -139,3 +139,4 @@ dmypy.json
/CDC_Backend/Storage/ /CDC_Backend/Storage/
.idea .idea
*.pyc *.pyc
dev.env

BIN
CDC_Backend.zip Normal file

Binary file not shown.

BIN
CDC_Backend/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -4,10 +4,50 @@ from django.shortcuts import resolve_url
from django.utils.html import format_html from django.utils.html import format_html
from django.utils.safestring import SafeText 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 * 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" 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)) return format_html('<a href="{}">{}</a>', url, name or str(obj))
class StudentAdmin(ImportExportMixin, SimpleHistoryAdmin):
pass
@admin.register(Student) @admin.register(Student)
class Student(admin.ModelAdmin): class Student(StudentAdmin):
list_display = ("roll_no", "name", "batch", "branch", "phone_number", 'can_apply') list_display = ("roll_no", "name", "batch", "branch", "phone_number", 'can_apply')
search_fields = ("roll_no", "name", "phone_number") search_fields = ("roll_no", "name", "phone_number")
ordering = ("roll_no", "name", "batch", "branch", "phone_number") ordering = ("roll_no", "name", "batch", "branch", "phone_number")
@ -35,17 +79,57 @@ class Student(admin.ModelAdmin):
queryset.update(can_apply=True) queryset.update(can_apply=True)
self.message_user(request, "Registered the users") 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) @admin.register(Placement)
class Placement(admin.ModelAdmin): class Placement(AdminAdmin):
list_display = (COMPANY_NAME, CONTACT_PERSON_NAME, PHONE_NUMBER, 'tier', 'compensation_CTC') list_display = (COMPANY_NAME, CONTACT_PERSON_NAME, PHONE_NUMBER, 'tier', 'compensation_CTC')
search_fields = (COMPANY_NAME, CONTACT_PERSON_NAME) search_fields = (COMPANY_NAME, CONTACT_PERSON_NAME)
ordering = (COMPANY_NAME, CONTACT_PERSON_NAME, 'tier', 'compensation_CTC') ordering = (COMPANY_NAME, CONTACT_PERSON_NAME, 'tier', 'compensation_CTC')
list_filter = ('tier',) 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) @admin.register(PlacementApplication)
class PlacementApplication(admin.ModelAdmin): class PlacementApplication(PlacementAdmin):
list_display = ('id', 'Placement', 'Student', 'selected') list_display = ('id', 'Placement', 'Student', 'selected')
search_fields = ('id',) search_fields = ('id',)
ordering = ('id',) ordering = ('id',)
@ -58,8 +142,18 @@ class PlacementApplication(admin.ModelAdmin):
return model_admin_url(obj.student) 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) @admin.register(PrePlacementOffer)
class PrePlacementOffer(admin.ModelAdmin): class PrePlacementOffer(PrePlacementOfferAdmin):
list_display = ('company', 'Student', 'accepted') list_display = ('company', 'Student', 'accepted')
search_fields = ('company',) search_fields = ('company',)
ordering = ('company',) ordering = ('company',)

View File

@ -8,10 +8,12 @@ urlpatterns = [
path('updateDeadline/', adminViews.updateDeadline, name="Update Deadline"), path('updateDeadline/', adminViews.updateDeadline, name="Update Deadline"),
path('updateOfferAccepted/', adminViews.updateOfferAccepted, name="Update Offer Accepted"), path('updateOfferAccepted/', adminViews.updateOfferAccepted, name="Update Offer Accepted"),
path('updateEmailVerified', adminViews.updateEmailVerified, name="Update Email Verified"), 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('getApplications/', adminViews.getApplications, name="Get Applications"),
path("submitApplication/", adminViews.submitApplication, name="Submit Application"), path("submitApplication/", adminViews.submitApplication, name="Submit Application"),
path('generateCSV/', adminViews.generateCSV, name="Generate CSV"), path('generateCSV/', adminViews.generateCSV, name="Generate CSV"),
path('addPPO/', adminViews.addPPO, name="Add PPO"), path('addPPO/', adminViews.addPPO, name="Add PPO"),
path('getStudentApplication/', adminViews.getStudentApplication, name="Get student application"), path('getStudentApplication/', adminViews.getStudentApplication, name="Get student application"),
path('getStats/', adminViews.getStats, name="Get Stats"),
] ]

View File

@ -39,6 +39,7 @@ def markStatus(request, id, email, user_type):
sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE) sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE)
else: else:
sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE) sendEmail(email, subject, data, STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE)
application.chaged_by = get_object_or_404(User, id=id)
application.save() application.save()
else: else:
raise ValueError("Student - " + i[STUDENT_ID] + " didn't apply for this opening") 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]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
# Updating deadline date with correct format in datetime field # 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.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() opening.save()
return Response({'action': "Update Deadline", 'message': "Deadline Updated"}, return Response({'action': "Update Deadline", 'message': "Deadline Updated"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
@ -102,21 +104,30 @@ def updateDeadline(request, id, email, user_type):
@api_view(['POST']) @api_view(['POST'])
@isAuthorized([ADMIN]) @isAuthorized([SUPER_ADMIN])
@precheck([OPENING_ID, OFFER_ACCEPTED]) @precheck([OPENING_ID, OFFER_ACCEPTED])
def updateOfferAccepted(request, id, email, user_type): def updateOfferAccepted(request, id, email, user_type):
try: try:
data = request.data data = request.data
print(data) offer_accepted = data[OFFER_ACCEPTED]
opening = get_object_or_404(Placement, pk=data[OPENING_ID]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
opening.offer_accepted = True if data[OFFER_ACCEPTED] == True else False if opening.offer_accepted is None:
print(opening.offer_accepted) opening.offer_accepted = offer_accepted == "true"
opening.save() 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"}, return Response({'action': "Update Offer Accepted", 'message': "Offer Accepted Updated"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404: except Http404:
return Response({'action': "Update Offer Accepted", 'message': 'Opening Not Found'}, return Response({'action': "Update Offer Accepted", 'message': 'Opening Not Found'},
status=status.HTTP_404_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: except:
logger.warning("Update Offer Accepted: " + str(sys.exc_info())) logger.warning("Update Offer Accepted: " + str(sys.exc_info()))
return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"}, return Response({'action': "Update Offer Accepted", 'message': "Something went wrong"},
@ -131,6 +142,7 @@ def updateEmailVerified(request, id, email, user_type):
data = request.data data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
opening.email_verified = True if data[EMAIL_VERIFIED] == "true" else False opening.email_verified = True if data[EMAIL_VERIFIED] == "true" else False
opening.changed_by = get_object_or_404(User, id=id)
opening.save() opening.save()
return Response({'action': "Update Email Verified", 'message': "Email Verified Updated"}, return Response({'action': "Update Email Verified", 'message': "Email Verified Updated"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
@ -145,29 +157,55 @@ def updateEmailVerified(request, id, email, user_type):
@api_view(['POST']) @api_view(['POST'])
@isAuthorized([ADMIN]) @isAuthorized([ADMIN])
@precheck([OPENING_ID, ADDITIONAL_INFO]) @precheck([OPENING_ID, FIELD])
def updateAdditionalInfo(request, id, email, user_type): def deleteAdditionalInfo(request, id, email, user_type):
try: try:
data = request.data data = request.data
opening = get_object_or_404(Placement, pk=data[OPENING_ID]) opening = get_object_or_404(Placement, pk=data[OPENING_ID])
if data[ADDITIONAL_INFO] == "": if data[FIELD] in opening.additional_info:
opening.additional_info = [] opening.additional_info.remove(data[FIELD])
elif isinstance(data[ADDITIONAL_INFO], list): opening.changed_by = get_object_or_404(User, id=id)
opening.additional_info = data[ADDITIONAL_INFO] opening.save()
return Response({'action': "Delete Additional Info", 'message': "Additional Info Deleted"},
status=status.HTTP_200_OK)
else: else:
raise ValueError("Additional Info must be a list") raise ValueError("Additional Info Not Found")
opening.save()
return Response({'action': "Update Additional Info", 'message': "Additional Info Updated"},
status=status.HTTP_200_OK)
except Http404: 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) status=status.HTTP_404_NOT_FOUND)
except ValueError: 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) status=status.HTTP_400_BAD_REQUEST)
except Exception as e: except Exception as e:
logger.warning("Update Additional Info: " + str(e)) logger.warning("Add Additional Info: " + str(e))
return Response({'action': "Update Additional Info", 'message': "Something went wrong"}, return Response({'action': "Add Additional Info", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -199,7 +237,7 @@ def submitApplication(request, id, email, user_type):
data = request.data data = request.data
student = get_object_or_404(Student, pk=data[STUDENT_ID]) student = get_object_or_404(Student, pk=data[STUDENT_ID])
opening = get_object_or_404(Placement, pk=data[OPENING_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] == "": if data[APPLICATION_ID] == "":
application = PlacementApplication() application = PlacementApplication()
application.id = generateRandomString() application.id = generateRandomString()
@ -216,7 +254,16 @@ def submitApplication(request, id, email, user_type):
else: else:
additional_info[i] = data[ADDITIONAL_INFO][i] additional_info[i] = data[ADDITIONAL_INFO][i]
application.additional_info = json.dumps(additional_info) 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() application.save()
sendEmail(student_user.email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
return Response({'action': "Add Student Application", 'message': "Application added"}, return Response({'action': "Add Student Application", 'message': "Application added"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
else: else:
@ -235,7 +282,17 @@ def submitApplication(request, id, email, user_type):
additional_info[i] = data[ADDITIONAL_INFO][i] additional_info[i] = data[ADDITIONAL_INFO][i]
application.additional_info = json.dumps(additional_info) 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() application.save()
sendEmail(student_user.email, subject, data, STUDENT_APPLICATION_UPDATED_TEMPLATE)
return Response({'action': "Add Student Application", 'message': "Application updated"}, return Response({'action': "Add Student Application", 'message': "Application updated"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
else: else:
@ -300,7 +357,6 @@ def generateCSV(request, id, email, user_type):
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except: except:
logger.warning("Create csv: " + str(sys.exc_info())) logger.warning("Create csv: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Create csv", 'message': "Something Went Wrong"}, return Response({'action': "Create csv", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -313,7 +369,7 @@ def addPPO(request, id, email, user_type):
data = request.data data = request.data
PPO = PrePlacementOffer() PPO = PrePlacementOffer()
PPO.company = data[COMPANY_NAME] PPO.company = data[COMPANY_NAME]
PPO.compensation = data[COMPENSATION_GROSS] PPO.compensation = int(data[COMPENSATION_GROSS])
if data[OFFER_ACCEPTED] == "true": if data[OFFER_ACCEPTED] == "true":
PPO.accepted = True PPO.accepted = True
elif data[OFFER_ACCEPTED] == "false": elif data[OFFER_ACCEPTED] == "false":
@ -322,15 +378,15 @@ def addPPO(request, id, email, user_type):
PPO.accepted = None PPO.accepted = None
PPO.student = get_object_or_404(Student, id=data[STUDENT_ID]) PPO.student = get_object_or_404(Student, id=data[STUDENT_ID])
PPO.designation = data[DESIGNATION] PPO.designation = data[DESIGNATION]
PPO.tier = data[TIER] PPO.tier = int(data[TIER])
if COMPENSATION_DETAILS in data: if COMPENSATION_DETAILS in data:
PPO.compensation_details = data[COMPENSATION_DETAILS] PPO.compensation_details = data[COMPENSATION_DETAILS]
PPO.changed_by = get_object_or_404(User, id=id)
PPO.save() PPO.save()
return Response({'action': "Add PPO", 'message': "PPO added"}, return Response({'action': "Add PPO", 'message': "PPO added"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except: except:
logger.warning("Add PPO: " + str(sys.exc_info())) logger.warning("Add PPO: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Add PPO", 'message': "Something Went Wrong"}, return Response({'action': "Add PPO", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) 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())) logger.warning("Get Student Application: " + str(sys.exc_info()))
return Response({'action': "Get Student Application", 'message': "Something Went Wrong"}, return Response({'action': "Get Student Application", 'message': "Something Went Wrong"},
status.HTTP_400_BAD_REQUEST) 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)

View File

@ -194,7 +194,7 @@ def addPlacement(request):
'%d-%m-%Y').date() '%d-%m-%Y').date()
# Only Allowing Fourth Year for Placement # 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 # Check if allowed_branch are valid
if data[ALLOWED_BRANCH] is None: if data[ALLOWED_BRANCH] is None:
raise ValueError('Allowed Branch cannot be empty') raise ValueError('Allowed Branch cannot be empty')
@ -230,9 +230,14 @@ def addPlacement(request):
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except ValueError as e: 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)}, return Response({'action': "Add Placement", 'message': str(e)},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
except: except:
store_all_files(request)
exception_email(data)
logger.warning("Add New Placement: " + str(sys.exc_info())) logger.warning("Add New Placement: " + str(sys.exc_info()))
return Response({'action': "Add Placement", 'message': "Something went wrong"}, return Response({'action': "Add Placement", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -276,11 +281,9 @@ def verifyEmail(request):
data = { data = {
"designation": opening.designation, "designation": opening.designation,
"opening_type": PLACEMENT, "opening_type": PLACEMENT,
"opening_link": PLACEMENT_OPENING_URL.format(id=opening.id), # Some Changes here too
"company_name": opening.company_name, "company_name": opening.company_name,
} }
json_data = json.dumps(data, default=str) sendEmail([opening.email, CDC_MAIl_ADDRESS], COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data,
sendEmail(opening.email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), json_data,
COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone) COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone)
return Response({'action': "Verify Email", 'message': "Email Verified Successfully"}, return Response({'action': "Verify Email", 'message': "Email Verified Successfully"},

View File

@ -1,20 +1,24 @@
import os
BRANCH_CHOICES = [ BRANCH_CHOICES = [
["CSE", "CSE"], ["CSE", "CSE"],
["EE", "EE"], ["EE", "EE"],
["ME", "ME"], ["ME", "ME"],
['MMAE', 'MMAE'],
['EP', 'EP'], ['EP', 'EP'],
] ]
BRANCHES = [ BRANCHES = [
"CSE", "CSE",
"EE", "EE",
"ME", "MMAE",
"EP" "EP"
] ]
BATCH_CHOICES = [ BATCH_CHOICES = [
["2021", "2021"], ["2021", "2021"],
["2020", "2020"], ["2020", "2020"],
["2019", "2019"], ["2019", "2019"],
["2018", "2018"] ["2018", "2018"],
["2017", "2017"],
] ]
OFFER_CITY_TYPE = [ OFFER_CITY_TYPE = [
@ -29,31 +33,42 @@ TIERS = [
['3', 'Tier 3'], ['3', 'Tier 3'],
['4', 'Tier 4'], ['4', 'Tier 4'],
['5', 'Tier 5'], ['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_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 # 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 # To be Configured Properly
PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}" # On frontend, this is the URL to be opened 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 = "http://localhost/storage/Company_Attachments/" LINK_TO_STORAGE_COMPANY_ATTACHMENT = "https://cdc.iitdh.ac.in/storage/Company_Attachments/"
LINK_TO_STORAGE_RESUME = "http://localhost/storage/Resumes/" LINK_TO_STORAGE_RESUME = "https://cdc.iitdh.ac.in/storage/Resumes/"
LINK_TO_APPLICATIONS_CSV = "http://localhost/storage/Application_CSV/" LINK_TO_APPLICATIONS_CSV = "https://cdc.iitdh.ac.in/storage/Application_CSV/"
LINK_TO_EMAIl_VERIFICATION_API = "http://localhost:3000/company/verifyEmail?token={token}" 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" EMAIL = "email"
STUDENT = 'student' STUDENT = 'student'
ADMIN = 'admin' ADMIN = 'admin'
COMPANY = '' SUPER_ADMIN = 's_admin'
COMPANY = 'company'
TIER = 'tier' TIER = 'tier'
# To be Configured Properly # To be Configured Properly
FOURTH_YEAR = '2019' FOURTH_YEAR = '2019'
MAX_OFFERS_PER_STUDENT = 2 MAX_OFFERS_PER_STUDENT = 2
MAX_RESUMES_PER_STUDENT = 3
EMAIL_VERIFICATION_TOKEN_TTL = 48 # in hours EMAIL_VERIFICATION_TOKEN_TTL = 48 # in hours
JNF_TEXT_MAX_CHARACTER_COUNT = 100 JNF_TEXT_MAX_CHARACTER_COUNT = 100
JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT = 200 JNF_TEXTMEDIUM_MAX_CHARACTER_COUNT = 200
@ -70,6 +85,7 @@ RESUME_FILE_NAME = 'resume_file_name'
APPLICATION_ID = "application_id" APPLICATION_ID = "application_id"
OPENING_ID = "opening_id" OPENING_ID = "opening_id"
ADDITIONAL_INFO = "additional_info" ADDITIONAL_INFO = "additional_info"
FIELD = "field"
STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications" 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'] 'email_verified', 'created_at']
SPECIAL_FORMAT_IN_PDF = ['website', 'company_details_pdf_names', 'description_pdf_names', SPECIAL_FORMAT_IN_PDF = ['website', 'company_details_pdf_names', 'description_pdf_names',
'compensation_details_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" 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_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' 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' STUDENT_APPLICATION_SUBMITTED_TEMPLATE = 'student_application_submitted.html'
COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html' COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html'
STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html' STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html'
STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE = 'student_application_status_not_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_EMAIL_VERIFICATION_TEMPLATE = 'company_email_verification.html'
COMPANY_JNF_RESPONSE_TEMPLATE = 'company_jnf_response.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', APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI',
'Resume', 'Selected', ] 'Resume', 'Selected', ]
PDF_FILES_SERVING_ENDPOINT = 'http://localhost/storage/Company_Attachments/' # TODO: Change this to actual URL

View File

@ -1,6 +1,7 @@
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from simple_history.models import HistoricalRecords
from .constants import * from .constants import *
@ -10,9 +11,10 @@ from .constants import *
class User(models.Model): class User(models.Model):
email = models.EmailField(primary_key=True, blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) 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) user_type = ArrayField(models.CharField(blank=False, max_length=10), size=4, default=list, blank=False)
last_login_time = models.DateTimeField(default=timezone.now) last_login_time = models.DateTimeField(default=timezone.now)
history = HistoricalRecords()
class Meta: class Meta:
verbose_name_plural = "User" verbose_name_plural = "User"
@ -30,18 +32,46 @@ class Student(models.Model):
default=list, blank=True) default=list, blank=True)
cpi = models.DecimalField(decimal_places=2, max_digits=4) cpi = models.DecimalField(decimal_places=2, max_digits=4)
can_apply = models.BooleanField(default=True, verbose_name='Registered') 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): def __str__(self):
return str(self.roll_no) 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): class Admin(models.Model):
id = models.CharField(blank=False, max_length=15, primary_key=True) id = models.CharField(blank=False, max_length=15, primary_key=True)
name = models.CharField(blank=False, max_length=JNF_TEXT_MAX_CHARACTER_COUNT) 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(): 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): 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="") 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) 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) 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( company_details_pdf_names = ArrayField(
models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), size=5, models.CharField(null=True, default=None, max_length=JNF_TEXT_MAX_CHARACTER_COUNT), size=5,
default=list, blank=True) 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) 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) created_at = models.DateTimeField(blank=False, default=None, null=True)
updated_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): def format(self):
if self.company_name is not None: if self.company_name is not None:
@ -156,7 +188,19 @@ class Placement(models.Model):
if self.other_requirements is not None: if self.other_requirements is not None:
self.other_requirements = self.other_requirements.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT] self.other_requirements = self.other_requirements.strip()[:JNF_TEXTAREA_MAX_CHARACTER_COUNT]
if self.additional_info is not None: 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): def save(self, *args, **kwargs):
''' On save, add timestamps ''' ''' On save, add timestamps '''
@ -179,6 +223,8 @@ class PlacementApplication(models.Model):
selected = models.BooleanField(null=True, default=None, blank=True) selected = models.BooleanField(null=True, default=None, blank=True)
applied_at = models.DateTimeField(blank=False, default=None, null=True) applied_at = models.DateTimeField(blank=False, default=None, null=True)
updated_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): def save(self, *args, **kwargs):
''' On save, add timestamps ''' ''' On save, add timestamps '''
@ -188,6 +234,17 @@ class PlacementApplication(models.Model):
return super(PlacementApplication, self).save(*args, **kwargs) 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: class Meta:
verbose_name_plural = "Placement Applications" verbose_name_plural = "Placement Applications"
unique_together = ('placement_id', 'student_id') unique_together = ('placement_id', 'student_id')
@ -204,5 +261,31 @@ class PrePlacementOffer(models.Model):
compensation = models.IntegerField(blank=False) # Job - Per Year compensation = models.IntegerField(blank=False) # Job - Per Year
compensation_details = models.CharField(blank=True, max_length=200) compensation_details = models.CharField(blank=True, max_length=200)
tier = models.CharField(blank=False, choices=TIERS, max_length=10) 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) 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

View File

@ -162,7 +162,8 @@ class PlacementApplicationSerializer(serializers.ModelSerializer):
return data return data
def get_resume_link(self, obj): 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 return ele
class Meta: class Meta:
@ -185,3 +186,9 @@ class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer):
class Meta: class Meta:
model = PlacementApplication model = PlacementApplication
exclude = ['placement', 'resume'] exclude = ['placement', 'resume']
class ContributorSerializer(serializers.ModelSerializer):
class Meta:
model = Contributor
fields = '__all__'

View File

@ -9,4 +9,6 @@ urlpatterns = [
path("addResume/", studentViews.addResume, name="Upload Resume"), path("addResume/", studentViews.addResume, name="Upload Resume"),
path("deleteResume/", studentViews.deleteResume, name="Upload Resume"), path("deleteResume/", studentViews.deleteResume, name="Upload Resume"),
path("submitApplication/", studentViews.submitApplication, name="Submit Application"), path("submitApplication/", studentViews.submitApplication, name="Submit Application"),
path("deleteApplication/", studentViews.deleteApplication, name="Delete Application"),
path("getContributorStats/", studentViews.getContributorStats, name="Get Contributor Stats"),
] ]

View File

@ -40,17 +40,23 @@ def addResume(request, id, email, user_type):
student = get_object_or_404(Student, id=id) student = get_object_or_404(Student, id=id)
files = request.FILES files = request.FILES
if len(student.resumes) >= MAX_RESUMES_PER_STUDENT:
raise PermissionError('Max Number of Resumes limit reached')
file = files['file'] file = files['file']
destination_path = STORAGE_DESTINATION_RESUMES + str(student.roll_no) + "/" destination_path = STORAGE_DESTINATION_RESUMES + str(student.roll_no) + "/"
file_name = saveFile(file, destination_path) file_name = saveFile(file, destination_path)
student.resumes.append(file_name) student.resumes.append(file_name)
student.changed_by = get_object_or_404(User, id=id)
student.save() student.save()
return Response({'action': "Upload Resume", 'message': "Resume Added"}, return Response({'action': "Upload Resume", 'message': "Resume Added"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404: except Http404:
return Response({'action': "Upload Resume", 'message': 'Student Not Found'}, return Response({'action': "Upload Resume", 'message': 'Student Not Found'},
status=status.HTTP_404_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: except:
if path.exists(destination_path): if path.exists(destination_path):
logger.error("Upload Resume: Error in Saving Resume") logger.error("Upload Resume: Error in Saving Resume")
@ -71,7 +77,10 @@ def getDashboard(request, id, email, user_type):
allowed_branch__contains=[studentDetails.branch], allowed_branch__contains=[studentDetails.branch],
deadline_datetime__gte=datetime.datetime.now(), deadline_datetime__gte=datetime.datetime.now(),
offer_accepted=True, email_verified=True).order_by('deadline_datetime') 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 = PlacementApplication.objects.filter(student_id=id)
placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data
return Response( return Response(
@ -83,7 +92,6 @@ def getDashboard(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except: except:
logger.warning("Get Dashboard -Student: " + str(sys.exc_info())) logger.warning("Get Dashboard -Student: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"}, return Response({'action': "Get Dashboard - Student", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -104,6 +112,7 @@ def deleteResume(request, id, email, user_type):
if path.exists(destination_path): if path.exists(destination_path):
# remove(destination_path) # remove(destination_path)
student.resumes.remove(file_name) student.resumes.remove(file_name)
student.changed_by = get_object_or_404(User, id=id)
student.save() student.save()
return Response({'action': "Delete Resume", 'message': "Resume Deleted"}, return Response({'action': "Delete Resume", 'message': "Resume Deleted"},
status=status.HTTP_200_OK) 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) subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
sendEmail(email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE) sendEmail(email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
application.changed_by = get_object_or_404(User, id=id)
application.save() application.save()
return Response({'action': "Submit Application", 'message': "Application Submitted"}, return Response({'action': "Submit Application", 'message': "Application Submitted"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
@ -192,8 +201,49 @@ def submitApplication(request, id, email, user_type):
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except: except:
logger.warning("Submit Application: " + str(sys.exc_info())) logger.warning("Submit Application: " + str(sys.exc_info()))
print(traceback.format_exc())
print(sys.exc_info())
return Response({'action': "Submit Application", 'message': "Something Went Wrong"}, return Response({'action': "Submit Application", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) 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)

View File

@ -12,6 +12,7 @@ from os import path, remove
import background_task import background_task
import jwt import jwt
import pdfkit import pdfkit
import pytz
import requests as rq import requests as rq
from django.conf import settings from django.conf import settings
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
@ -27,7 +28,7 @@ from rest_framework import status
from rest_framework.response import Response from rest_framework.response import Response
from .constants import * from .constants import *
from .models import User, PrePlacementOffer, PlacementApplication, Placement from .models import User, PrePlacementOffer, PlacementApplication, Placement, Student
logger = logging.getLogger('db') logger = logging.getLogger('db')
@ -57,6 +58,7 @@ def precheck(required_data=None):
return view_func(request, *args, **kwargs) return view_func(request, *args, **kwargs)
except: except:
logger.warning("Pre check: " + str(sys.exc_info()))
return Response({'action': "Pre check", 'message': "Something went wrong"}, return Response({'action': "Pre check", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@ -77,7 +79,6 @@ def isAuthorized(allowed_users=None):
token_id = headers['HTTP_AUTHORIZATION'][7:] token_id = headers['HTTP_AUTHORIZATION'][7:]
idinfo = id_token.verify_oauth2_token(token_id, requests.Request(), CLIENT_ID) idinfo = id_token.verify_oauth2_token(token_id, requests.Request(), CLIENT_ID)
email = idinfo[EMAIL] email = idinfo[EMAIL]
print(email)
user = get_object_or_404(User, email=email) user = get_object_or_404(User, email=email)
if user: if user:
user.last_login_time = timezone.now() user.last_login_time = timezone.now()
@ -138,7 +139,7 @@ def saveFile(file, location):
return file_name return file_name
@background_task.background(schedule=5) @background_task.background(schedule=2)
def sendEmail(email_to, subject, data, template, attachment_jnf_response=None): def sendEmail(email_to, subject, data, template, attachment_jnf_response=None):
try: try:
if not isinstance(data, dict): 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) text_content = strip_tags(html_content)
email_from = settings.EMAIL_HOST_USER 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 = EmailMultiAlternatives(subject, text_content, email_from, recipient_list)
msg.attach_alternative(html_content, "text/html") msg.attach_alternative(html_content, "text/html")
if attachment_jnf_response: if attachment_jnf_response:
logger.info(attachment_jnf_response) # logger.info(attachment_jnf_response)
pdf = pdfkit.from_string(attachment_jnf_response['html'], False, pdf = pdfkit.from_string(attachment_jnf_response['html'], False,
options={"--enable-local-file-access": "", '--dpi': '96'}) options={"--enable-local-file-access": "", '--dpi': '96'})
msg.attach(attachment_jnf_response['name'], pdf, 'application/pdf') 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 return True
except: except:
logger.error("Send Email: " + str(sys.exc_info())) logger.error("Send Email: " + str(sys.exc_info()))
print(str(sys.exc_info()[1]))
return False return False
@ -169,31 +172,36 @@ def PlacementApplicationConditions(student, placement):
selected_companies = PlacementApplication.objects.filter(student=student, selected=True) selected_companies = PlacementApplication.objects.filter(student=student, selected=True)
selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu'] selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu']
PPO = PrePlacementOffer.objects.filter(student=student, accepted=True) PPO = PrePlacementOffer.objects.filter(student=student, accepted=True)
# find lenght of PPO PPO_PSU = [i for i in PPO if i.tier == 'psu']
print(PPO) # find length of PPO
print(len(PPO), "ere")
if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT: if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT:
raise PermissionError("Max Applications Reached for the Season") raise PermissionError("Max Applications Reached for the Season")
if len(selected_companies_PSU) > 0: if len(selected_companies_PSU) > 0:
raise PermissionError('Selected for PSU Can\'t apply anymore') 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': if placement.tier == 'psu':
return True, "Conditions Satisfied" return True, "Conditions Satisfied"
for i in selected_companies: 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): if int(i.placement.tier) < int(placement.tier):
return False, "Can't apply for this 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" return True, "Conditions Satisfied"
except PermissionError as e: except PermissionError as e:
return False, e return False, e
except: except:
print(sys.exc_info())
print(traceback.format_exc())
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info())) logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
return False, "_" return False, "_"
@ -231,7 +239,6 @@ def getTier(compensation_gross, is_psu=False):
logger.warning("Utils - getTier: " + str(sys.exc_info())) logger.warning("Utils - getTier: " + str(sys.exc_info()))
return False, e return False, e
except: except:
print(sys.exc_info())
logger.warning("Utils - getTier: " + str(sys.exc_info())) logger.warning("Utils - getTier: " + str(sys.exc_info()))
return False, "_" return False, "_"
@ -248,36 +255,35 @@ def generateOneTimeVerificationLink(email, opening_id, opening_type):
link = LINK_TO_EMAIl_VERIFICATION_API.format(token=token) link = LINK_TO_EMAIl_VERIFICATION_API.format(token=token)
return True, link return True, link
except: except:
print(sys.exc_info())
logger.warning("Utils - generateOneTimeVerificationLink: " + str(sys.exc_info())) logger.warning("Utils - generateOneTimeVerificationLink: " + str(sys.exc_info()))
return False, "_" return False, "_"
def verify_recaptcha(request): def verify_recaptcha(request):
try: try:
print(settings.RECAPTCHA_SECRET_KEY)
data = { data = {
'secret': settings.RECAPTCHA_SECRET_KEY, 'secret': settings.RECAPTCHA_SECRET_KEY,
'response': request 'response': request
} }
print(data)
r = rq.post('https://www.google.com/recaptcha/api/siteverify', data=data) r = rq.post('https://www.google.com/recaptcha/api/siteverify', data=data)
result = r.json() result = r.json()
# logger.info("Recaptcha Response: " + str(result)+"request: "+str(data)) if not result['success']:
logger.warning("Utils - verify_recaptcha: " + str(result))
print(result, "Result")
return result['success'] return result['success']
except: except:
# get exception line number # get exception line number
print(sys.exc_info())
print(traceback.format_exc())
logger.warning("Utils - verify_recaptcha: " + str(sys.exc_info())) logger.warning("Utils - verify_recaptcha: " + str(sys.exc_info()))
return False, "_" return False, "_"
def opening_description_table_html(opening): def opening_description_table_html(opening):
details = model_to_dict(opening, fields=[field.name for field in Placement._meta.fields], # check typing of opening
exclude=EXCLUDE_IN_PDF) 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()) keys = list(details.keys())
newdetails = {} newdetails = {}
for key in keys: for key in keys:
@ -287,7 +293,7 @@ def opening_description_table_html(opening):
if key == 'website': if key == 'website':
details[key] = {"details": details[key], "type": ["link"]} details[key] = {"details": details[key], "type": ["link"]}
else: else:
details[key] = {"details": details[key]["details"], "type": ["list", "link"], details[key] = {"details": [item for item in details[key]["details"]], "type": ["list", "link"],
"link": PDF_FILES_SERVING_ENDPOINT + opening.id + "/"} "link": PDF_FILES_SERVING_ENDPOINT + opening.id + "/"}
new_key = key.replace('_', ' ') new_key = key.replace('_', ' ')
if new_key.endswith(' names'): if new_key.endswith(' names'):
@ -295,9 +301,95 @@ def opening_description_table_html(opening):
new_key = new_key.capitalize() new_key = new_key.capitalize()
newdetails[new_key] = details[key] newdetails[new_key] = details[key]
imagepath = os.path.abspath('./templates/image.png') imagepath = os.path.abspath('./templates/image.png')
print(imagepath)
data = { data = {
"data": newdetails, "data": newdetails,
"imgpath": imagepath "imgpath": imagepath
} }
return render_to_string(COMPANY_JNF_RESPONSE_TEMPLATE, data) return render_to_string(COMPANY_JNF_RESPONSE_TEMPLATE, data)
def placement_eligibility_filters(student, placements):
try:
filtered_placements = []
for placement in placements.iterator():
if PlacementApplicationConditions(student, placement)[0]:
filtered_placements.append(placement)
return filtered_placements
except:
logger.warning("Utils - placement_eligibility_filters: " + str(sys.exc_info()))
return placements
@background_task.background(schedule=2)
def send_opening_notifications(placement_id):
try:
placement = get_object_or_404(Placement, id=placement_id)
students = Student.objects.all()
for student in students.iterator():
if student.branch in placement.allowed_branch:
if student.degree == 'bTech' or placement.rs_eligible is True:
if PlacementApplicationConditions(student, placement)[0]:
try:
student_user = get_object_or_404(User, id=student.id)
subject = NOTIFY_STUDENTS_OPENING_TEMPLATE_SUBJECT.format(
company_name=placement.company_name)
deadline_datetime = placement.deadline_datetime.astimezone(pytz.timezone('Asia/Kolkata'))
data = {
"company_name": placement.company_name,
"opening_type": 'Placement',
"designation": placement.designation,
"deadline": deadline_datetime.strftime("%A, %-d %B %Y, %-I:%M %p"),
"link": PLACEMENT_OPENING_URL.format(id=placement.id)
}
sendEmail(student_user.email, subject, data, NOTIFY_STUDENTS_OPENING_TEMPLATE)
except Http404:
logger.warning('Utils - send_opening_notifications: user not found : ' + student.id)
except Exception as e:
logger.warning('Utils - send_opening_notifications: For Loop' + str(e))
except:
logger.warning('Utils - send_opening_notifications: ' + str(sys.exc_info()))
return False
def exception_email(opening):
opening = opening.dict()
data = {
"designation": opening["designation"],
"opening_type": PLACEMENT,
"company_name": opening["company_name"],
}
pdfhtml = opening_description_table_html(opening)
name = opening["company_name"] + '_jnf_response.pdf'
attachment_jnf_respone = {
"name": name,
"html": pdfhtml,
}
sendEmail(CDC_MAIl_ADDRESS, COMPANY_OPENING_ERROR_TEMPLATE.format(company_name=opening["company_name"]), data,
COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone)
def store_all_files(request):
files = request.FILES
data = request.data
# save all the files
if files:
# company details pdf
for file in files.getlist(COMPANY_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
# compensation details pdf
for file in files.getlist(COMPENSATION_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
# selection procedure details pdf
for file in files.getlist(SELECTION_PROCEDURE_DETAILS_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)
# description pdf
for file in files.getlist(DESCRIPTION_PDF):
file_location = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + "temp" + '/'
saveFile(file, file_location)

View File

@ -15,7 +15,6 @@ import os
from dotenv import load_dotenv from dotenv import load_dotenv
load_dotenv("../dev.env") load_dotenv("../dev.env")
# import django_heroku
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -24,13 +23,14 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'e_i2g3z!y4+p3dwm%k9k=zmsot@aya-0$mmetgxz4mp#8_oy#*' SECRET_KEY = os.environ.get("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = os.environ.get('DEBUG') == "True"
ALLOWED_HOSTS = ['cdc-iitdh.herokuapp.com/', 'localhost', '192.168.29.199'] ALLOWED_HOSTS = ['cdc.iitdh.ac.in', 'localhost']
ADMINS = [('Gowtham Sai', '190010036@iitdh.ac.in'), ('Karthik Mv', '200010030@iitdh.ac.in')]
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
@ -44,7 +44,10 @@ INSTALLED_APPS = [
'rest_framework', 'rest_framework',
'corsheaders', 'corsheaders',
'django_db_logger', 'django_db_logger',
'background_task' 'background_task',
'simple_history',
'import_export',
"django_extensions"
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -54,10 +57,11 @@ MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', 'django.middleware.csrf.CsrfViewMiddleware',
'corsheaders.middleware.CorsPostCsrfMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',
] ]
ROOT_URLCONF = 'CDC_Backend.urls' ROOT_URLCONF = 'CDC_Backend.urls'
@ -144,13 +148,14 @@ STATICFILES_DIR = (
os.path.join(BASE_DIR, 'static'), os.path.join(BASE_DIR, 'static'),
) )
CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = [ CORS_ORIGIN_WHITELIST = [
"https://cdc.iitdh.ac.in",
"http://localhost:3000", "http://localhost:3000",
"http://127.0.0.1:3000", "https://localhost:3000"
"http://localhost:8000",
"http://127.0.0.1:8000"
] ]
CORS_REPLACE_HTTPS_REFERER = True
CSRF_TRUSTED_ORIGINS = [ "https://cdc.iitdh.ac.in", "http://cdc.iitdh.ac.in"]
# EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' # EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = './emails' EMAIL_FILE_PATH = './emails'
@ -181,14 +186,13 @@ LOGGING = {
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler' 'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
}, },
'mail_admins': { 'mail_admins': {
'level': 'ERROR', 'level': 'WARNING',
'class': 'django.utils.log.AdminEmailHandler', 'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
} }
}, },
'loggers': { 'loggers': {
'db': { 'db': {
'handlers': ['db_log'], 'handlers': ['db_log', 'mail_admins'],
'level': 'DEBUG' 'level': 'DEBUG'
} }
} }

View File

@ -6,7 +6,6 @@ It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see For more information on this file, see
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
""" """
import os import os
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application

1
CDC_Backend/run_prod.sh Normal file
View File

@ -0,0 +1 @@
gunicorn --certfile=/home/cdc/Desktop/1f9476e3959ebe60.crt --keyfile=/home/cdc/Desktop/star_iitdh_key.key --bind localhost:8000 CDC_Backend.wsgi --access-logfile access.log --error-logfile error.log &

View File

View File

@ -0,0 +1,70 @@
from APIs.models import Contributor
from django.shortcuts import get_object_or_404
import time
from dotenv import load_dotenv
import requests
import os
load_dotenv("../dev.env")
owner = 'CDC-IITDH'
access_token = os.environ.get("GITHUB_ACCESS_TOKEN")
headers = {'Authorization': "Token " + access_token}
maxRetires = 10
REPEAT_AFTER = 60 * 15 # 15 minutes
def getStats():
try:
stats = {}
repos = ['cdc-placement-website-backend', 'cdc-placement-website-frontend']
for i in repos:
try:
repo_name = i
print(repo_name)
url = f"https://api.github.com/repos/{owner}/{repo_name}/stats/contributors"
retry = 0
contributors = []
while True:
if retry > maxRetires:
break
req = requests.get(url, headers=headers)
contributors = req.json()
if req.status_code != 200:
print("ERROR:", req.json())
retry += 1
elif len(contributors):
break
retry += 1
time.sleep(1)
for contributor in contributors:
if contributor['author']['login'] not in stats:
stats[contributor['author']['login']] = 0
stats[contributor['author']['login']] += contributor['total']
except Exception as e:
print(e)
for i in stats:
try:
contributor = get_object_or_404(Contributor, github_id=i)
contributor.commits = stats[i]
contributor.save()
except:
pass
stats = sorted(stats.items(), key=lambda x: x[1], reverse=True)
for i in stats:
print(i)
except Exception as e:
print(e)
return stats
def run():
while True:
getStats()
print("Sleeping for", REPEAT_AFTER, "seconds")
time.sleep(REPEAT_AFTER)
print("Running send_reminder_mails()")
run()

View File

@ -44,7 +44,7 @@
{% for item in value.details %} {% for item in value.details %}
<li> <li>
{% if 'link' in value.type and value.link %} {% if 'link' in value.type and value.link %}
<a href="{{ value.link|add:item}}">{{ item }}</a> <a href="{{ value.link|add:item}}">{{ item|slice:"16:" }}</a>
{% elif 'link' in value.type %} {% elif 'link' in value.type %}
<a href="{{ item }}">{{ item }}</a> <a href="{{ item }}">{{ item }}</a>
{% else %} {% else %}

View File

@ -65,8 +65,7 @@
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;"> <p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
We have received your <b>{{ opening_type }}</b> notification for a We have received your <b>{{ opening_type }}</b> notification for a
<b>{{ designation }}</b> offer at <b> <b>{{ designation }}</b> offer at <b>
{{ company_name }}</b>. Click <a href="{{ opening_link }}">here</a> to view your {{ company_name }}</b>.
notification.
</p> </p>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;"> <p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
We will keep you informed with the updates. If you have any queries, please We will keep you informed with the updates. If you have any queries, please

View File

@ -50,12 +50,12 @@
<p style="text-indent: 4ch; margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;"> <p style="text-indent: 4ch; margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
CDC is excited to announce that <b>{{ company_name }}</b> is interested in CDC is excited to announce that <b>{{ company_name }}</b> is interested in
recruiting <b>{{ designation }}</b> from IIT Dharwad. recruiting <b>{{ designation }}</b> from IIT Dharwad.
More details can be found in the CDC-webportal. More details can be found in the CDC Web Portal.
</p> </p>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;"> <p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
Interested students can apply before <b>{{ deadline }}</b> in the <a Interested students can apply before <b>{{ deadline }}</b> in the <a
href="{{ link }}">CDC-webportal</a>. href="{{ link }}">CDC-Web Portal</a>.
</p> </p>
</td> </td>
</tr> </tr>

View File

@ -0,0 +1,124 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="x-apple-disable-message-reformatting">
<title></title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="shortcut icon" href="favicon.ico"/>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
<style>
table, td, div, h1, p {
font-family: 'Roboto', sans-serif;
}
</style>
</head>
<body style="margin:0;padding:0;">
<table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0;background:#ffffff;">
<tr>
<td align="center" style="padding:0;">
<table role="presentation"
style="width:602px;border-collapse:collapse;border:1px solid #334878;border-spacing:0;text-align:left;">
<tr>
<td align="center" style="padding:40px 0 30px 0;background:#334878;">
<img src="https://drive.google.com/uc?id=1QTA6dB7jnsZfU1kzyUqfD_2V5xODpWFt" alt="" width="200"
style="height:auto;display:block;"/>
</td>
</tr>
<tr>
<td style="padding:36px 30px 42px 30px;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="padding:0 0 36px 0;color:#153643;">
<h1 style="font-size:24px;margin:0 0 20px 0;font-family: 'Roboto', sans-serif;
">Hello, {{ name }}</h1>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
We have received some update in your application for a <b>{{ application_type }}</b> offer at
<b>
{{ company_name }}</b>.
<table style="border:solid 1px; margin: auto; text-align: center;width: 80%;
border-radius:15px; background-color: #e0e3ee">
<tr>
<td style="padding:8px 10px;color:#153643; "> resume:</td>
<td style="padding:8px 10px;color:#153643;">{{ resume }}</td>
</tr>
</table>
{% if additional_info_items %}
We received these additional details
<br>
<table style="border:solid 1px; margin: auto; text-align: center;width: 80%;
border-radius:15px; background-color: #e0e3ee">
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family:
'Roboto', sans-serif;text-align: center">
{% for i,j in additional_info_items.items %}
<tr>
<td style="padding:8px 10px;color:#153643; ">{{ i }}:</td>
<td style="padding:8px 10px;color:#153643;">{{ j }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
</p>
</p>
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
We will keep you informed with the updates. If you have any queries, please
feel to
write to
<nobr><u>cdc.support@iitdh.ac.in</u></nobr>
</p>
</td>
</tr>
<tr>
<td style="padding:0;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
<tr>
<td style="width:260px;padding:0;vertical-align:top;color:#334878;">
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding:30px;background:#334878;">
<table role="presentation"
style="width:100%;border-collapse:collapse;border:0;border-spacing:0;font-size:9px;font-family: 'Roboto', sans-serif;">
<tr>
<td style="padding:0;width:50%;" align="left">
<p style="margin:0;font-size:14px;line-height:16px;font-family: 'Roboto', sans-serif;color:#ffffff;">
&reg; CDC,IIT Dharwad,2021<br/>
</p>
</td>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

13
Email_service_README.md Normal file
View File

@ -0,0 +1,13 @@
we have defined a service for running the `start_email_service.sh` file continusouly on the server. Use the following commands for doing anything to the email
service.
## Enable the Service
`sudo systemctl enable cdc-email-sender.service`
## Start the Service
`sudo systemctl start cdc-email-sender.service`
## Check Status of the Service
`sudo systemctl status cdc-email-sender.service`
Any Doubts contact Gowtham Sai - 190010036

View File

@ -9,11 +9,12 @@ python# CDC - Backend
3. Create a Virtual Environment in the [CDC_Backend](./) folder with this command below <br> 3. Create a Virtual Environment in the [CDC_Backend](./) folder with this command below <br>
`python -m venv venv` `python -m venv venv`
3. Activate the environment with this command <br> 3. Activate the environment with this command <br>
`.\venv\Scripts\activate` `.\venv\Scripts\activate` (for WINDOWS) <br>
`source ./venv/bin/activate` (for LINUX)
4. Install the dependencies <br> 4. Install the dependencies <br>
`pip install -r requirements.txt ` `pip install -r requirements.txt `
5. Ensure that you have the PostgreSQL installed on your machine and is running on PORT **5432** <br> 5. Ensure that you have the PostgreSQL installed on your machine and is running on PORT **5432** <br>
6. Make sure to give the correct database credentials in [settings.py](./CDC_Backend/CDC_Backend/settings.py) 6. Make sure to give the correct database credentials in [settings.py](./CDC_Backend/CDC_Backend/settings.py)(https://www.youtube.com/watch?v=bE9h6aAky4s&t=193s)
7. Run these following commands below. (The same are there in setup.sh for linux users and setup.bat for windows users) 7. Run these following commands below. (The same are there in setup.sh for linux users and setup.bat for windows users)
```cd CDC_Backend ```cd CDC_Backend
python manage.py flush --no-input python manage.py flush --no-input
@ -25,10 +26,12 @@ python manage.py makemigrations APIs
``` ```
### Running the Application ### Running the Application
1. Activate the environment with this command. <br> 1. Activate the environment with this command. <br>
`.\venv\Scripts\activate` `.\venv\Scripts\activate` (for WINDOWS) <br>
`source ./venv/bin/activate` (for LINUX)
2. Start the application by running this command (_Run the command where [manage.py](./CDC_Backend/manage.py) is 2. Start the application by running this command (_Run the command where [manage.py](./CDC_Backend/manage.py) is
located_) <br> located_) <br>
` python manage.py runserver` ` python manage.py runserver`
@ -45,6 +48,12 @@ python manage.py makemigrations APIs
And then recognize it And then recognize it
8.Check the client link in dev.env in backend and .env in frontend is the same 8.Check the client link in dev.env in backend and .env in frontend is the same
# Error
1.make sure that your machine time and google time are same ,if not go to setting of date and time and sync this
2.make sure u have used same id for both student and Admin that is your iitfh roll_no
3. same client link in .env of frontend or constants.py of bakcend
### Deploying ### Deploying
1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py) 1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py)

12
dev.env
View File

@ -1,12 +0,0 @@
HOSTING_URL=http://localhost:8000/
DEBUG=True
EMAIL=saisurya3127@gmail.com
EMAIL_PASSWORD=lvryxwieedpervtv
SECRET_KEY=%2e!&f6(ib^690y48z=)&w6fczhwukzzp@3y*^*7u+7%4s-mie
EMAIL_VERIFICATION_SECRET_KEY=b'<\xa3\xaf&(*|\x0e\xbces\x07P\xf7\xd6\xa9sf\x19$\x96\xb7\x90\x8b\x88\x84\x0e\x191\xde,M\x90\x17(\xf7\nG\x13"\x8d$\x9f&\xb0\xcd\xa4\xaf\xa9\x1b\x15\x02B\x8a\xaf\xff\x0c\x1e\xd5\xb3\x06\xb8\xa6\x9bQ\xa0TR\xe8\x98\x9ae\xe0n}\xcc/[\xdaFz\x18\xfeX\xaf\xbd\xd0\x88\xeal\xe3\xd2\xe3\xb8\x8c\x199{\xf3<\xb0\xc5\xd0\xe7*Rv\xda\xbb \x1d\x85~\xff%>\x1e\xb8\xa7\xbf\xbc\xb2\x06\x86X\xc3\x9f\x13<\x9fd\xea\xb5"\\5&\x01\xa4\x7f=\xa0\x1b\x8bO\x01h\xe8\xfd\x1f\xfe\xba\xbeg\\\xc2\xcb\xc3\xd1~\xff\xd5/9d\xa8\xa7x{\x16\xdb\\\xbb\x08\rI\xcd\x9e7\x8c~\x0f\x1d\x81rXZD\xf0\xf7\x87K\x8f\xfb,\xf4\xf0\xa5\x9e\xde^\xca\xae\x80|9b\x9b\xaaE"\xba\xfb\xdf\x80\xb1\x99\x83e[\xf8\xce&Rq\x99\xdb}\xeeO\xd5\x18\x8d\x0bv\xe7\xab\xf9\xb9{\xb5u\xce\xcf\x90\xa6HE\xc5\x92p\x00\x158\xdf\x1d'
DB_NAME=cdc
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=localhost
DB_PORT=5432
RECAPTCHA_SECRET_KEY=6Lcv-mEfAAAAAOxM3pzPc-9W96yPlkWnn6v41fLl

16
doc/setup/postgres.md Normal file
View File

@ -0,0 +1,16 @@
typical conf file for pg_hba.conf for dev work.
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all md5
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 ident
host replication all ::1/128 ident

View File

@ -27,6 +27,8 @@ http {
sendfile on; sendfile on;
#tcp_nopush on; #tcp_nopush on;
client_max_body_size 50M;
#keepalive_timeout 0; #keepalive_timeout 0;
keepalive_timeout 65; keepalive_timeout 65;
@ -34,13 +36,13 @@ http {
server { server {
listen 80; listen 80;
server_name localhost; server_name cdc.iitdh.ac.in;
# listen 443 ssl; listen 443 ssl;
# server_name localhost; # server_name localhost;
# ssl_certificate cert.pem; ssl_certificate /home/cdc/Desktop/1f9476e3959ebe60.pem;
# ssl_certificate_key cert.key; ssl_certificate_key /home/cdc/Desktop/star_iitdh_key.key;
#charset koi8-r; #charset koi8-r;
@ -48,7 +50,13 @@ http {
location / { location / {
root /usr/share/nginx/html; root /usr/share/nginx/html;
index index.html index.htm; try_files $uri $uri/ /portal;
}
location /portal {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /portal/index.html;
} }
# Server static files /storage # Server static files /storage
@ -65,14 +73,14 @@ http {
} }
location /api/ { location /api/ {
proxy_pass http://localhost:8000; proxy_pass https://localhost:8000;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade"; proxy_set_header Connection "Upgrade";
proxy_set_header Host $host; proxy_set_header Host $host;
} }
location /admin/ { location /admin/ {
proxy_pass http://localhost:8000; proxy_pass https://localhost:8000;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade"; proxy_set_header Connection "Upgrade";

View File

@ -5,13 +5,19 @@ certifi==2021.10.8
chardet==4.0.0 chardet==4.0.0
charset-normalizer==2.0.12 charset-normalizer==2.0.12
colorama==0.4.4 colorama==0.4.4
defusedxml==0.7.1
diff-match-patch==20200713
dill==0.3.5.1
dj-database-url==0.5.0 dj-database-url==0.5.0
Django==3.2.13 Django==3.2.13
django-background-tasks==1.2.5 django-background-tasks==1.2.5
django-compat==1.0.15 django-compat==1.0.15
django-cors-headers==3.11.0 django-cors-headers==3.11.0
django-db-logger==0.1.12 django-db-logger==0.1.12
django-import-export==2.8.0
django-simple-history==3.1.1
djangorestframework==3.13.1 djangorestframework==3.13.1
et-xmlfile==1.1.0
google-auth==2.6.6 google-auth==2.6.6
gunicorn==20.1.0 gunicorn==20.1.0
idna==3.3 idna==3.3
@ -20,23 +26,31 @@ isort==5.10.1
jsonfield==3.1.0 jsonfield==3.1.0
lazy-object-proxy==1.7.1 lazy-object-proxy==1.7.1
Markdown==3.3.6 Markdown==3.3.6
MarkupPy==1.14
mccabe==0.7.0 mccabe==0.7.0
odfpy==1.4.1
openpyxl==3.0.10
pdfkit==1.0.0 pdfkit==1.0.0
platformdirs==2.5.1 platformdirs==2.5.1
psycopg2-binary==2.9.3 psycopg2-binary==2.9.3
pyasn1==0.4.8 pyasn1==0.4.8
pyasn1-modules==0.2.8 pyasn1-modules==0.2.8
PyJWT==2.4.0
pylint==2.13.5 pylint==2.13.5
python-dotenv==0.20.0 python-dotenv==0.20.0
pytz==2022.1 pytz==2022.1
PyJWT==2.4.0 PyYAML==6.0
requests==2.27.1 requests==2.27.1
rsa==4.8 rsa==4.8
six==1.16.0 six==1.16.0
sqlparse==0.4.2 sqlparse==0.4.2
tablib==3.2.1
toml==0.10.2 toml==0.10.2
tomli==2.0.1
typing_extensions==4.1.1 typing_extensions==4.1.1
urllib3==1.26.9 urllib3==1.26.9
whitenoise==6.0.0 whitenoise==6.0.0
zipp==3.8.0
wrapt==1.14.0 wrapt==1.14.0
xlrd==2.0.1
xlwt==1.3.0
zipp==3.8.0

7
start_email_service.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
source /home/cdc/Desktop/CDC_Web_Portal_Backend/cdc-placement-website-backend/venv/bin/activate
cd /home/cdc/Desktop/CDC_Web_Portal_Backend/cdc-placement-website-backend/CDC_Backend
python manage.py process_tasks