diff --git a/.gitignore b/.gitignore
index b6e4761..d2e39e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/CDC_Backend/APIs/__init__.py b/CDC_Backend/APIs/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/CDC_Backend/APIs/admin.py b/CDC_Backend/APIs/admin.py
new file mode 100644
index 0000000..bc5b427
--- /dev/null
+++ b/CDC_Backend/APIs/admin.py
@@ -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)
diff --git a/CDC_Backend/APIs/adminUrls.py b/CDC_Backend/APIs/adminUrls.py
new file mode 100644
index 0000000..203c0dc
--- /dev/null
+++ b/CDC_Backend/APIs/adminUrls.py
@@ -0,0 +1,7 @@
+from django.urls import path
+from . import companyViews
+
+
+urlpatterns = [
+
+]
diff --git a/CDC_Backend/APIs/adminViews.py b/CDC_Backend/APIs/adminViews.py
new file mode 100644
index 0000000..e69de29
diff --git a/CDC_Backend/APIs/apps.py b/CDC_Backend/APIs/apps.py
new file mode 100644
index 0000000..e704049
--- /dev/null
+++ b/CDC_Backend/APIs/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class ApisConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'APIs'
diff --git a/CDC_Backend/APIs/companyUrls.py b/CDC_Backend/APIs/companyUrls.py
new file mode 100644
index 0000000..f175144
--- /dev/null
+++ b/CDC_Backend/APIs/companyUrls.py
@@ -0,0 +1,7 @@
+from django.urls import path
+from . import companyViews
+
+
+urlpatterns = [
+ path('addOpening/', companyViews.addOpening, name="Add Opening"),
+]
diff --git a/CDC_Backend/APIs/companyViews.py b/CDC_Backend/APIs/companyViews.py
new file mode 100644
index 0000000..c31f135
--- /dev/null
+++ b/CDC_Backend/APIs/companyViews.py
@@ -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)
diff --git a/CDC_Backend/APIs/constants.py b/CDC_Backend/APIs/constants.py
new file mode 100644
index 0000000..2ea330b
--- /dev/null
+++ b/CDC_Backend/APIs/constants.py
@@ -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'
diff --git a/CDC_Backend/APIs/models.py b/CDC_Backend/APIs/models.py
new file mode 100644
index 0000000..e844dc2
--- /dev/null
+++ b/CDC_Backend/APIs/models.py
@@ -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)
diff --git a/CDC_Backend/APIs/serializers.py b/CDC_Backend/APIs/serializers.py
new file mode 100644
index 0000000..62f9ef7
--- /dev/null
+++ b/CDC_Backend/APIs/serializers.py
@@ -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']
diff --git a/CDC_Backend/APIs/studentUrls.py b/CDC_Backend/APIs/studentUrls.py
new file mode 100644
index 0000000..1d6d76a
--- /dev/null
+++ b/CDC_Backend/APIs/studentUrls.py
@@ -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"),
+]
diff --git a/CDC_Backend/APIs/studentViews.py b/CDC_Backend/APIs/studentViews.py
new file mode 100644
index 0000000..6abee88
--- /dev/null
+++ b/CDC_Backend/APIs/studentViews.py
@@ -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)
diff --git a/CDC_Backend/APIs/tests.py b/CDC_Backend/APIs/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/CDC_Backend/APIs/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/CDC_Backend/APIs/urls.py b/CDC_Backend/APIs/urls.py
new file mode 100644
index 0000000..bdb06c8
--- /dev/null
+++ b/CDC_Backend/APIs/urls.py
@@ -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)),
+
+]
diff --git a/CDC_Backend/APIs/utils.py b/CDC_Backend/APIs/utils.py
new file mode 100644
index 0000000..422cec1
--- /dev/null
+++ b/CDC_Backend/APIs/utils.py
@@ -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, "_"
diff --git a/CDC_Backend/CDC_Backend/__init__.py b/CDC_Backend/CDC_Backend/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/CDC_Backend/CDC_Backend/settings.py b/CDC_Backend/CDC_Backend/settings.py
new file mode 100644
index 0000000..e2b812b
--- /dev/null
+++ b/CDC_Backend/CDC_Backend/settings.py
@@ -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())
diff --git a/CDC_Backend/CDC_Backend/urls.py b/CDC_Backend/CDC_Backend/urls.py
new file mode 100644
index 0000000..6a3f873
--- /dev/null
+++ b/CDC_Backend/CDC_Backend/urls.py
@@ -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'))
+]
diff --git a/CDC_Backend/CDC_Backend/wsgi.py b/CDC_Backend/CDC_Backend/wsgi.py
new file mode 100644
index 0000000..057007a
--- /dev/null
+++ b/CDC_Backend/CDC_Backend/wsgi.py
@@ -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()
diff --git a/CDC_Backend/README.md b/CDC_Backend/README.md
new file mode 100644
index 0000000..95398ea
--- /dev/null
+++ b/CDC_Backend/README.md
@@ -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/`
+Request_Body:
+
+```json
+{}
+```
+
+> Headers
+> 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
+- 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`
+Request_Body:
+
+```json
+{}
+```
+
+> Headers
+> 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
+- 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`
+
+Request_Body:
+
+```json
+{}
+```
+
+> Headers
+> 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
+- 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/`
+
+> Only users with `student` role can access this Api.
+
+Request_Body:
+
+```json
+{
+ "file": "__FILE_OBJECT__"
+}
+```
+
+> Excepted to send Form Data
+
+> Headers
+> 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
+- 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/`
+
+> 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
+> Authorization: "Bearer {tokenID}"
+
+- action: Tells us about the message creator
+- 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/`
+
+> 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
+> 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
+- 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. |
diff --git a/CDC_Backend/client_secret_956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com (2).json b/CDC_Backend/client_secret_956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com (2).json
new file mode 100644
index 0000000..42f9eb6
--- /dev/null
+++ b/CDC_Backend/client_secret_956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleusercontent.com (2).json
@@ -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"]
+ }
+}
diff --git a/CDC_Backend/manage.py b/CDC_Backend/manage.py
new file mode 100644
index 0000000..dc415b9
--- /dev/null
+++ b/CDC_Backend/manage.py
@@ -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()
diff --git a/CDC_Backend/templates/favicon.ico b/CDC_Backend/templates/favicon.ico
new file mode 100644
index 0000000..9b2402e
Binary files /dev/null and b/CDC_Backend/templates/favicon.ico differ
diff --git a/CDC_Backend/templates/image.png b/CDC_Backend/templates/image.png
new file mode 100644
index 0000000..ce9d82e
Binary files /dev/null and b/CDC_Backend/templates/image.png differ
diff --git a/CDC_Backend/templates/student_application_submitted.html b/CDC_Backend/templates/student_application_submitted.html
new file mode 100644
index 0000000..805edee
--- /dev/null
+++ b/CDC_Backend/templates/student_application_submitted.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Hello there, {{ name }}
+
+ We have received your application for a {{ applicaton_type }} offer at
+ {{ company_name }}
+ . We received these additional details
+
+
+
+
+ {% for i,j in additional_info.items %}
+
+
+
{{ i }}:
+
{{ j }}
+
+ {% endfor %}
+
+
+
+
+
+ We will keep you informed with the updates. If you have any queries, please
+ feel to
+ write to
+ cdc.support@iitdh.ac.in
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ® CDC,IIT Dharwad,2021
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 9bce313..d812996 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,39 @@
-# cdc-placement-website-backend
\ No newline at end of file
+# CDC - Backend
+
+---
+
+### Setup
+
+1. Download the Repository to your local machine
+2. Create a Virtual Environment in the [CDC_Backend](./) folder with this command below
+ `python -m venv venv`
+3. Activate the environment with this command
+ `.\venv\Scripts\activate`
+4. Install the dependencies
+ `pip install -r requirements.txt `
+5. Ensure that you have the PostgreSQL installed on your machine and is running on PORT **5432**
+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.
+ `.\venv\Scripts\activate`
+2. Start the application by running this command (_Run the command where [manage.py](./CDC_Backend/manage.py) is
+ located_)
+ ` python manage.py runserver`
+
+### Accessing the Admin Panel
+
+1. You can access the admin panel by running the server and opening
+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
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..eb6c7a4
--- /dev/null
+++ b/requirements.txt
@@ -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