Initial Commit
This commit is contained in:
parent
dcc4a10f6e
commit
aa9aa40e81
|
@ -1,4 +1,3 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
@ -127,3 +126,12 @@ dmypy.json
|
|||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
|
||||
/venv/
|
||||
/.github/
|
||||
/CDC_Backend/CDC_Backend/__pycache__/
|
||||
/CDC_Backend/APIs/__pycache__/
|
||||
/CDC_Backend/APIs/migrations/
|
||||
.idea
|
||||
*.pyc
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
from django.contrib import admin
|
||||
from .models import *
|
||||
|
||||
admin.site.register(User)
|
||||
admin.site.register(Student)
|
||||
admin.site.register(PR)
|
||||
admin.site.register(Company)
|
||||
admin.site.register(Placement)
|
||||
admin.site.register(Internship)
|
||||
admin.site.register(PlacementApplication)
|
||||
admin.site.register(InternshipApplication)
|
||||
admin.site.register(PrePlacementOffer)
|
|
@ -0,0 +1,7 @@
|
|||
from django.urls import path
|
||||
from . import companyViews
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
]
|
|
@ -0,0 +1,6 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ApisConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'APIs'
|
|
@ -0,0 +1,7 @@
|
|||
from django.urls import path
|
||||
from . import companyViews
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('addOpening/', companyViews.addOpening, name="Add Opening"),
|
||||
]
|
|
@ -0,0 +1,120 @@
|
|||
import json
|
||||
from datetime import datetime
|
||||
|
||||
from django.utils.timezone import make_aware
|
||||
from rest_framework.decorators import api_view
|
||||
|
||||
from .utils import *
|
||||
|
||||
logger = logging.getLogger('db')
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@precheck([OPENING_DESIGNATION, OPENING_DESCRIPTION, OPENING_TYPE, OPENING_CITY, OPENING_CITY_TYPE,
|
||||
OPENING_COMPENSATION, OPENING_COMPENSATION_DETAILS, OPENING_ALLOWED_BATCH, OPENING_ALLOWED_BRANCH,
|
||||
OPENING_ROUNDS, OPENING_CO_OP, OPENING_START_DATE, OPENING_ADDITIONAL_INFO,
|
||||
OPENING_DURATION, OPENING_ROUND_DETAILS])
|
||||
def addOpening(request):
|
||||
try:
|
||||
data = request.data
|
||||
if data[OPENING_TYPE] == "Placement":
|
||||
opening = Placement()
|
||||
else:
|
||||
raise ValueError("Invalid Opening Type")
|
||||
|
||||
opening.id = generateRandomString()
|
||||
# Create Company object here for every Opening
|
||||
|
||||
|
||||
# Some new code above
|
||||
|
||||
if data[OPENING_DESIGNATION] != "":
|
||||
opening.designation = data[OPENING_DESIGNATION]
|
||||
else:
|
||||
raise ValueError(OPENING_DESIGNATION + " Not Found")
|
||||
|
||||
opening.description = data[OPENING_DESCRIPTION]
|
||||
|
||||
if data[OPENING_START_DATE] != "":
|
||||
opening.description = data[OPENING_START_DATE]
|
||||
else:
|
||||
raise ValueError(OPENING_START_DATE + " Not Found")
|
||||
if data[OPENING_START_DATE] != "":
|
||||
opening.start_date = datetime.strptime(data[OPENING_START_DATE], '%d-%m-%Y')
|
||||
else:
|
||||
raise ValueError(OPENING_START_DATE + " Not Found")
|
||||
if data[OPENING_CITY] != "":
|
||||
opening.city = data[OPENING_CITY]
|
||||
else:
|
||||
raise ValueError(OPENING_CITY + " Not Found")
|
||||
if data[OPENING_CITY_TYPE] != "":
|
||||
opening.city_type = data[OPENING_CITY_TYPE]
|
||||
else:
|
||||
raise ValueError(OPENING_CITY_TYPE + " Not Found")
|
||||
if data[OPENING_COMPENSATION] != "":
|
||||
opening.compensation = data[OPENING_COMPENSATION]
|
||||
else:
|
||||
raise ValueError(OPENING_COMPENSATION + " Not Found")
|
||||
|
||||
opening.compensation_details = data[OPENING_COMPENSATION_DETAILS]
|
||||
|
||||
if data[OPENING_ALLOWED_BATCH] != "":
|
||||
if set(json.loads(data[OPENING_ALLOWED_BATCH])).issubset(BATCHES):
|
||||
opening.allowed_batch = json.loads(data[OPENING_ALLOWED_BATCH])
|
||||
else:
|
||||
raise ValueError(OPENING_ALLOWED_BATCH + " is Invalid")
|
||||
else:
|
||||
raise ValueError(OPENING_ALLOWED_BATCH + " Not Found")
|
||||
if data[OPENING_ALLOWED_BRANCH] != "":
|
||||
if set(json.loads(data[OPENING_ALLOWED_BRANCH])).issubset(BRANCHES):
|
||||
opening.allowed_branch = json.loads(data[OPENING_ALLOWED_BRANCH])
|
||||
else:
|
||||
raise ValueError(OPENING_ALLOWED_BATCH + " is Invalid")
|
||||
else:
|
||||
raise ValueError(OPENING_ALLOWED_BRANCH + " Not Found")
|
||||
|
||||
opening.rounds = json.loads(data[OPENING_ROUNDS])
|
||||
|
||||
opening.additional_info = json.loads(data[OPENING_ADDITIONAL_INFO])
|
||||
|
||||
opening.status = STATUS_ACCEPTING_APPLICATIONS
|
||||
|
||||
opening.rounds_details = json.loads(data[OPENING_ROUND_DETAILS])
|
||||
|
||||
opening.created_at = make_aware(datetime.now())
|
||||
files = request.FILES.getlist(OPENING_ATTACHMENTS)
|
||||
attachments = []
|
||||
for file in files:
|
||||
attachments.append(saveFile(file, STORAGE_DESTINATION_COMPANY_ATTACHMENTS))
|
||||
|
||||
opening.attachments = attachments
|
||||
opening.save()
|
||||
data = {
|
||||
"designation": opening.designation,
|
||||
"opening_type": data[OPENING_TYPE],
|
||||
"opening_link": "google.com", # Some Changes here too
|
||||
"company_name": opening.company.name
|
||||
}
|
||||
|
||||
# Needs some edits here
|
||||
|
||||
email = 'This is temporary'
|
||||
|
||||
# Delete the above var when done
|
||||
|
||||
stat = sendEmail(email, COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data,
|
||||
COMPANY_OPENING_SUBMITTED_TEMPLATE)
|
||||
if stat is not True:
|
||||
logger.warning("Add New Opening: Unable to send email - " + stat)
|
||||
|
||||
return Response({'action': "Add Opening", 'message': "Opening Added"},
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
except ValueError as e:
|
||||
return Response({'action': "Add Opening", 'message': str(e)},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
except:
|
||||
logger.warning("Add New Opening: " + str(sys.exc_info()))
|
||||
return Response({'action': "Add Opening", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
|
@ -0,0 +1,92 @@
|
|||
BRANCH_CHOICES = [
|
||||
["CSE", "CSE"],
|
||||
["EE", "EE"],
|
||||
["ME", "ME"]
|
||||
]
|
||||
|
||||
BATCH_CHOICES = [
|
||||
["FIRST", "First"],
|
||||
["SECOND", "Second"],
|
||||
["THIRD", "Third"],
|
||||
["FOURTH", "Fourth"]
|
||||
]
|
||||
|
||||
OFFER_CITY_TYPE = [
|
||||
['Domestic', 'Domestic'],
|
||||
['International', 'International']
|
||||
]
|
||||
|
||||
TIERS = [
|
||||
['psu', 'PSU'],
|
||||
['1', 'Tier 1'],
|
||||
['2', 'Tier 2'],
|
||||
['3', 'Tier 3'],
|
||||
['4', 'Tier 4'],
|
||||
['5', 'Tier 5'],
|
||||
['6', 'Tier 6']
|
||||
]
|
||||
|
||||
|
||||
TOTAL_BRANCHES = 3 # Total No of Branches
|
||||
TOTAL_BATCHES = 4 # Total No of Batches
|
||||
|
||||
CLIENT_ID = "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com" # Google Login Client ID
|
||||
|
||||
TOKEN = "token_id"
|
||||
EMAIL = "email"
|
||||
|
||||
STUDENT = 'student'
|
||||
ADMIN = 'Admin'
|
||||
COMPANY = ''
|
||||
STORAGE_DESTINATION = "./Storage/Resumes/"
|
||||
STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/'
|
||||
|
||||
RESUME_FILE_NAME = 'resume_file_name'
|
||||
|
||||
APPLICATION_ID = "application_id"
|
||||
APPLICATION_OPENING_TYPE = "opening_type"
|
||||
APPLICATION_OPENING_ID = "opening_id"
|
||||
APPLICATION_ADDITIONAL_INFO = "additional_info"
|
||||
|
||||
STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications"
|
||||
|
||||
PLACEMENT = "Placement"
|
||||
|
||||
COMPANY_WEBSITE = 'website'
|
||||
COMPANY_ADDRESS = 'address'
|
||||
COMPANY_PHONE_NUMBER = 'phone_number'
|
||||
COMPANY_CONTACT_PERSON_NAME = 'contact_person_name'
|
||||
|
||||
OPENING_DESIGNATION = 'designation'
|
||||
OPENING_DESCRIPTION = 'description'
|
||||
OPENING_TYPE = 'opening_type'
|
||||
OPENING_CITY = 'city'
|
||||
OPENING_CITY_TYPE = 'city_type'
|
||||
OPENING_COMPENSATION = 'compensation'
|
||||
OPENING_COMPENSATION_DETAILS = 'compensation_details'
|
||||
OPENING_ALLOWED_BATCH = 'allowed_batch'
|
||||
OPENING_ALLOWED_BRANCH = 'allowed_branch'
|
||||
OPENING_ATTACHMENTS = 'attachments'
|
||||
OPENING_ROUNDS = 'rounds'
|
||||
OPENING_ADDITIONAL_INFO = 'additional_info'
|
||||
OPENING_ROUND_DETAILS = 'round_details'
|
||||
OPENING_DURATION = 'duration'
|
||||
OPENING_CO_OP = 'co_op'
|
||||
OPENING_START_DATE = 'start_date'
|
||||
|
||||
BRANCHES = [
|
||||
"CSE",
|
||||
"EE",
|
||||
"ME"
|
||||
]
|
||||
BATCHES = [
|
||||
"FIRST",
|
||||
"SECOND",
|
||||
"THIRD",
|
||||
"FOURTH"
|
||||
]
|
||||
|
||||
COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - CDC IIT Dharwad"
|
||||
|
||||
STUDENT_APPLICATION_SUBMITTED_TEMPLATE = 'student_application_submitted.html'
|
||||
COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html'
|
|
@ -0,0 +1,103 @@
|
|||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from .constants import *
|
||||
|
||||
|
||||
class User(models.Model):
|
||||
email = models.CharField(primary_key=True, blank=False, max_length=50)
|
||||
id = models.CharField(blank=False, max_length=25)
|
||||
user_type = ArrayField(models.CharField(blank=False, max_length=10), size=4, default=list, blank=False)
|
||||
|
||||
|
||||
class Student(models.Model):
|
||||
id = models.CharField(blank=False, max_length=15, primary_key=True)
|
||||
roll_no = models.IntegerField(blank=False)
|
||||
name = models.CharField(blank=False, max_length=50)
|
||||
batch = models.CharField(max_length=10, choices=BATCH_CHOICES, blank=False)
|
||||
branch = models.CharField(choices=BRANCH_CHOICES, blank=False, max_length=10)
|
||||
phone_number = models.PositiveBigIntegerField(blank=True, default=None, null=True)
|
||||
resumes = ArrayField(models.CharField(null=True, default=None, max_length=100), size=10, default=list, blank=True)
|
||||
cpi = models.DecimalField(decimal_places=2, max_digits=4)
|
||||
|
||||
|
||||
class Admin(models.Model):
|
||||
id = models.CharField(blank=False, max_length=15, primary_key=True)
|
||||
name = models.CharField(blank=False, max_length=50)
|
||||
|
||||
|
||||
class Placement(models.Model):
|
||||
id = models.CharField(blank=False, primary_key=True, max_length=15)
|
||||
name = models.CharField(blank=False, max_length=50)
|
||||
address = models.CharField(blank=False, max_length=150)
|
||||
companyType = models.CharField(blank=False, max_length=50)
|
||||
website = models.CharField(blank=True, max_length=50)
|
||||
contact_person_name = models.CharField(blank=False, max_length=50)
|
||||
phone_number = models.PositiveBigIntegerField(blank=False)
|
||||
designation = models.CharField(blank=False, max_length=25, default=None, null=True)
|
||||
description = models.CharField(blank=False, max_length=200)
|
||||
start_date = models.DateField(blank=False, verbose_name="Start Date")
|
||||
city = models.CharField(blank=False, max_length=100, default="")
|
||||
city_type = models.CharField(blank=False, max_length=15, choices=OFFER_CITY_TYPE)
|
||||
compensation = models.IntegerField(blank=False) # Job - Per Year
|
||||
compensation_details = models.CharField(blank=True, max_length=200)
|
||||
tier = models.CharField(blank=False, choices=TIERS, max_length=10, default=None, null=True)
|
||||
allowed_batch = ArrayField(
|
||||
models.CharField(max_length=10, choices=BATCH_CHOICES),
|
||||
size=TOTAL_BATCHES,
|
||||
default=list
|
||||
)
|
||||
allowed_branch = ArrayField(
|
||||
models.CharField(choices=BRANCH_CHOICES, blank=False, max_length=10),
|
||||
size=TOTAL_BRANCHES,
|
||||
default=list
|
||||
)
|
||||
attachments = ArrayField(
|
||||
models.CharField(max_length=100, blank=True),
|
||||
size=10,
|
||||
blank=True
|
||||
)
|
||||
rounds = ArrayField(
|
||||
models.CharField(max_length=25, blank=True),
|
||||
size=10,
|
||||
)
|
||||
additional_info = ArrayField(
|
||||
models.CharField(max_length=25, blank=True),
|
||||
size=10,
|
||||
blank=True
|
||||
)
|
||||
status = models.CharField(max_length=50, blank=False)
|
||||
rounds_details = models.JSONField(blank=True, default=dict)
|
||||
created_at = models.DateTimeField(blank=False, default=None, null=True)
|
||||
|
||||
|
||||
class PlacementApplication(models.Model):
|
||||
id = models.CharField(blank=False, primary_key=True, max_length=15)
|
||||
placement = models.ForeignKey(Placement, blank=False, on_delete=models.RESTRICT, default=None, null=True)
|
||||
student = models.ForeignKey(Student, blank=False, on_delete=models.CASCADE)
|
||||
resume = models.CharField(max_length=100, blank=False, null=True, default=None)
|
||||
status = models.CharField(max_length=50, null=True, blank=True, default=None)
|
||||
additional_info = models.JSONField(blank=True, default=None, null=True)
|
||||
selected = models.BooleanField(null=True, default=None, blank=True)
|
||||
applied_at = models.DateTimeField(blank=False, default=None, null=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
''' On save, add timestamps '''
|
||||
if not self.applied_at:
|
||||
self.applied_at = timezone.now()
|
||||
|
||||
return super(PlacementApplication, self).save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Placement Applications"
|
||||
|
||||
|
||||
class PrePlacementOffer(models.Model):
|
||||
id = models.AutoField(primary_key=True)
|
||||
student = models.ForeignKey(Student, on_delete=models.CASCADE, blank=False)
|
||||
company = models.CharField(max_length=50, blank=False)
|
||||
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)
|
||||
accepted = models.BooleanField(default=None, null=True)
|
|
@ -0,0 +1,56 @@
|
|||
from rest_framework import serializers
|
||||
from .models import *
|
||||
|
||||
|
||||
class StudentSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Student
|
||||
fields = '__all__'
|
||||
# exclude = ['id']
|
||||
|
||||
|
||||
class PlacementSerializer(serializers.ModelSerializer):
|
||||
company_details = serializers.SerializerMethodField()
|
||||
|
||||
def get_company_details(self, obj):
|
||||
data = {
|
||||
"id": obj.company.id,
|
||||
"name": obj.company.name,
|
||||
"address": obj.company.address,
|
||||
"companyType": obj.company.companyType,
|
||||
"website": obj.company.website,
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
class Meta:
|
||||
model = Placement
|
||||
exclude=[COMPANY]
|
||||
depth = 1
|
||||
|
||||
|
||||
class PlacementApplicationSerializer(serializers.ModelSerializer):
|
||||
application_status = serializers.SerializerMethodField()
|
||||
company_details = serializers.SerializerMethodField()
|
||||
|
||||
|
||||
def get_application_status(self, obj):
|
||||
if obj.status is None:
|
||||
return obj.placement.status
|
||||
else:
|
||||
return obj.status
|
||||
|
||||
|
||||
def get_company_details(self, obj):
|
||||
data = {
|
||||
"id": obj.placement.company.id,
|
||||
"name": obj.placement.company.name,
|
||||
"address": obj.placement.company.address,
|
||||
"companyType": obj.placement.company.companyType,
|
||||
"website": obj.placement.company.website,
|
||||
}
|
||||
return data
|
||||
|
||||
class Meta:
|
||||
model = PlacementApplication
|
||||
exclude = ['status', 'student']
|
|
@ -0,0 +1,12 @@
|
|||
from django.urls import path, include
|
||||
from . import studentViews
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', studentViews.login, name="Login"),
|
||||
path('profile/', studentViews.studentProfile, name="Student Profile"),
|
||||
path('getDashboard/', studentViews.getDashboard, name="Dashboard"),
|
||||
path("addResume/", studentViews.addResume, name="Upload Resume"),
|
||||
path("deleteResume/", studentViews.deleteResume, name="Upload Resume"),
|
||||
path("submitApplication/", studentViews.submitApplication, name="Submit Application"),
|
||||
]
|
|
@ -0,0 +1,190 @@
|
|||
import logging
|
||||
from os import path, remove
|
||||
|
||||
from rest_framework.decorators import api_view
|
||||
|
||||
from .serializers import *
|
||||
from .utils import *
|
||||
|
||||
logger = logging.getLogger('db')
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized(allowed_users='*')
|
||||
def login(request, id, email, user_type):
|
||||
try:
|
||||
return Response({'action': "Login", 'message': "Verified", "user_type": user_type},
|
||||
status=status.HTTP_200_OK)
|
||||
except:
|
||||
return Response({'action': "Login", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@isAuthorized(allowed_users=[STUDENT])
|
||||
def studentProfile(request, id, email, user_type):
|
||||
try:
|
||||
studentDetails = get_object_or_404(Student, id=id)
|
||||
|
||||
data = StudentSerializer(studentDetails).data
|
||||
return Response({'action': "Student Profile", 'message': "Details Found", "details": data},
|
||||
status=status.HTTP_200_OK)
|
||||
except:
|
||||
return Response({'action': "Student Profile", 'message': "Error Occurred {0}".format(str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized(allowed_users=[STUDENT])
|
||||
def addResume(request, id, email, user_type):
|
||||
destination_path = ""
|
||||
try:
|
||||
student = get_object_or_404(Student, id=id)
|
||||
prefix = generateRandomString()
|
||||
files = request.FILES
|
||||
file_name = prefix + "_" + files['file'].name
|
||||
print(file_name)
|
||||
student.resumes.append(file_name)
|
||||
|
||||
file = files['file']
|
||||
destination_path = STORAGE_DESTINATION + str(file_name)
|
||||
if path.exists(destination_path):
|
||||
remove(destination_path)
|
||||
|
||||
with open(destination_path, 'wb+') as destination:
|
||||
for chunk in file.chunks():
|
||||
destination.write(chunk)
|
||||
|
||||
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:
|
||||
if path.exists(destination_path):
|
||||
logger.error("Upload Resume: Error in Saving Resume")
|
||||
remove(destination_path)
|
||||
else:
|
||||
logger.warning("Upload Resume: " + str(sys.exc_info()))
|
||||
return Response({'action': "Upload Resume", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@isAuthorized(allowed_users=[STUDENT])
|
||||
def getDashboard(request, id, email, user_type):
|
||||
try:
|
||||
studentDetails = get_object_or_404(Student, id=id)
|
||||
|
||||
placements = Placement.objects.filter(allowed_batch__contains=[studentDetails.batch],
|
||||
allowed_branch__contains=[studentDetails.branch],
|
||||
status=STATUS_ACCEPTING_APPLICATIONS)
|
||||
placementsdata = PlacementSerializer(placements, many=True).data
|
||||
|
||||
placementApplications = PlacementApplication.objects.filter(student_id=id)
|
||||
placementApplications = PlacementApplicationSerializer(placementApplications, many=True).data
|
||||
|
||||
return Response(
|
||||
{'action': "Placement and Internships", 'message': "Data Found", "placements": placementsdata,
|
||||
'placementApplication': placementApplications},
|
||||
status=status.HTTP_200_OK)
|
||||
except Http404:
|
||||
return Response({'action': "Placements and Internships", 'message': 'Student Not Found'},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except:
|
||||
logger.warning("Placements and Internships: " + str(sys.exc_info()))
|
||||
return Response({'action': "Placements and Internships", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized(allowed_users=[STUDENT])
|
||||
@precheck(required_data=[RESUME_FILE_NAME])
|
||||
def deleteResume(request, id, email, user_type):
|
||||
try:
|
||||
student = get_object_or_404(Student, id=id)
|
||||
file_name = request.data[RESUME_FILE_NAME]
|
||||
destination_path = STORAGE_DESTINATION + str(file_name)
|
||||
if path.exists(destination_path):
|
||||
remove(destination_path)
|
||||
student.resumes.remove(file_name)
|
||||
student.save()
|
||||
return Response({'action': "Delete Resume", 'message': "Resume Deleted"},
|
||||
status=status.HTTP_200_OK)
|
||||
else:
|
||||
raise FileNotFoundError("File Not Found")
|
||||
except Http404:
|
||||
return Response({'action': "Delete Resume", 'message': 'Student Not Found'},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except FileNotFoundError as e:
|
||||
return Response({'action': "Delete Resume", 'message': str(e)},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except:
|
||||
logger.warning("Delete Resume: " + str(sys.exc_info()))
|
||||
return Response({'action': "Delete Resume", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@isAuthorized(allowed_users=[STUDENT])
|
||||
@precheck(required_data=[APPLICATION_OPENING_TYPE, APPLICATION_OPENING_ID, RESUME_FILE_NAME,
|
||||
APPLICATION_ADDITIONAL_INFO])
|
||||
def submitApplication(request, id, email, user_type):
|
||||
try:
|
||||
data = request.data
|
||||
student = get_object_or_404(Student, id=id)
|
||||
|
||||
if data[APPLICATION_OPENING_TYPE] == PLACEMENT:
|
||||
if not len(PlacementApplication.objects.filter(
|
||||
student_id=id, placement_id=data[APPLICATION_OPENING_ID])):
|
||||
application = PlacementApplication()
|
||||
opening = get_object_or_404(Placement, id=data[APPLICATION_OPENING_ID],
|
||||
status=STATUS_ACCEPTING_APPLICATIONS)
|
||||
cond_stat, cond_msg = PlacementApplicationConditions(student, opening)
|
||||
print(cond_stat, cond_msg)
|
||||
if not cond_stat:
|
||||
raise PermissionError(cond_msg)
|
||||
application.placement = opening
|
||||
else:
|
||||
raise PermissionError("Application is already Submitted")
|
||||
else:
|
||||
raise ValueError(APPLICATION_OPENING_TYPE + " is Invalid")
|
||||
|
||||
if data[RESUME_FILE_NAME] in student.resumes:
|
||||
application.resume = data[RESUME_FILE_NAME]
|
||||
else:
|
||||
raise FileNotFoundError(RESUME_FILE_NAME + " Not Found")
|
||||
|
||||
application.student = student
|
||||
application.id = generateRandomString()
|
||||
for i in opening.additional_info:
|
||||
if i not in data[APPLICATION_ADDITIONAL_INFO]:
|
||||
print(i)
|
||||
raise AttributeError(i + " not found in Additional Info")
|
||||
|
||||
application.additional_info = data[APPLICATION_ADDITIONAL_INFO]
|
||||
if not sendApplicationEmail(email, student.name, opening.company.name, data[APPLICATION_OPENING_TYPE],
|
||||
data[APPLICATION_ADDITIONAL_INFO]):
|
||||
logger.error("Submit Application: Unable to Send Email")
|
||||
# raise RuntimeError("Unable to Send Email")
|
||||
|
||||
application.save()
|
||||
return Response({'action': "Submit Application", 'message': "Application Submitted"},
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
except PermissionError as e:
|
||||
return Response({'action': "Submit Application", 'message': str(e)},
|
||||
status=status.HTTP_403_FORBIDDEN)
|
||||
except FileNotFoundError as e:
|
||||
return Response({'action': "Submit Application", 'message': str(e)},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except:
|
||||
logger.warning("Submit Application: " + str(sys.exc_info()))
|
||||
return Response({'action': "Submit Application", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path, include
|
||||
from . import studentViews, studentUrls, companyUrls, adminUrls
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', studentViews.login, name="Login"),
|
||||
path('student/', include(studentUrls)),
|
||||
path('company/', include(companyUrls)),
|
||||
path('admin/', include(adminUrls)),
|
||||
|
||||
]
|
|
@ -0,0 +1,197 @@
|
|||
import logging
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
from os import path, remove
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
from google.auth.transport import requests
|
||||
from google.oauth2 import id_token
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
from .models import *
|
||||
|
||||
logger = logging.getLogger('db')
|
||||
|
||||
|
||||
def precheck(required_data=None):
|
||||
if required_data is None:
|
||||
required_data = []
|
||||
|
||||
def decorator(view_func):
|
||||
def wrapper_func(request, *args, **kwargs):
|
||||
try:
|
||||
request_data = None
|
||||
if request.method == 'GET':
|
||||
request_data = request.GET
|
||||
elif request.method == 'POST':
|
||||
request_data = request.data
|
||||
if not len(request_data):
|
||||
request_data = request.POST
|
||||
if len(request_data):
|
||||
for i in required_data:
|
||||
if i not in request_data:
|
||||
return Response({'action': "Pre check", 'message': str(i) + " Not Found"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
return Response({'action': "Pre check", 'message': "Message Data not Found"},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return view_func(request, *args, **kwargs)
|
||||
except:
|
||||
return Response({'action': "Pre check", 'message': "Error Occurred " + str(sys.exc_info())},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return wrapper_func
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def isAuthorized(allowed_users=None):
|
||||
if allowed_users is None:
|
||||
allowed_users = []
|
||||
|
||||
def decorator(view_func):
|
||||
def wrapper_func(request, *args, **kwargs):
|
||||
try:
|
||||
headers = request.META
|
||||
if 'HTTP_AUTHORIZATION' in headers:
|
||||
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:
|
||||
|
||||
if len(set(user.user_type).intersection(set(allowed_users))) or allowed_users == '*':
|
||||
return view_func(request, user.id, user.email, user.user_type, *args, **kwargs)
|
||||
else:
|
||||
raise PermissionError("Access Denied. You are not allowed to use this service")
|
||||
else:
|
||||
raise PermissionError("Authorization Header Not Found")
|
||||
|
||||
except PermissionError as e:
|
||||
print(e)
|
||||
return Response({'action': "Is Authorized?", 'message': str(e)},
|
||||
status=status.HTTP_401_UNAUTHORIZED)
|
||||
except Http404:
|
||||
print('http404')
|
||||
return Response({'action': "Is Authorized?", 'message': "User Not Found. Contact CDC for more details"},
|
||||
status=status.HTTP_404_NOT_FOUND)
|
||||
except ValueError as e:
|
||||
logger.warning("Problem with Google Oauth2.0 " + str(e))
|
||||
return Response({'action': "Is Authorized?", 'message': str(e)},
|
||||
status=status.HTTP_401_UNAUTHORIZED)
|
||||
except:
|
||||
return Response({'action': "Is Authorized?", 'message': "Error Occurred {0}".format(
|
||||
str(sys.exc_info()[1]))},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
return wrapper_func
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
def generateRandomString():
|
||||
try:
|
||||
N = 15
|
||||
res = ''.join(random.choices(string.ascii_uppercase + string.digits, k=N))
|
||||
return res
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def sendApplicationEmail(email, name, company_name, applicaton_type, additional_info):
|
||||
try:
|
||||
subject = 'CDC - Application Submitted - ' + str(company_name)
|
||||
data = {
|
||||
"name": name,
|
||||
"company_name": company_name,
|
||||
"applicaton_type": applicaton_type,
|
||||
"additional_info": additional_info
|
||||
}
|
||||
|
||||
html_content = render_to_string('student_application_submited.html', data) # render with dynamic value
|
||||
text_content = strip_tags(html_content)
|
||||
|
||||
email_from = settings.EMAIL_HOST_USER
|
||||
recipient_list = [str(email), ]
|
||||
|
||||
msg = EmailMultiAlternatives(subject, text_content, email_from, recipient_list)
|
||||
msg.attach_alternative(html_content, "text/html")
|
||||
msg.send()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def saveFile(file, location):
|
||||
prefix = generateRandomString()
|
||||
file_name = prefix + "_" + file.name
|
||||
|
||||
if not path.isdir(location):
|
||||
os.mkdir(location)
|
||||
|
||||
destination_path = STORAGE_DESTINATION_COMPANY_ATTACHMENTS + str(file_name)
|
||||
if path.exists(destination_path):
|
||||
remove(destination_path)
|
||||
|
||||
with open(destination_path, 'wb+') as destination:
|
||||
for chunk in file.chunks():
|
||||
destination.write(chunk)
|
||||
|
||||
return file_name
|
||||
|
||||
|
||||
def sendEmail(email_to, subject, data, template):
|
||||
try:
|
||||
html_content = render_to_string(template, data) # render with dynamic value
|
||||
text_content = strip_tags(html_content)
|
||||
|
||||
email_from = settings.EMAIL_HOST_USER
|
||||
recipient_list = [str(email_to), ]
|
||||
|
||||
msg = EmailMultiAlternatives(subject, text_content, email_from, recipient_list)
|
||||
msg.attach_alternative(html_content, "text/html")
|
||||
msg.send()
|
||||
return True
|
||||
except:
|
||||
print(str(sys.exc_info()[1]))
|
||||
return str(sys.exc_info()[1])
|
||||
|
||||
|
||||
def PlacementApplicationConditions(student, placement):
|
||||
try:
|
||||
selected_companies = PlacementApplication.objects.filter(student=student, selected=True)
|
||||
selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu']
|
||||
PPO = PrePlacementOffer.objects.filter(internship_application__student=student, accepted=True)
|
||||
|
||||
if len(selected_companies) + len(PPO) >= 2:
|
||||
raise PermissionError("Max Applications Reached for the Season")
|
||||
|
||||
if len(selected_companies_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"
|
||||
|
||||
return True, "Conditions Satisfied"
|
||||
|
||||
except PermissionError as e:
|
||||
return False, e
|
||||
except:
|
||||
print(sys.exc_info())
|
||||
logger.warning("Utils - PlacementApplicationConditions: " + str(sys.exc_info()))
|
||||
return False, "_"
|
|
@ -0,0 +1,191 @@
|
|||
"""
|
||||
Django settings for CDC_Backend project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 2.2.5.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/2.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/2.2/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# 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__)))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# 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#*'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['cdc-iitdh.herokuapp.com/', 'localhost', '192.168.29.199']
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'APIs',
|
||||
'rest_framework',
|
||||
'corsheaders',
|
||||
'django_db_logger',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'corsheaders.middleware.CorsMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'CDC_Backend.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': ['templates'],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'CDC_Backend.wsgi.application'
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.sqlite3',
|
||||
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
# }
|
||||
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'cdc',
|
||||
'USER': 'postgres',
|
||||
'PASSWORD': 'root',
|
||||
'HOST': 'localhost',
|
||||
'PORT': '5432',
|
||||
},
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
# 'NAME': 'd84i5cbjig5rrf',
|
||||
# 'USER': 'hbkullcdjbxuwh',
|
||||
# 'PASSWORD': '45d990da00e2cc96d7d4e2e5e308d4b07a387883f70c40e090a6252175cb634e',
|
||||
# 'HOST': 'ec2-54-163-97-228.compute-1.amazonaws.com',
|
||||
# 'PORT': '5432',
|
||||
# }
|
||||
}
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'Asia/Kolkata'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
|
||||
STATICFILES_DIR = (
|
||||
os.path.join(BASE_DIR, 'static'),
|
||||
)
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
CORS_ORIGIN_WHITELIST = [
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:3000",
|
||||
"http://localhost:8000",
|
||||
"http://127.0.0.1:8000"
|
||||
]
|
||||
|
||||
# EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
|
||||
EMAIL_FILE_PATH = './emails'
|
||||
|
||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||
EMAIL_HOST = 'smtp.gmail.com'
|
||||
EMAIL_USE_TLS = True
|
||||
EMAIL_PORT = 587
|
||||
EMAIL_HOST_USER = 'saisurya3127@gmail.com'#'email here'
|
||||
EMAIL_HOST_PASSWORD = 'ehwkqmryyqjiifcz'#'password here'
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
|
||||
},
|
||||
'simple': {
|
||||
'format': '%(levelname)s %(asctime)s %(message)s'
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'db_log': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
|
||||
},
|
||||
},
|
||||
'loggers': {
|
||||
'db': {
|
||||
'handlers': ['db_log'],
|
||||
'level': 'DEBUG'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# django_heroku.settings(locals())
|
|
@ -0,0 +1,7 @@
|
|||
from django.contrib import admin
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('api/', include('APIs.urls'))
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
"""
|
||||
WSGI config for CDC_Backend project.
|
||||
|
||||
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
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CDC_Backend.settings')
|
||||
|
||||
application = get_wsgi_application()
|
|
@ -0,0 +1,403 @@
|
|||
# API References
|
||||
1. [**Common APIs**](#common-apis)
|
||||
1. [**api/login/**](#apilogin)
|
||||
2[**Student APIs**](#student-portal-apis)
|
||||
2. [**api/student/profile/**](#apistudentprofile)
|
||||
3. [**api/student/getDashboard/**](#apistudentgetdashboard)
|
||||
4. [**api/student/addResume/**](#apistudentaddresume)
|
||||
5. [**api/student/deleteResume/**](#apistudentdeleteresume)
|
||||
6. [**api/student/submitApplication/**](#apistudentsubmitapplication)
|
||||
3[**Common Errors**](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
# Common APIs
|
||||
|
||||
## `api/login/`
|
||||
|
||||
This Api is used to Verify the user and find out the role he/she has
|
||||
|
||||
### How to Use?
|
||||
|
||||
Send a `POST` request to `api/login/`<br>
|
||||
Request_Body:
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
> Headers <br>
|
||||
> Authorization: "Bearer {tokenID}"
|
||||
|
||||
### Response
|
||||
|
||||
Response is a Json with these fields
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "Login",
|
||||
"message": "Verified",
|
||||
"user_type": [
|
||||
"student"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- action: Tells us about the message creator<Br>
|
||||
- message: Tells us what happened with our Request.
|
||||
- user_type: Tells us about the role the user possess. Can have these values
|
||||
- student
|
||||
- Admin
|
||||
|
||||
### Status Codes
|
||||
|
||||
The possible responses for this api request are as follows
|
||||
|
||||
| Status Codes | Possible Messages |
|
||||
| ------------ | ----------------- |
|
||||
| 200 OK | `Verified` |
|
||||
|
||||
You may see some different errors which can be seen [here](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
# Student Portal APIs
|
||||
|
||||
## `api/student/profile`
|
||||
|
||||
This Api is used to get the profile of the student.
|
||||
|
||||
### How to Use?
|
||||
|
||||
Send a `GET` request to `api/student/profile`<br>
|
||||
Request_Body:
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
> Headers <br>
|
||||
> Authorization: "Bearer {tokenID}"
|
||||
|
||||
### Response
|
||||
|
||||
Response is a Json with these fields
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "Student Profile",
|
||||
"message": "Details Found",
|
||||
"details": {
|
||||
"id": "fdgdb",
|
||||
"roll_no": 190010036,
|
||||
"name": "Gowtham Sai",
|
||||
"batch": "THIRD",
|
||||
"branch": "CSE",
|
||||
"phone_number": 9390291911,
|
||||
"resumes": [
|
||||
"XB85F4RIGBF5VJN_Cv-Gowtham.pdf"
|
||||
],
|
||||
"cpi": "9.02"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- action: Tells us about the message creator<Br>
|
||||
- message: Tells us what happened with our Request.
|
||||
- details: Has the student data.
|
||||
|
||||
### Status Codes
|
||||
|
||||
The possible responses for this api request are as follows
|
||||
|
||||
| Status Codes | Possible Messages |
|
||||
| --------------- | ------------------------ |
|
||||
| 200 OK | `Details Found` |
|
||||
| 400 BAD_REQUEST | `Error Occurred {error}` |
|
||||
|
||||
You may see some different errors which can be seen [here](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
## `api/student/getDashboard`
|
||||
|
||||
This Api is used to get all the placements applicable to the student.
|
||||
|
||||
### How to Use?
|
||||
|
||||
Send a `GET` request to `api/student/Dashboard`<br>
|
||||
|
||||
Request_Body:
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
> Headers <br>
|
||||
> Authorization: "Bearer {tokenID}"
|
||||
|
||||
### Response
|
||||
|
||||
Response is a Json with these fields
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "Placement and Internships",
|
||||
"message": "Data Found",
|
||||
"placements": [
|
||||
{
|
||||
"id": "fdgdb121",
|
||||
"designation": "Software Developer",
|
||||
"description": "nice job",
|
||||
"start_date": "2021-06-17",
|
||||
"city": "Mumbai",
|
||||
"city_type": "Domestic",
|
||||
"compensation": 1200000,
|
||||
"compensation_details": "",
|
||||
"allowed_batch": [
|
||||
"THIRD",
|
||||
"FOURTH"
|
||||
],
|
||||
"allowed_branch": [
|
||||
"CSE",
|
||||
"EE",
|
||||
"ME"
|
||||
],
|
||||
"attachments": [],
|
||||
"rounds": [
|
||||
"Resume Shortlisting",
|
||||
"Technical Test",
|
||||
"Interview"
|
||||
],
|
||||
"additional_info": [
|
||||
"school",
|
||||
"place of study",
|
||||
"language"
|
||||
],
|
||||
"status": "Resume Shortlisting",
|
||||
"rounds_details": {
|
||||
"Interview": "One -to-One interview",
|
||||
"Technical Test": "Online Technical test which will be monitored remotely",
|
||||
"Resume Shortlisting": "Resume will be seen"
|
||||
},
|
||||
"company_details": {
|
||||
"id": "fdgdb",
|
||||
"name": "Apple",
|
||||
"address": "California",
|
||||
"companyType": "Technology",
|
||||
"website": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"placementApplication": [
|
||||
{
|
||||
"id": "dsdads",
|
||||
"application_status": "Resume Shortlisting",
|
||||
"resume": "XB85F4RIGBF5VJN_Cv-Gowtham.pdf",
|
||||
"additional_info": {
|
||||
"school": "Delhi Public School",
|
||||
"language": "Telugu",
|
||||
"place of study": "Visakhapatnam"
|
||||
},
|
||||
"selected": null,
|
||||
"placement": "fdgdb121"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- action: Tells us about the message creator<Br>
|
||||
- message: Tells us what happened with our Request.
|
||||
- placements: Has the placements data.
|
||||
- internships: Has the internships data.
|
||||
- application_status: Can have many names
|
||||
- Accepting Applications
|
||||
- One of the Round Names
|
||||
- Completed
|
||||
- selected: Can take three Values
|
||||
- null: Student is still in the Selection process
|
||||
- true: Student is Selected
|
||||
- false: Student is not selected
|
||||
|
||||
### Status Codes
|
||||
|
||||
The possible responses for this api request are as follows
|
||||
|
||||
| Status Codes | Possible Messages |
|
||||
| --------------- | ------------------------ |
|
||||
| 200 OK | `Resume Added` |
|
||||
| 400 BAD_REQUEST | `Error Occurred {error}` |
|
||||
|
||||
You can see some common errors [here](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
## `api/student/addResume/`
|
||||
|
||||
This Api is used to add resumes by a student.
|
||||
|
||||
### How to Use?
|
||||
|
||||
Send a `POST` request to `api/student/addResume/`<br>
|
||||
|
||||
> Only users with `student` role can access this Api.
|
||||
|
||||
Request_Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"file": "__FILE_OBJECT__"
|
||||
}
|
||||
```
|
||||
|
||||
> Excepted to send Form Data
|
||||
|
||||
> Headers <br>
|
||||
> Authorization: "Bearer {tokenID}"
|
||||
|
||||
### Response
|
||||
|
||||
Response is a Json with these fields
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "Upload Resume",
|
||||
"message": "Resume Added"
|
||||
}
|
||||
```
|
||||
|
||||
- action: Tells us about the message creator<Br>
|
||||
- message: Tells us what happened with our Request.
|
||||
|
||||
### Status Codes
|
||||
|
||||
The possible responses for this api request are as follows
|
||||
|
||||
| Status Codes | Possible Messages |
|
||||
| ------------ | ----------------- |
|
||||
| 200 OK | `Resume Added` |
|
||||
|
||||
You can see some common errors [here](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
## `api/student/deleteResume/`
|
||||
|
||||
This Api is used to delete resumes added by a student.
|
||||
|
||||
### How to Use?
|
||||
|
||||
Send a `POST` request to `api/student/deleteResume/`<br>
|
||||
|
||||
> Only users with `student` role can access this Api.
|
||||
|
||||
Request_Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"resume_file_name": "8ZJ44RIS9914SO4_Resume for Google STEP.pdf"
|
||||
}
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
Response is a Json with these fields
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "Delete Resume",
|
||||
"message": "Resume Deleted"
|
||||
}
|
||||
```
|
||||
|
||||
> Headers <br>
|
||||
> Authorization: "Bearer {tokenID}"
|
||||
|
||||
- action: Tells us about the message creator<Br>
|
||||
- message: Tells us what happened with our Request.
|
||||
|
||||
### Status Codes
|
||||
|
||||
The possible responses for this api request are as follows
|
||||
|
||||
| Status Codes | Possible Messages |
|
||||
| ------------- | ----------------- |
|
||||
| 200 OK | `Resume Deleted` |
|
||||
| 404 NOT FOUND | `File Not Found` |
|
||||
|
||||
You can see some common errors [here](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
## `api/student/submitApplication/`
|
||||
|
||||
This Api is used to submit application to Internships/Placements.
|
||||
|
||||
### How to Use?
|
||||
|
||||
Send a `POST` request to `api/student/submitApplication/`<br>
|
||||
|
||||
> Only users with `student` role can access this Api.
|
||||
|
||||
Request_Body:
|
||||
|
||||
```json
|
||||
{
|
||||
"opening_type": "Placement",
|
||||
"opening_id": "fgervsdgdsf",
|
||||
"resume_file_name": "1FYE0PQZZ508HR6_Resume for Google STEP.pdf",
|
||||
"additional_info": {
|
||||
"school": "Narayana English Medium",
|
||||
"place of study": "Vizag",
|
||||
"language": "Telugu"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> Headers <br>
|
||||
> Authorization: "Bearer {tokenID}"
|
||||
|
||||
- opening_type: Can be Placement/Internship
|
||||
- opening_id: Opening Id unique to each opening.
|
||||
- additional_info: This is the info which the Internship/Placement demands besides the normal user data which has to
|
||||
asked and sent. These fields can be found in the Internship Details.
|
||||
|
||||
### Response
|
||||
|
||||
Response is a Json with these fields
|
||||
|
||||
```json
|
||||
{
|
||||
"action": "Submit Application",
|
||||
"message": "Application Submitted"
|
||||
}
|
||||
```
|
||||
|
||||
- action: Tells us about the message creator<Br>
|
||||
- message: Tells us what happened with our Request.
|
||||
|
||||
### Status Codes
|
||||
|
||||
The possible responses for this api request are as follows
|
||||
|
||||
| Status Codes | Possible Messages |
|
||||
| ------------- | ---------------------------------- |
|
||||
| 200 OK | `Application Submitted` |
|
||||
| 403 FORBIDDEN | `Application is already Submitted` |
|
||||
| 404 NOT FOUND | `RESUME_FILE_NAME Not Found` |
|
||||
|
||||
You can see some common errors [here](#common-errors)
|
||||
|
||||
---
|
||||
|
||||
## `Common Errors`
|
||||
|
||||
Some common errors that you may see while accessing the Apis
|
||||
|
||||
| Status Codes | Possible Messages | Possible Reasons |
|
||||
| ---------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
||||
| 401 UNAUTHORIZED | `Authorization Header Not Found` | Check for the authorization header in you request and the prefix( Should use `Bearer`) used. |
|
||||
| 401 UNAUTHORIZED | `Access Denied. You are not allowed to use this service` | Your may not have required access to those access those Apis. |
|
||||
| 401 UNAUTHORIZED | `Token has wrong audience` | You may be using wrong credentials for Google OAuth2.0. |
|
||||
| 404 NOT FOUND | `User Not Found. Contact CDC for more details` | You may not be a user at CDC, IIT Dharwad. Please contact us to get your user account |
|
||||
| 400 BAD_REQUEST | `Error Occurred {error}` | Any random Error which can be seen in the {error} string. |
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"web": {
|
||||
"client_id": "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com",
|
||||
"project_id": "cdc-automation",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_secret": "ZzvcweJylL1IDLUnYOi1ws2W",
|
||||
"redirect_uris": ["https://www.getpostman.com/oauth2/callback"],
|
||||
"javascript_origins": ["http://localhost:3000"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'CDC_Backend.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
|
@ -0,0 +1,113 @@
|
|||
<!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="./image.png" 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 there, {{ name }}</h1>
|
||||
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family: 'Roboto', sans-serif;">
|
||||
We have received your application for a <b>{{ applicaton_type }}</b> offer at <b>
|
||||
{{ company_name }}</b>
|
||||
. We received these additional details<br>
|
||||
<p style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family:
|
||||
'Roboto', sans-serif;text-align: center">
|
||||
|
||||
<table style="border:solid 1px; margin: auto; text-align: center;width: 80%;
|
||||
border-radius:15px; background-color: #e0e3ee">
|
||||
|
||||
{% for i,j in additional_info.items %}
|
||||
|
||||
<tr>
|
||||
<td style="padding:8px 10px;color:#153643; ">{{ i }}:</td>
|
||||
<td style="padding:8px 10px;color:#153643;">{{ j }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</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>
|
40
README.md
40
README.md
|
@ -1 +1,39 @@
|
|||
# cdc-placement-website-backend
|
||||
# CDC - Backend
|
||||
|
||||
---
|
||||
|
||||
### Setup
|
||||
|
||||
1. Download the Repository to your local machine <br>
|
||||
2. 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`
|
||||
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)
|
||||
|
||||
### Running the Application
|
||||
|
||||
1. Activate the environment with this command. <br>
|
||||
`.\venv\Scripts\activate`
|
||||
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`
|
||||
|
||||
### Accessing the Admin Panel
|
||||
|
||||
1. You can access the admin panel by running the server and opening <http://localhost:8000/admin>
|
||||
2. Run `python manage.py createsuperuser` to create a user to access the admin panel.
|
||||
3. Set up the Username and Password
|
||||
4. You can log in and change the database values anytime.
|
||||
|
||||
### Deploying
|
||||
|
||||
1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py)
|
||||
2. Update the `CORS_ORIGIN_WHITELIST` list and `CORS_ORIGIN_ALLOW_ALL` variable
|
||||
|
||||
### API Reference
|
||||
|
||||
Check [here](./CDC_Backend/README.md) for Api Reference
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
asgiref==3.4.1
|
||||
astroid==2.7.1
|
||||
cachetools==4.2.2
|
||||
certifi==2021.5.30
|
||||
chardet==4.0.0
|
||||
colorama==0.4.4
|
||||
dj-database-url==0.5.0
|
||||
Django==3.2.6
|
||||
django-cors-headers==3.8.0
|
||||
django-db-logger==0.1.10
|
||||
djangorestframework==3.12.4
|
||||
google-auth==2.0.0
|
||||
idna==3.2
|
||||
isort==5.9.3
|
||||
jsonfield==3.1.0
|
||||
lazy-object-proxy==1.6.0
|
||||
Markdown==3.3.4
|
||||
mccabe==0.6.1
|
||||
psycopg2==2.9.1
|
||||
pyasn1==0.4.8
|
||||
pyasn1-modules==0.2.8
|
||||
pylint==2.9.6
|
||||
pytz==2021.1
|
||||
requests==2.26.0
|
||||
rsa==4.7.2
|
||||
six==1.16.0
|
||||
sqlparse==0.4.1
|
||||
toml==0.10.2
|
||||
urllib3==1.26.6
|
||||
whitenoise==5.3.0
|
||||
wrapt==1.12.1
|
Loading…
Reference in New Issue