Merge branch 'main' into gowtham/send-reminder-mails

This commit is contained in:
karthik mv 2023-05-30 15:06:54 +05:30 committed by GitHub
commit 65fc6face4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 347 additions and 10 deletions

View File

@ -15,4 +15,5 @@ urlpatterns = [
path('generateCSV/', adminViews.generateCSV, name="Generate CSV"), path('generateCSV/', adminViews.generateCSV, name="Generate CSV"),
path('addPPO/', adminViews.addPPO, name="Add PPO"), path('addPPO/', adminViews.addPPO, name="Add PPO"),
path('getStudentApplication/', adminViews.getStudentApplication, name="Get student application"), path('getStudentApplication/', adminViews.getStudentApplication, name="Get student application"),
path('getStats/', adminViews.getStats, name="Get Stats"),
] ]

View File

@ -429,3 +429,205 @@ def getStudentApplication(request, id, email, user_type):
logger.warning("Get Student Application: " + str(sys.exc_info())) logger.warning("Get Student Application: " + str(sys.exc_info()))
return Response({'action': "Get Student Application", 'message': "Something Went Wrong"}, return Response({'action': "Get Student Application", 'message': "Something Went Wrong"},
status.HTTP_400_BAD_REQUEST) status.HTTP_400_BAD_REQUEST)
@api_view(['GET'])
@isAuthorized(allowed_users=[ADMIN])
def getStats(request, id, email, user_type):
try:
stats = []
placement_ids = {}
tier_count = {
"CSE": {
"1":0,
"2":0,
"3":0,
"4":0,
"5":0,
"6":0,
"7":0,
"psu":0,
},
"EE": {
"1":0,
"2":0,
"3":0,
"4":0,
"5":0,
"6":0,
"7":0,
"psu":0,
},
"MMAE": {
"1":0,
"2":0,
"3":0,
"4":0,
"5":0,
"6":0,
"7":0,
"psu":0,
},
"Total": {
"1":0,
"2":0,
"3":0,
"4":0,
"5":0,
"6":0,
"7":0,
"psu":0,
},
}
number_of_students_placed = {
"CSE": 0,
"EE": 0,
"MMAE": 0,
"Total": 0,
}
number_of_students_with_multiple_offers = 0
number_of_students_with_no_offers = {
"CSE": 0,
"EE": 0,
"MMAE": 0,
"Total": 0,
}
max_CTC = {
"CSE": 0,
"EE": 0,
"MMAE": 0
}
average_CTC = {
"CSE": 0,
"EE": 0,
"MMAE": 0
}
count = {
"CSE": 0,
"EE": 0,
"MMAE": 0
}
students = Student.objects.all().order_by("roll_no")
for student in students.iterator():
applications = PlacementApplication.objects.filter(student=student, selected=True)
ppos = PrePlacementOffer.objects.filter(student=student, accepted=True)
first_offer_data = None
second_offer_data = None
# get the first and second offer
offers = []
offers.extend(applications)
offers.extend(ppos)
if len(offers) == 0:
number_of_students_with_no_offers[student.branch] += 1
number_of_students_with_no_offers["Total"] += 1
else:
number_of_students_placed[student.branch] += 1
number_of_students_placed["Total"] += 1
if len(offers) > 1:
number_of_students_with_multiple_offers += 1
for offer in offers:
if type(offer) == PrePlacementOffer:
if first_offer_data is None:
first_offer_data = {
"id": offer.id,
"company": offer.company,
"compensation": offer.compensation,
"tier": offer.tier,
"type": "PPO",
}
elif second_offer_data is None:
second_offer_data = {
"id": offer.id,
"company": offer.company,
"compensation": offer.compensation,
"tier": offer.tier,
"type": "PPO",
}
elif type(offer) == PlacementApplication:
if first_offer_data is None:
first_offer_data = {
"id": offer.placement.id,
"company": offer.placement.company_name,
"compensation": offer.placement.compensation_CTC,
"tier": offer.placement.tier,
"type": "Placement",
}
elif second_offer_data is None:
second_offer_data = {
"id": offer.placement.id,
"company": offer.placement.company_name,
"compensation": offer.placement.compensation_CTC,
"tier": offer.placement.tier,
"type": "Placement",
}
data = {
"id": student.id,
"name": student.name,
"roll_no": student.roll_no,
"batch": student.batch,
"branch": student.branch,
"cpi": student.cpi,
"first_offer": first_offer_data['company'] if first_offer_data is not None else None,
"first_offer_tier": first_offer_data['tier'] if first_offer_data is not None else None,
"first_offer_compensation": first_offer_data['compensation'] if first_offer_data is not None else None,
"second_offer": second_offer_data['company'] if second_offer_data is not None else None,
"second_offer_tier": second_offer_data['tier'] if second_offer_data is not None else None,
"second_offer_compensation": second_offer_data['compensation'] if second_offer_data is not None else None,
}
if first_offer_data is not None:
tier_count[student.branch][first_offer_data['tier']] += 1
tier_count['Total'][first_offer_data['tier']] += 1
max_CTC[student.branch] = max(max_CTC[student.branch], first_offer_data['compensation'])
average_CTC[student.branch] += first_offer_data['compensation']
count[student.branch] += 1
if first_offer_data['type'] == "Placement":
placement_ids[first_offer_data['company']] = first_offer_data['id']
if second_offer_data is not None:
tier_count[student.branch][second_offer_data['tier']] += 1
tier_count['Total'][second_offer_data['tier']] += 1
max_CTC[student.branch] = max(max_CTC[student.branch], second_offer_data['compensation'])
average_CTC[student.branch] += second_offer_data['compensation']
count[student.branch] += 1
if second_offer_data['type'] == "Placement":
placement_ids[second_offer_data['company']] = second_offer_data['id']
stats.append(data)
for branch in average_CTC:
if count[branch] > 0:
average_CTC[branch] /= count[branch]
# round off to 2 decimal places
average_CTC[branch] = round(average_CTC[branch], 2)
else:
average_CTC[branch] = 0
return Response({'action': "Get Stats", 'message': "Stats fetched", 'stats': stats, 'placement_ids': placement_ids,
"tier_count": {br: tier_count[br].values() for br in tier_count},
"number_of_students_placed": number_of_students_placed,
"number_of_students_with_multiple_offers": number_of_students_with_multiple_offers,
"number_of_students_with_no_offers": number_of_students_with_no_offers,
"max_CTC": max_CTC,
"average_CTC": average_CTC,
},
status=status.HTTP_200_OK)
except:
logger.warning("Get Stats: " + str(sys.exc_info()))
print(sys.exc_info())
return Response({'action': "Get Stats", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -276,3 +276,16 @@ class PrePlacementOffer(models.Model):
self.changed_by = value self.changed_by = value
else: else:
self.changed_by = None self.changed_by = None
class Contributor(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="")
email = models.EmailField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", unique=True)
github_id = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", unique=True)
linkedin = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, unique=True, null=True)
commits = models.IntegerField(blank=False, default=0)
image = models.CharField(max_length=JNF_SMALLTEXT_MAX_CHARACTER_COUNT, blank=False, default="", null=True)
def __str__(self):
return self.name

View File

@ -162,7 +162,8 @@ class PlacementApplicationSerializer(serializers.ModelSerializer):
return data return data
def get_resume_link(self, obj): def get_resume_link(self, obj):
ele = {'link': LINK_TO_STORAGE_RESUME + urllib.parse.quote(str(obj.student.roll_no) + "/" + obj.resume), 'name': obj.resume} ele = {'link': LINK_TO_STORAGE_RESUME + urllib.parse.quote(str(obj.student.roll_no) + "/" + obj.resume),
'name': obj.resume}
return ele return ele
class Meta: class Meta:
@ -185,3 +186,9 @@ class PlacementApplicationSerializerForAdmin(serializers.ModelSerializer):
class Meta: class Meta:
model = PlacementApplication model = PlacementApplication
exclude = ['placement', 'resume'] exclude = ['placement', 'resume']
class ContributorSerializer(serializers.ModelSerializer):
class Meta:
model = Contributor
fields = '__all__'

View File

@ -10,4 +10,5 @@ urlpatterns = [
path("deleteResume/", studentViews.deleteResume, name="Upload Resume"), path("deleteResume/", studentViews.deleteResume, name="Upload Resume"),
path("submitApplication/", studentViews.submitApplication, name="Submit Application"), path("submitApplication/", studentViews.submitApplication, name="Submit Application"),
path("deleteApplication/", studentViews.deleteApplication, name="Delete Application"), path("deleteApplication/", studentViews.deleteApplication, name="Delete Application"),
path("getContributorStats/", studentViews.getContributorStats, name="Get Contributor Stats"),
] ]

View File

@ -231,3 +231,19 @@ def deleteApplication(request, id, email, user_type):
return Response({'action': "Delete Application", 'message': "Something Went Wrong"}, return Response({'action': "Delete Application", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET'])
@isAuthorized(allowed_users='*')
def getContributorStats(request, id, email, user_type):
try:
contributors = Contributor.objects.all()
serialized_data = ContributorSerializer(contributors, many=True).data
return Response({'action': "Get Contributor Stats", 'message': "Contributor Stats Fetched",
'data': serialized_data},
status=status.HTTP_200_OK)
except:
logger.warning("Get Contributor Stats: " + str(sys.exc_info()))
return Response({'action': "Get Contributor Stats", 'message': "Something Went Wrong"},
status=status.HTTP_400_BAD_REQUEST)

View File

@ -172,12 +172,17 @@ def PlacementApplicationConditions(student, placement):
selected_companies = PlacementApplication.objects.filter(student=student, selected=True) selected_companies = PlacementApplication.objects.filter(student=student, selected=True)
selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu'] selected_companies_PSU = [i for i in selected_companies if i.placement.tier == 'psu']
PPO = PrePlacementOffer.objects.filter(student=student, accepted=True) PPO = PrePlacementOffer.objects.filter(student=student, accepted=True)
PPO_PSU = [i for i in PPO if i.tier == 'psu']
# find length of PPO # find length of PPO
if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT: if len(selected_companies) + len(PPO) >= MAX_OFFERS_PER_STUDENT:
raise PermissionError("Max Applications Reached for the Season") raise PermissionError("Max Applications Reached for the Season")
if len(selected_companies_PSU) > 0: if len(selected_companies_PSU) > 0:
raise PermissionError('Selected for PSU Can\'t apply anymore') raise PermissionError('Selected for PSU Can\'t apply anymore')
if len(PPO_PSU) > 0:
raise PermissionError('Selected for PSU Can\'t apply anymore')
if placement.tier == 'psu': if placement.tier == 'psu':
return True, "Conditions Satisfied" return True, "Conditions Satisfied"
@ -186,7 +191,7 @@ def PlacementApplicationConditions(student, placement):
return False, "Can't apply for this tier" return False, "Can't apply for this tier"
for i in PPO: for i in PPO:
if int(i.placement.tier) < int(placement.tier): if int(i.tier) < int(placement.tier):
return False, "Can't apply for this tier" return False, "Can't apply for this tier"
if student.degree != 'bTech' and not placement.rs_eligible: if student.degree != 'bTech' and not placement.rs_eligible:

View File

@ -30,6 +30,7 @@ DEBUG = os.environ.get('DEBUG') == "True"
ALLOWED_HOSTS = ['cdc.iitdh.ac.in', 'localhost'] ALLOWED_HOSTS = ['cdc.iitdh.ac.in', 'localhost']
ADMINS = [('Gowtham Sai', '190010036@iitdh.ac.in'), ('Karthik Mv', '200010030@iitdh.ac.in')]
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
@ -47,6 +48,8 @@ INSTALLED_APPS = [
'simple_history', 'simple_history',
'import_export', 'import_export',
'django_extensions', 'django_extensions',
"django_extensions"
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -185,14 +188,13 @@ LOGGING = {
'class': 'django_db_logger.db_log_handler.DatabaseLogHandler' 'class': 'django_db_logger.db_log_handler.DatabaseLogHandler'
}, },
'mail_admins': { 'mail_admins': {
'level': 'ERROR', 'level': 'WARNING',
'class': 'django.utils.log.AdminEmailHandler', 'class': 'django.utils.log.AdminEmailHandler',
'include_html': True,
} }
}, },
'loggers': { 'loggers': {
'db': { 'db': {
'handlers': ['db_log'], 'handlers': ['db_log', 'mail_admins'],
'level': 'DEBUG' 'level': 'DEBUG'
} }
} }

View File

View File

@ -0,0 +1,70 @@
from APIs.models import Contributor
from django.shortcuts import get_object_or_404
import time
from dotenv import load_dotenv
import requests
import os
load_dotenv("../dev.env")
owner = 'CDC-IITDH'
access_token = os.environ.get("GITHUB_ACCESS_TOKEN")
headers = {'Authorization': "Token " + access_token}
maxRetires = 10
REPEAT_AFTER = 60 * 15 # 15 minutes
def getStats():
try:
stats = {}
repos = ['cdc-placement-website-backend', 'cdc-placement-website-frontend']
for i in repos:
try:
repo_name = i
print(repo_name)
url = f"https://api.github.com/repos/{owner}/{repo_name}/stats/contributors"
retry = 0
contributors = []
while True:
if retry > maxRetires:
break
req = requests.get(url, headers=headers)
contributors = req.json()
if req.status_code != 200:
print("ERROR:", req.json())
retry += 1
elif len(contributors):
break
retry += 1
time.sleep(1)
for contributor in contributors:
if contributor['author']['login'] not in stats:
stats[contributor['author']['login']] = 0
stats[contributor['author']['login']] += contributor['total']
except Exception as e:
print(e)
for i in stats:
try:
contributor = get_object_or_404(Contributor, github_id=i)
contributor.commits = stats[i]
contributor.save()
except:
pass
stats = sorted(stats.items(), key=lambda x: x[1], reverse=True)
for i in stats:
print(i)
except Exception as e:
print(e)
return stats
def run():
while True:
getStats()
print("Sleeping for", REPEAT_AFTER, "seconds")
time.sleep(REPEAT_AFTER)
print("Running send_reminder_mails()")
run()

View File

@ -5,7 +5,8 @@ python# CDC - Backend
### Setup ### Setup
1. Download the Repository to your local machine <br> 1. Download the Repository to your local machine <br>
2. Create a Virtual Environment in the [CDC_Backend](./) folder with this command below <br> 2. Make Sure u have downloaded python from python.org or windows store.
3. Create a Virtual Environment in the [CDC_Backend](./) folder with this command below <br>
`python -m venv venv` `python -m venv venv`
3. Activate the environment with this command <br> 3. Activate the environment with this command <br>
`.\venv\Scripts\activate` (for WINDOWS) <br> `.\venv\Scripts\activate` (for WINDOWS) <br>
@ -14,6 +15,17 @@ python# CDC - Backend
`pip install -r requirements.txt ` `pip install -r requirements.txt `
5. Ensure that you have the PostgreSQL installed on your machine and is running on PORT **5432** <br> 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)(https://www.youtube.com/watch?v=bE9h6aAky4s&t=193s) 6. Make sure to give the correct database credentials in [settings.py](./CDC_Backend/CDC_Backend/settings.py)(https://www.youtube.com/watch?v=bE9h6aAky4s&t=193s)
7. Run these following commands below. (The same are there in setup.sh for linux users and setup.bat for windows users)
```cd CDC_Backend
python manage.py flush --no-input
python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic --noinput
mkdir Storage
python manage.py makemigrations APIs
```
### Running the Application ### Running the Application
@ -28,13 +40,20 @@ python# CDC - Backend
1. You can access the admin panel by running the server and opening <http://localhost:8000/admin> 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. 2. Run `python manage.py createsuperuser` to create a user to access the admin panel.
3. Set up the Username and Password 3. if there is an error due to time then sync your machine time .
4. You can log in and change the database values anytime. 4. Set up the Username and Password
5. You can log in and change the database values anytime.
6. Create your id as insitute Roll No for both admin and student .
7. if you are still getting an error ,open inspect and see in network
And then recognize it
8.Check the client link in dev.env in backend and .env in frontend is the same
# Error # Error
1.make sure that your machine time and google time are same ,if not go to setting of date and time and sync this 1.make sure that your machine time and google time are same ,if not go to setting of date and time and sync this
2.make sure u have used same id for both student and Admin that is your iitfh roll_no 2.make sure u have used same id for both student and Admin that is your iitfh roll_no
3. same client link in .env of frontend or constants.py of bakcend 3. same client link in .env of frontend or constants.py of bakcend
### Deploying ### Deploying
1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py) 1. Add the hosted domain name in `ALLOWED_HOSTS` in [settings.py](./CDC_Backend/CDC_Backend/settings.py)

View File

@ -1,6 +1,6 @@
typical conf file for pg_hba.conf for dev work. typical conf file for pg_hba.conf for dev work.
```
# TYPE DATABASE USER ADDRESS METHOD # TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only # "local" is for Unix domain socket connections only
@ -14,3 +14,4 @@ host all all ::1/128 md5
local replication all peer local replication all peer
host replication all 127.0.0.1/32 ident host replication all 127.0.0.1/32 ident
host replication all ::1/128 ident host replication all ::1/128 ident
```