Added Few More Apis and corrected a view

This commit is contained in:
gowtham 2021-12-12 19:14:27 +05:30
parent 1c9286f6fa
commit 5201df7e90
12 changed files with 385 additions and 58 deletions

View File

@ -1,9 +1,41 @@
from django.contrib import admin from django.contrib import admin
from .models import * from .models import *
from django.contrib import admin
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.shortcuts import resolve_url
from django.utils.html import format_html
from django.utils.safestring import SafeText
from .models import *
admin.site.register(User) admin.site.register(User)
admin.site.register(Student) # admin.site.register(Student)
admin.site.register(Admin) admin.site.register(Admin)
admin.site.register(Placement) # admin.site.register(Placement)
admin.site.register(PlacementApplication) admin.site.register(PlacementApplication)
admin.site.register(PrePlacementOffer) admin.site.register(PrePlacementOffer)
admin.site.site_header = "CDC Recruitment Portal"
def model_admin_url(obj, name=None) -> str:
url = resolve_url(admin_urlname(obj._meta, SafeText("change")), obj.pk)
return format_html('<a href="{}">{}</a>', url, name or str(obj))
@admin.register(Student)
class Student(admin.ModelAdmin):
list_display = ("roll_no", "name", "batch", "branch", "phone_number")
search_fields = ("roll_no", "name","phone_number")
ordering = ("roll_no", "name", "batch", "branch", "phone_number")
list_filter = ("batch", "branch")
@admin.register(Placement)
class Placement(admin.ModelAdmin):
list_display = (COMPANY_NAME, CONTACT_PERSON_NAME, PHONE_NUMBER, 'tier', 'compensation_CTC')
search_fields = (COMPANY_NAME, CONTACT_PERSON_NAME)
ordering = (COMPANY_NAME, CONTACT_PERSON_NAME, 'tier', 'compensation_CTC')
list_filter = ('tier',)

View File

@ -9,5 +9,7 @@ urlpatterns = [
path('updateOfferAccepted/', adminViews.updateOfferAccepted, name="Update Offer Accepted"), path('updateOfferAccepted/', adminViews.updateOfferAccepted, name="Update Offer Accepted"),
path('updateEmailVerified', adminViews.updateEmailVerified, name="Update Email Verified"), path('updateEmailVerified', adminViews.updateEmailVerified, name="Update Email Verified"),
path('updateAdditionalInfo/', adminViews.updateAdditionalInfo, name="Update Additional Info"), path('updateAdditionalInfo/', adminViews.updateAdditionalInfo, name="Update Additional Info"),
path('getApplications/', adminViews.getApplications, name="Get Applications"),
path("submitApplication/", adminViews.submitApplication, name="Submit Application"),
path('generateCSV/', adminViews.generateCSV, name="Generate CSV"),
] ]

View File

@ -1,8 +1,9 @@
import json
from datetime import datetime from datetime import datetime
from .utils import * from .utils import *
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
import csv
from .serializers import * from .serializers import *
@ -153,3 +154,146 @@ def updateAdditionalInfo(request, id, email, user_type):
logger.warning("Update Additional Info: " + str(sys.exc_info())) logger.warning("Update Additional Info: " + str(sys.exc_info()))
return Response({'action': "Update Additional Info", 'message': "Something went wrong"}, return Response({'action': "Update Additional Info", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET'])
@isAuthorized([ADMIN])
@precheck([OPENING_ID])
def getApplications(request, id, email, user_type):
try:
data = request.GET
opening = get_object_or_404(Placement, pk=data[OPENING_ID])
applications = PlacementApplication.objects.filter(placement=opening)
serializer = PlacementApplicationSerializerForAdmin(applications, many=True)
return Response({'action': "Get Applications", 'message': 'Data Found', 'applications':serializer.data},
status=status.HTTP_200_OK)
except Http404:
return Response({'action': "Get Applications", 'message': 'Opening Not Found'},
status=status.HTTP_404_NOT_FOUND)
except:
logger.warning("Get Applications: " + str(sys.exc_info()))
return Response({'action': "Get Applications", 'message': "Something went wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized(allowed_users=[ADMIN])
@precheck(required_data=[OPENING_TYPE, OPENING_ID, RESUME_FILE_NAME,
STUDENT_ID])
def submitApplication(request, id, email, user_type):
try:
data = request.data
student = get_object_or_404(Student, roll_no=data[STUDENT_ID])
# Only Allowing Applications for Placements
if data[OPENING_TYPE] == PLACEMENT:
if not len(PlacementApplication.objects.filter(
student_id=student.id, placement_id=data[OPENING_ID])):
application = PlacementApplication()
opening = get_object_or_404(Placement, id=data[OPENING_ID],
allowed_batch__contains=[student.batch],
allowed_branch__contains=[student.branch],
deadline_datetime__gte=datetime.now().date()
)
if not opening.offer_accepted or not opening.email_verified:
raise PermissionError("Placement Not Approved")
cond_stat, cond_msg = PlacementApplicationConditions(student, opening)
if not cond_stat:
raise PermissionError(cond_msg)
application.placement = opening
else:
raise PermissionError("Application is already Submitted")
else:
raise ValueError(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()
additional_info = {}
for i in opening.additional_info:
if i not in data[ADDITIONAL_INFO]:
raise AttributeError(i + " not found in Additional Info")
else:
additional_info[i] = data[ADDITIONAL_INFO][i]
application.additional_info = json.dumps(additional_info)
data = {
"name": student.name,
"company_name": opening.company_name,
"application_type": data[OPENING_TYPE],
"additional_info": dict(json.loads(application.additional_info)),
}
subject = STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT.format(company_name=opening.company_name)
student_email = str(student.roll_no)+"@iitdh.ac.in"
sendEmail(student_email, subject, data, STUDENT_APPLICATION_SUBMITTED_TEMPLATE)
application.save()
return Response({'action': "Submit Application", 'message': "Application Submitted"},
status=status.HTTP_200_OK)
except Http404 as e:
return Response({'action': "Submit Application", 'message': str(e)},
status=status.HTTP_404_NOT_FOUND)
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': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@isAuthorized(allowed_users=[ADMIN])
@precheck(required_data=[OPENING_ID])
def generateCSV(request, id, email, user_type):
try:
data = request.data
placement = get_object_or_404(Placement, id=data[OPENING_ID])
applications = PlacementApplication.objects.filter(placement=placement)
filename = generateRandomString()
if not os.path.isdir(STORAGE_DESTINATION_APPLICATION_CSV):
os.mkdir(STORAGE_DESTINATION_APPLICATION_CSV)
destination_path = STORAGE_DESTINATION_APPLICATION_CSV + filename + ".csv"
f = open(destination_path, 'w')
writer = csv.writer(f)
header_row = APPLICATION_CSV_COL_NAMES.copy()
header_row.extend(placement.additional_info)
writer.writerow(header_row)
for apl in applications:
row_details=[]
row_details.append(apl.applied_at)
row_details.append(apl.student.roll_no)
row_details.append(apl.student.name)
row_details.append(str(apl.student.roll_no)+"@iitdh.ac.in")
row_details.append(apl.student.phone_number)
row_details.append(apl.student.branch)
row_details.append(apl.student.batch)
row_details.append(apl.student.cpi)
link = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(apl.student.id + "/" + apl.resume)
row_details.append(link)
row_details.append(apl.selected)
for i in placement.additional_info:
row_details.append(json.loads(apl.additional_info)[i])
writer.writerow(row_details)
f.close()
file_path = LINK_TO_APPLICATIONS_CSV + urllib.parse.quote_plus(filename+".csv")
return Response({'action': "Create csv", 'message': "CSV created", 'file': file_path},
status=status.HTTP_200_OK)
except:
logger.warning("Create csv: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Create csv", 'message': "Error Occurred"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -42,6 +42,7 @@ CLIENT_ID = "956830229554-290mirc16pdhd5j7ph7v7ukibo4t1qcp.apps.googleuserconten
PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}" PLACEMENT_OPENING_URL = "https://www.googleapis.com/auth/adwords/{id}"
LINK_TO_STORAGE_COMPANY_ATTACHMENT = "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/" LINK_TO_STORAGE_COMPANY_ATTACHMENT = "https://storage.googleapis.com/cdc-backend-attachments/company_attachments/"
LINK_TO_STORAGE_RESUME = "https://storage.googleapis.com/cdc-backend-attachments/resume/" LINK_TO_STORAGE_RESUME = "https://storage.googleapis.com/cdc-backend-attachments/resume/"
LINK_TO_APPLICATIONS_CSV = "https://storage.googleapis.com/cdc-backend-attachments/applications-csv/"
TOKEN = "token_id" TOKEN = "token_id"
@ -58,6 +59,8 @@ MAX_OFFERS_PER_STUDENT = 2
STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/" STORAGE_DESTINATION_RESUMES = "./Storage/Resumes/"
STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/' STORAGE_DESTINATION_COMPANY_ATTACHMENTS = './Storage/Company_Attachments/'
STORAGE_DESTINATION_APPLICATION_CSV = './Storage/Application_CSV/'
RESUME_FILE_NAME = 'resume_file_name' RESUME_FILE_NAME = 'resume_file_name'
@ -120,8 +123,6 @@ STUDENT_ID = "student_id"
STUDENT_SELECTED = "student_selected" STUDENT_SELECTED = "student_selected"
COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - CDC IIT Dharwad" COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT = "Notification Submitted - {id} - CDC IIT Dharwad"
STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}' STUDENT_APPLICATION_STATUS_TEMPLATE_SUBJECT = 'Application Status : {company_name} - {id}'
STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - {company_name}' STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - {company_name}'
@ -131,3 +132,5 @@ COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html'
STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html' STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html'
STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE = 'student_application_status_not_selected.html' STUDENT_APPLICATION_STATUS_NOT_SELECTED_TEMPLATE = 'student_application_status_not_selected.html'
APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI',
'Resume', 'Selected', ]

View File

@ -160,3 +160,19 @@ class PlacementApplicationSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = PlacementApplication model = PlacementApplication
exclude = [STUDENT, 'resume'] exclude = [STUDENT, 'resume']
class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer):
student_details = serializers.SerializerMethodField()
resume_link = serializers.SerializerMethodField()
def get_student_details(self, obj):
data = StudentSerializer(obj.student).data
return data
def get_resume_link(self, obj):
link = LINK_TO_STORAGE_RESUME + urllib.parse.quote_plus(obj.id + "/" + obj.resume)
return link
class Meta:
model = PlacementApplication
exclude = ['placement', 'resume']

View File

@ -178,7 +178,7 @@ def submitApplication(request, id, email, user_type):
return Response({'action': "Submit Application", 'message': "Application Submitted"}, return Response({'action': "Submit Application", 'message': "Application Submitted"},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)
except Http404 as e: except Http404 as e:
return Response({'action': "Submit Application", 'message': "Student Not Found"}, return Response({'action': "Submit Application", 'message': str(e)},
status=status.HTTP_404_NOT_FOUND) status=status.HTTP_404_NOT_FOUND)
except PermissionError as e: except PermissionError as e:
return Response({'action': "Submit Application", 'message': str(e)}, return Response({'action': "Submit Application", 'message': str(e)},

View File

@ -103,7 +103,7 @@ def isAuthorized(allowed_users=None):
def generateRandomString(): def generateRandomString():
try: try:
N = 15 N = 15
res = ''.join(random.choices(string.ascii_uppercase + string.digits, k=N)) res = ''.join(random.choices(string.ascii_uppercase +string.ascii_lowercase+ string.digits, k=N))
return res return res
except: except:
return False return False

View File

@ -11,7 +11,9 @@ https://docs.djangoproject.com/en/2.2/ref/settings/
""" """
import os import os
from dotenv import load_dotenv
load_dotenv("../dev.env")
# import django_heroku # import django_heroku
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
@ -81,19 +83,15 @@ WSGI_APPLICATION = 'CDC_Backend.wsgi.application'
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases # https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = { DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
'default': { 'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2', 'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'cdc', 'NAME': os.environ.get("DB_NAME"),
'USER': 'postgres', 'USER': os.environ.get("DB_USER"),
'PASSWORD': 'root', 'PASSWORD': os.environ.get("DB_PASSWORD"),
'HOST': 'localhost', 'HOST': os.environ.get("DB_HOST"),
'PORT': '5432', 'PORT': os.environ.get("DB_PORT"),
}, },
# 'default': { # 'default': {
# 'ENGINE': 'django.db.backends.postgresql_psycopg2', # 'ENGINE': 'django.db.backends.postgresql_psycopg2',
# 'NAME': 'd84i5cbjig5rrf', # 'NAME': 'd84i5cbjig5rrf',
@ -160,8 +158,8 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com' EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
EMAIL_PORT = 587 EMAIL_PORT = 587
EMAIL_HOST_USER = 'saisurya3127@gmail.com'#'email here' EMAIL_HOST_USER = os.environ.get("EMAIL") # 'email here'
EMAIL_HOST_PASSWORD = 'yeylqcnsyjfpzsew'#'password here' EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_PASSWORD") # 'password here'
LOGGING = { LOGGING = {
'version': 1, 'version': 1,
@ -179,6 +177,11 @@ LOGGING = {
'level': 'DEBUG', 'level': 'DEBUG',
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler' 'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
}, },
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
}
}, },
'loggers': { 'loggers': {
'db': { 'db': {
@ -188,5 +191,4 @@ LOGGING = {
} }
} }
# django_heroku.settings(locals()) # django_heroku.settings(locals())

10
dev.env Normal file
View File

@ -0,0 +1,10 @@
HOSTING_URL=http://localhost:8000/
DEBUG=True
EMAIL=saisurya3127@gmail.com
EMAIL_PASSWORD=yeylqcnsyjfpzsew
SECRET_KEY=%2e!&f6(ib^690y48z=)&w6fczhwukzzp@3y*^*7u+7%4s-mie
DB_NAME=cdc
DB_USER=postgres
DB_PASSWORD=root
DB_HOST=localhost
DB_PORT=5432

92
nginx.conf Executable file
View File

@ -0,0 +1,92 @@
#user nobody;
worker_processes 1;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
# Server static files /storage
location /storage {
alias '/home/gowtham/Gowtham/Shared Projects/cdc-placement-website-backend/CDC_Backend/Storage';
# autoindex on;
}
location /static {
# autoindex on;
alias '/home/gowtham/Gowtham/Shared Projects/cdc-placement-website-backend/CDC_Backend/static';
}
location /api/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
location /admin/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

View File

@ -1,4 +1,4 @@
asgiref==3.4.1 asgiref==3.4.1
astroid==2.9.0 astroid==2.9.0
cachetools==4.2.4 cachetools==4.2.4
certifi==2021.10.8 certifi==2021.10.8
@ -13,24 +13,28 @@ django-cors-headers==3.10.0
django-db-logger==0.1.11 django-db-logger==0.1.11
djangorestframework==3.12.4 djangorestframework==3.12.4
google-auth==2.3.3 google-auth==2.3.3
gunicorn==20.1.0
idna==3.3 idna==3.3
importlib-metadata==4.8.2
isort==5.10.1 isort==5.10.1
jsonfield==3.1.0 jsonfield==3.1.0
lazy-object-proxy==1.6.0 lazy-object-proxy==1.6.0
Markdown==3.3.6 Markdown==3.3.6
mccabe==0.6.1 mccabe==0.6.1
platformdirs==2.4.0 platformdirs==2.4.0
psycopg2==2.9.2 psycopg2-binary==2.9.2
pyasn1==0.4.8 pyasn1==0.4.8
pyasn1-modules==0.2.8 pyasn1-modules==0.2.8
pylint==2.12.1 pylint==2.12.1
python-dotenv==0.19.2
pytz==2021.3 pytz==2021.3
requests==2.26.0 requests==2.26.0
rsa==4.8 rsa==4.8
six==1.16.0 six==1.16.0
sqlparse==0.4.2 sqlparse==0.4.2
toml==0.10.2 toml==0.10.2
typing-extensions==4.0.0 typing_extensions==4.0.0
urllib3==1.26.7 urllib3==1.26.7
whitenoise==5.3.0 whitenoise==5.3.0
wrapt==1.13.3 wrapt==1.13.3
zipp==3.6.0

22
setup.sh Normal file
View File

@ -0,0 +1,22 @@
python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt
echo "Environment setup complete"
cd CDC_Backend
python3 manage.py flush --no-input
python3 manage.py makemigrations
python3 manage.py migrate
echo "Migrations complete"
python3 manage.py collectstatic --noinput
DIR="./Storage"
if [ -d "$DIR" ]; then
### Take action if $DIR exists ###
echo "${DIR} Directory already exists"
else
### Control will jump here if $DIR does NOT exists ###
echo "Creating ${DIR} Directory..."
mkdir ${DIR}
echo "${DIR} Directory Created"
fi