Merge branch 'main' into Abhishek28112002-patch-1
This commit is contained in:
commit
b06455cf5b
.DS_Store.gitignoreCDC_Backend.zip
CDC_Backend
.DS_Store
Email_service_README.mdREADME.mddev.envAPIs
admin.pyadminUrls.pyadminViews.pycompanyViews.pyconstants.pymodels.pyserializers.pystudentUrls.pystudentViews.pyutils.py
CDC_Backend
run_prod.shscripts
templates
doc/setup
nginx.confrequirements.txtstart_email_service.sh
|
@ -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 == 'website':
|
||||
details[key] = {"details": details[key], "type": ["link"]}
|
||||
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 + "/"}
|
||||
new_key = key.replace('_', ' ')
|
||||
if new_key.endswith(' names'):
|
||||
|
@ -295,9 +301,95 @@ def opening_description_table_html(opening):
|
|||
new_key = new_key.capitalize()
|
||||
newdetails[new_key] = details[key]
|
||||
imagepath = os.path.abspath('./templates/image.png')
|
||||
print(imagepath)
|
||||
data = {
|
||||
"data": newdetails,
|
||||
"imgpath": imagepath
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -15,7 +15,6 @@ import os
|
|||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv("../dev.env")
|
||||
# import django_heroku
|
||||
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
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/
|
||||
|
||||
# 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!
|
||||
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
|
||||
|
||||
INSTALLED_APPS = [
|
||||
|
@ -44,7 +44,10 @@ INSTALLED_APPS = [
|
|||
'rest_framework',
|
||||
'corsheaders',
|
||||
'django_db_logger',
|
||||
'background_task'
|
||||
'background_task',
|
||||
'simple_history',
|
||||
'import_export',
|
||||
"django_extensions"
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -54,10 +57,11 @@ MIDDLEWARE = [
|
|||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'corsheaders.middleware.CorsPostCsrfMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
|
||||
'simple_history.middleware.HistoryRequestMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'CDC_Backend.urls'
|
||||
|
@ -144,13 +148,14 @@ STATICFILES_DIR = (
|
|||
os.path.join(BASE_DIR, 'static'),
|
||||
)
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
CORS_ORIGIN_ALLOW_ALL = False
|
||||
CORS_ORIGIN_WHITELIST = [
|
||||
"https://cdc.iitdh.ac.in",
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000",
|
||||
"http://localhost:8000",
|
||||
"http://127.0.0.1:8000"
|
||||
"https://localhost:3000"
|
||||
]
|
||||
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_FILE_PATH = './emails'
|
||||
|
@ -181,14 +186,13 @@ LOGGING = {
|
|||
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
|
||||
},
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'level': 'WARNING',
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
'include_html': True,
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'db': {
|
||||
'handlers': ['db_log'],
|
||||
'handlers': ['db_log', 'mail_admins'],
|
||||
'level': 'DEBUG'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ It exposes the WSGI callable as a module-level variable named ``application``.
|
|||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
|
|
@ -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 &
|
|
@ -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()
|
|
@ -44,7 +44,7 @@
|
|||
{% for item in value.details %}
|
||||
<li>
|
||||
{% 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 %}
|
||||
<a href="{{ item }}">{{ item }}</a>
|
||||
{% else %}
|
||||
|
|
|
@ -65,8 +65,7 @@
|
|||
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
|
||||
We have received your <b>{{ opening_type }}</b> notification for a
|
||||
<b>{{ designation }}</b> offer at <b>
|
||||
{{ company_name }}</b>. Click <a href="{{ opening_link }}">here</a> to view your
|
||||
notification.
|
||||
{{ company_name }}</b>.
|
||||
</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
|
||||
|
|
|
@ -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;">
|
||||
CDC is excited to announce that <b>{{ company_name }}</b> is interested in
|
||||
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 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
|
||||
href="{{ link }}">CDC-webportal</a>.
|
||||
href="{{ link }}">CDC-Web Portal</a>.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -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;">
|
||||
® CDC,IIT Dharwad,2021<br/>
|
||||
</p>
|
||||
</td>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -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
|
15
README.md
15
README.md
|
@ -9,11 +9,12 @@ python# CDC - Backend
|
|||
3. Create a Virtual Environment in the [CDC_Backend](./) folder with this command below <br>
|
||||
`python -m venv venv`
|
||||
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>
|
||||
`pip install -r requirements.txt `
|
||||
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)
|
||||
```cd CDC_Backend
|
||||
python manage.py flush --no-input
|
||||
|
@ -25,10 +26,12 @@ python manage.py makemigrations APIs
|
|||
```
|
||||
|
||||
|
||||
|
||||
### Running the Application
|
||||
|
||||
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
|
||||
located_) <br>
|
||||
` python manage.py runserver`
|
||||
|
@ -45,6 +48,12 @@ python manage.py makemigrations APIs
|
|||
And then recognize it
|
||||
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
|
||||
|
||||
1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py)
|
||||
|
|
12
dev.env
12
dev.env
|
@ -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
|
|
@ -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
|
24
nginx.conf
24
nginx.conf
|
@ -27,6 +27,8 @@ http {
|
|||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
client_max_body_size 50M;
|
||||
|
||||
#keepalive_timeout 0;
|
||||
keepalive_timeout 65;
|
||||
|
||||
|
@ -34,21 +36,27 @@ http {
|
|||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
server_name cdc.iitdh.ac.in;
|
||||
|
||||
# listen 443 ssl;
|
||||
listen 443 ssl;
|
||||
# server_name localhost;
|
||||
|
||||
# ssl_certificate cert.pem;
|
||||
# ssl_certificate_key cert.key;
|
||||
ssl_certificate /home/cdc/Desktop/1f9476e3959ebe60.pem;
|
||||
ssl_certificate_key /home/cdc/Desktop/star_iitdh_key.key;
|
||||
|
||||
#charset koi8-r;
|
||||
|
||||
#access_log logs/host.access.log main;
|
||||
|
||||
|
||||
location / {
|
||||
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
|
||||
|
@ -65,14 +73,14 @@ http {
|
|||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_pass https://localhost:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
location /admin/ {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_pass https://localhost:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "Upgrade";
|
||||
|
|
|
@ -5,13 +5,19 @@ certifi==2021.10.8
|
|||
chardet==4.0.0
|
||||
charset-normalizer==2.0.12
|
||||
colorama==0.4.4
|
||||
defusedxml==0.7.1
|
||||
diff-match-patch==20200713
|
||||
dill==0.3.5.1
|
||||
dj-database-url==0.5.0
|
||||
Django==3.2.13
|
||||
django-background-tasks==1.2.5
|
||||
django-compat==1.0.15
|
||||
django-cors-headers==3.11.0
|
||||
django-db-logger==0.1.12
|
||||
django-import-export==2.8.0
|
||||
django-simple-history==3.1.1
|
||||
djangorestframework==3.13.1
|
||||
et-xmlfile==1.1.0
|
||||
google-auth==2.6.6
|
||||
gunicorn==20.1.0
|
||||
idna==3.3
|
||||
|
@ -20,23 +26,31 @@ isort==5.10.1
|
|||
jsonfield==3.1.0
|
||||
lazy-object-proxy==1.7.1
|
||||
Markdown==3.3.6
|
||||
MarkupPy==1.14
|
||||
mccabe==0.7.0
|
||||
odfpy==1.4.1
|
||||
openpyxl==3.0.10
|
||||
pdfkit==1.0.0
|
||||
platformdirs==2.5.1
|
||||
psycopg2-binary==2.9.3
|
||||
pyasn1==0.4.8
|
||||
pyasn1-modules==0.2.8
|
||||
PyJWT==2.4.0
|
||||
pylint==2.13.5
|
||||
python-dotenv==0.20.0
|
||||
pytz==2022.1
|
||||
PyJWT==2.4.0
|
||||
PyYAML==6.0
|
||||
requests==2.27.1
|
||||
rsa==4.8
|
||||
six==1.16.0
|
||||
sqlparse==0.4.2
|
||||
tablib==3.2.1
|
||||
toml==0.10.2
|
||||
tomli==2.0.1
|
||||
typing_extensions==4.1.1
|
||||
urllib3==1.26.9
|
||||
whitenoise==6.0.0
|
||||
wrapt==1.14.0
|
||||
xlrd==2.0.1
|
||||
xlwt==1.3.0
|
||||
zipp==3.8.0
|
||||
wrapt==1.14.0
|
|
@ -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
|
Loading…
Reference in New Issue