diff --git a/.DS_Store b/.DS_Store index 4808ac2..b4c80e4 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 64c7e13..43f423c 100644 --- a/.gitignore +++ b/.gitignore @@ -142,4 +142,4 @@ dmypy.json dev.env #vscode settings -.vscode/ +.vscode/ \ No newline at end of file diff --git a/CDC_Backend/.DS_Store b/CDC_Backend/.DS_Store index e1c3358..7f94099 100644 Binary files a/CDC_Backend/.DS_Store and b/CDC_Backend/.DS_Store differ diff --git a/CDC_Backend/APIs/companyUrls.py b/CDC_Backend/APIs/companyUrls.py index 4db1c55..e09de52 100644 --- a/CDC_Backend/APIs/companyUrls.py +++ b/CDC_Backend/APIs/companyUrls.py @@ -5,4 +5,5 @@ from . import companyViews urlpatterns = [ path('addPlacement/', companyViews.addPlacement, name="Add Placement"), path('verifyEmail/', companyViews.verifyEmail, name="Verify Email"), + path('getAutoFillJnf/', companyViews.autoFillJnf, name="Auto FIll JNF"), ] diff --git a/CDC_Backend/APIs/companyViews.py b/CDC_Backend/APIs/companyViews.py index 590673e..60e144c 100644 --- a/CDC_Backend/APIs/companyViews.py +++ b/CDC_Backend/APIs/companyViews.py @@ -1,6 +1,7 @@ from rest_framework.decorators import api_view from .utils import * +from .serializers import * logger = logging.getLogger('db') @@ -283,7 +284,8 @@ def verifyEmail(request): "opening_type": PLACEMENT, "company_name": opening.company_name, } - sendEmail([opening.email, CDC_MAIl_ADDRESS], COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data, + sendEmail([opening.email, CDC_MAIl_ADDRESS], + COMPANY_OPENING_SUBMITTED_TEMPLATE_SUBJECT.format(id=opening.id), data, COMPANY_OPENING_SUBMITTED_TEMPLATE, attachment_jnf_respone) return Response({'action': "Verify Email", 'message': "Email Verified Successfully"}, @@ -298,3 +300,23 @@ def verifyEmail(request): logger.warning("Verify Email: " + str(sys.exc_info())) return Response({'action': "Verify Email", 'message': "Something went wrong"}, status=status.HTTP_400_BAD_REQUEST) + + +@api_view(['GET']) +@precheck([PLACEMENT_ID]) +def autoFillJnf(request): + try: + data = request.GET + placement_id = data.get(PLACEMENT_ID) + opening = get_object_or_404(Placement, id=placement_id) + serializer = AutofillSerializers(opening) + return Response({'action': "Get AutoFill", 'message': 'Data Found', 'placement_data': serializer.data}, + status=status.HTTP_200_OK) + except Http404: + return Response({'action': "Get AutoFill", 'message': 'Placement Not Found'}, + status=status.HTTP_404_NOT_FOUND) + except Exception as e: + traceback_str = traceback.format_exc() + logger.warning("Get AutoFill: " + traceback_str) + return Response({'action': "Get AutoFill", 'message': "Something went wrong"}, + status=status.HTTP_400_BAD_REQUEST) diff --git a/CDC_Backend/APIs/constants.py b/CDC_Backend/APIs/constants.py index 526eb9e..d2daf91 100644 --- a/CDC_Backend/APIs/constants.py +++ b/CDC_Backend/APIs/constants.py @@ -49,6 +49,9 @@ CDC_MAIl_ADDRESS = 'cdc@iitdh.ac.in' # To be Configured Properly CLIENT_ID = os.environ.get('GOOGLE_OAUTH_CLIENT_ID') # Google Login Client ID +CLIENT_SECRET = os.environ.get('GOOGLE_OAUTH_CLIENT_SECRET') # Google Login Client Secret +REDIRECT_URI = 'postmessage' # Google Login Redirect URI +OAUTH2_API_ENDPOINT = 'https://oauth2.googleapis.com/token' # Google Login OAUTH2 URL # To be Configured Properly PLACEMENT_OPENING_URL = "https://cdc.iitdh.ac.in/portal/student/dashboard/placements/{id}" # On frontend, this is the URL to be opened @@ -58,6 +61,9 @@ LINK_TO_APPLICATIONS_CSV = "https://cdc.iitdh.ac.in/storage/Application_CSV/" LINK_TO_EMAIl_VERIFICATION_API = "https://cdc.iitdh.ac.in/portal/company/verifyEmail?token={token}" PDF_FILES_SERVING_ENDPOINT = 'https://cdc.iitdh.ac.in/storage/Company_Attachments/' # TODO: Change this to actual URL +AUTH_CODE = "code" +ID_TOKEN = "id_token" +REFRESH_TOKEN = "refresh_token" EMAIL = "email" STUDENT = 'student' @@ -90,6 +96,7 @@ FIELD = "field" STATUS_ACCEPTING_APPLICATIONS = "Accepting Applications" PLACEMENT = "Placement" +PLACEMENT_ID = "placement_id" COMPANY_NAME = "company_name" ADDRESS = "address" @@ -158,7 +165,7 @@ STUDENT_APPLICATION_SUBMITTED_TEMPLATE_SUBJECT = 'CDC - Application Submitted - STUDENT_APPLICATION_UPDATED_TEMPLATE_SUBJECT = 'CDC - Application Updated - {company_name}' COMPANY_EMAIl_VERIFICATION_TEMPLATE_SUBJECT = 'Email Verification - Career Development Cell, IIT Dharwad' NOTIFY_STUDENTS_OPENING_TEMPLATE_SUBJECT = 'Placement Opportunity at {company_name}' - +REMINDER_STUDENTS_OPENING_TEMPLATE_SUBJECT = 'Reminder - Placement Opportunity at {company_name}' STUDENT_APPLICATION_SUBMITTED_TEMPLATE = 'student_application_submitted.html' COMPANY_OPENING_SUBMITTED_TEMPLATE = 'company_opening_submitted.html' STUDENT_APPLICATION_STATUS_SELECTED_TEMPLATE = 'student_application_status_selected.html' @@ -167,7 +174,7 @@ STUDENT_APPLICATION_UPDATED_TEMPLATE = 'student_application_updated.html' COMPANY_EMAIL_VERIFICATION_TEMPLATE = 'company_email_verification.html' COMPANY_JNF_RESPONSE_TEMPLATE = 'company_jnf_response.html' NOTIFY_STUDENTS_OPENING_TEMPLATE = 'notify_students_new_opening.html' - +REMINDER_STUDENTS_OPENING_TEMPLATE = 'students_opening_reminder.html' APPLICATION_CSV_COL_NAMES = ['Applied At', 'Roll No.', 'Name', 'Email', 'Phone Number', 'Branch', 'Batch', 'CPI', 'Resume', 'Selected', ] diff --git a/CDC_Backend/APIs/serializers.py b/CDC_Backend/APIs/serializers.py index ad7d9f7..19d94bc 100644 --- a/CDC_Backend/APIs/serializers.py +++ b/CDC_Backend/APIs/serializers.py @@ -188,4 +188,11 @@ class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer): class ContributorSerializer(serializers.ModelSerializer): class Meta: - model = Contributor \ No newline at end of file + model = Contributor + + + +class AutofillSerializers(serializers.ModelSerializer): + class Meta: + model = Placement + fields = '__all__' \ No newline at end of file diff --git a/CDC_Backend/APIs/studentViews.py b/CDC_Backend/APIs/studentViews.py index e02e0f1..62d36b4 100644 --- a/CDC_Backend/APIs/studentViews.py +++ b/CDC_Backend/APIs/studentViews.py @@ -7,15 +7,42 @@ logger = logging.getLogger('db') @api_view(['POST']) +@precheck(required_data=[AUTH_CODE]) +@get_token() @isAuthorized(allowed_users='*') -def login(request, id, email, user_type): +def login(request, id, email, user_type, token, refresh_token): try: - return Response({'action': "Login", 'message': "Verified", "user_type": user_type}, + return Response({'action': "Login", 'message': "Verified", "user_type": user_type, "id_token": token, "refresh_token": refresh_token}, status=status.HTTP_200_OK) except: return Response({'action': "Login", 'message': "Something Went Wrong"}, status=status.HTTP_400_BAD_REQUEST) +@api_view(['POST']) +@precheck(required_data=[REFRESH_TOKEN]) +def refresh(request): + refresh_token = request.data[REFRESH_TOKEN] + data = { + 'refresh_token': refresh_token, + 'client_id': CLIENT_ID, + 'client_secret': CLIENT_SECRET, + 'redirect_uri': REDIRECT_URI, + 'grant_type': 'refresh_token' + } + response = rq.post(OAUTH2_API_ENDPOINT, data=data) + if response.status_code == 200: + id_info = id_token.verify_oauth2_token(response.json()['id_token'], requests.Request(), CLIENT_ID) + if id_info['iss'] not in ['accounts.google.com', 'https://accounts.google.com']: + raise ValueError('Wrong issuer.') + user_types = User.objects.filter(email=id_info['email']).values_list('user_type', flat=True) + return Response({'action': "Refresh Token", 'message': "Token Refreshed", "id_token": response.json()['id_token'], "user_type": user_types[0]}, + status=status.HTTP_200_OK) + else: + logger.error("refresh_token"+str(response)) + return Response({'action': "Refresh Token", 'message': "Something Went Wrong"}, + status=status.HTTP_400_BAD_REQUEST) + + @api_view(['GET']) @isAuthorized(allowed_users=[STUDENT]) diff --git a/CDC_Backend/APIs/urls.py b/CDC_Backend/APIs/urls.py index 36f929e..af80640 100644 --- a/CDC_Backend/APIs/urls.py +++ b/CDC_Backend/APIs/urls.py @@ -4,6 +4,7 @@ from . import studentViews, studentUrls, companyUrls, adminUrls urlpatterns = [ path('login/', studentViews.login, name="Login"), + path('refresh_token/', studentViews.refresh, name="Refresh Token"), 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 index be57175..63f2729 100644 --- a/CDC_Backend/APIs/utils.py +++ b/CDC_Backend/APIs/utils.py @@ -33,6 +33,38 @@ from .models import User, PrePlacementOffer, PlacementApplication, Placement, St logger = logging.getLogger('db') +def get_token(): + def decorator(view_func): + def wrapper_func(request, *args, **kwargs): + try: + authcode = request.data[AUTH_CODE] + data = { + 'code': authcode, + 'client_id': CLIENT_ID, + 'client_secret': CLIENT_SECRET, + 'redirect_uri': REDIRECT_URI, + 'grant_type': 'authorization_code' + } + r = rq.post(OAUTH2_API_ENDPOINT, data=data) + if r.status_code == 200: + response = r.json() + token = response[ID_TOKEN] + refresh_token = response[REFRESH_TOKEN] + request.META["HTTP_AUTHORIZATION"] = "Bearer " + token + request.META["MODIFIED"] = "True" + kwargs['refresh_token'] = refresh_token + return view_func(request, *args, **kwargs) + else: + return Response({'action': "Get Token", 'message': "Invalid Auth Code"}, + status=status.HTTP_400_BAD_REQUEST) + except Exception as e: + logger.warning("Get Token: " + str(sys.exc_info())) + return Response({'action': "Get Token", 'message': str(e)}, + status=status.HTTP_400_BAD_REQUEST) + return wrapper_func + return decorator + + def precheck(required_data=None): if required_data is None: required_data = [] @@ -84,7 +116,10 @@ def isAuthorized(allowed_users=None): user.last_login_time = timezone.now() user.save() 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) + if "MODIFIED" in headers: + return view_func(request, user.id, user.email, user.user_type, token_id, *args, **kwargs) + else: + 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: @@ -285,7 +320,7 @@ def opening_description_table_html(opening): else: # if isinstance(opening, QueryDict): details = opening keys = list(details.keys()) - newdetails = {} + newdetails = {"ID": opening.id} for key in keys: if isinstance(details[key], list): details[key] = {"details": details[key], "type": ["list"]} diff --git a/CDC_Backend/CDC_Backend/settings.py b/CDC_Backend/CDC_Backend/settings.py index 4f04556..786e67b 100644 --- a/CDC_Backend/CDC_Backend/settings.py +++ b/CDC_Backend/CDC_Backend/settings.py @@ -30,7 +30,7 @@ DEBUG = os.environ.get('DEBUG') == "True" ALLOWED_HOSTS = ['cdc.iitdh.ac.in', 'localhost'] -ADMINS = [('Gowtham Sai', '190010036@iitdh.ac.in'), ('Karthik Mv', '200010030@iitdh.ac.in')] +ADMINS = [ ('Karthik Mv', '200010030@iitdh.ac.in')] # Application definition INSTALLED_APPS = [ @@ -48,7 +48,7 @@ INSTALLED_APPS = [ 'background_task', 'simple_history', 'import_export', - "django_extensions" + 'django_extensions' ] MIDDLEWARE = [ diff --git a/CDC_Backend/scripts/send_reminder_mails.py b/CDC_Backend/scripts/send_reminder_mails.py new file mode 100644 index 0000000..0048c34 --- /dev/null +++ b/CDC_Backend/scripts/send_reminder_mails.py @@ -0,0 +1,63 @@ +from APIs.models import Placement, Student, PlacementApplication, User +from APIs.utils import sendEmail, PlacementApplicationConditions +from APIs.constants import * +from django.shortcuts import get_object_or_404 +from django.utils import timezone +import time +import pytz + +REPEAT_AFTER = 10 * 60 + + +def send_reminder_mails(): + placements = Placement.objects.all() + students = Student.objects.all() + + for placement in placements.iterator(): + print("Processing placement: ", placement) + # if placement is approved and email is verified + if not (placement.offer_accepted and placement.email_verified): + continue + + # if placement is not expired + if placement.deadline_datetime < timezone.now(): + continue + + # send the reminder mail if the deadline is within 24 hours +- ReapetAfter + if timezone.now() - timezone.timedelta( + seconds=REPEAT_AFTER) <= placement.deadline_datetime - timezone.timedelta(days=1) < timezone.now() + \ + timezone.timedelta(seconds=REPEAT_AFTER): + for student in students: + try: + # if Application not found then send email + if not PlacementApplication.objects.filter(placement=placement, student=student).exists(): + if student.branch in placement.allowed_branch: + if student.degree == 'bTech' or placement.rs_eligible is True: + if PlacementApplicationConditions(student, placement)[0]: + student_user = get_object_or_404(User, id=student.id) + # change timezone to IST + deadline_datetime = placement.deadline_datetime.astimezone(pytz.timezone('Asia/Kolkata')) + data = { + "company_name": placement.company_name, + "opening_type": 'Placement', + "deadline": deadline_datetime.strftime("%A, %-d %B %Y, %-I:%M %p"), + "link": PLACEMENT_OPENING_URL.format(id=placement.id) + } + print("Sending mail to " + student_user.email, "placement id: ", placement.id) + sendEmail(student_user.email, + REMINDER_STUDENTS_OPENING_TEMPLATE_SUBJECT.format( + company_name=placement.company_name), + data, REMINDER_STUDENTS_OPENING_TEMPLATE) + + except Exception as e: + print(e) + continue + + +def run(): + while True: + print("Sleeping for", REPEAT_AFTER, "seconds") + time.sleep(REPEAT_AFTER) + print("Running send_reminder_mails()") + send_reminder_mails() + diff --git a/CDC_Backend/templates/students_opening_reminder.html b/CDC_Backend/templates/students_opening_reminder.html index 4541089..dd0b9d2 100644 --- a/CDC_Backend/templates/students_opening_reminder.html +++ b/CDC_Backend/templates/students_opening_reminder.html @@ -45,7 +45,7 @@
- Gentle reminder for the same. + Gentle reminder to fill out the application form. Interested students can apply before {{ deadline }} in the CDC-webportal.
diff --git a/README.md b/README.md index bae49a2..1c41ba8 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ python# CDC - Backend ### Setup 1. Download the Repository to your local machine