Commit 85e6dc13 authored by Rajiv Vaidyanathan's avatar Rajiv Vaidyanathan

Implemented SPA algorithm and facad dashboard

parent bd65d104
File added
from django.contrib import admin
# Register your models here.
from .models import *
from django_drf_filepond.models import TemporaryUpload, StoredUpload
admin.site.register(PositionsModel)
admin.site.register(RequisitesModel)
admin.site.register(StudentDetailModel)
......@@ -15,4 +17,4 @@ admin.site.register(StudentPrioritiesArchive)
admin.site.register(ProjectPrioritiesArchive)
admin.site.register(StudentResumeModel)
admin.site.register(TemporaryUpload)
admin.site.register(StoredUpload)
admin.site.register(StoredUpload)
\ No newline at end of file
from copy import deepcopy
# Student project allocation algorithm function
def SPA(S, Ppref, Pc, Ms, Mp, MsPrev):
'''
Input:
S : Student priorities
Ppref: Project Priorities
Pc: Counts for each project
Ms: Empty structure for student results
Mp: Empty structure for project results
MsPrev: Empty structure for end case handling
Output:
Student to project mapping
'''
isStable = True
for i in Ms.values():
if len(i)==0:
isStable = False
break
# print(isStable)
# Part 2 (compute and return to the webapp)
# Run algo
while True:
for stud in Ms.keys():
if len(Ms[stud])==0 and len(S[stud])>0:
# provisionally asigning
# print("Current student: ", stud)
proj = S[stud][0]
# lec = P2L[proj]
Ms[stud].append(proj)
Mp[proj].append(stud)
# check if project is oversubscibed
while len(Mp[proj]) > Pc[proj]:
# find the least priority students assigned to the project
prefList = Ppref[proj] # pref order of current project
idx = len(prefList)-1
found = False
while not found:
if prefList[idx] in Mp[proj]:
Mp[proj].remove(prefList[idx])
Ms[prefList[idx]].remove(proj)
S[prefList[idx]].remove(proj)
prefList.remove(prefList[idx])
# print("Removing project: ", proj)
# print("from student: ", prefList[idx])
found = True
else:
idx -= 1
# isStable = reduce(lambda x, y: (x and (len(y)>0), Ms.values(), True)
# isStable = True
# for i in Ms.values():
# if len(i)==0:
# isStable = False
# break
if Ms == MsPrev:
break
MsPrev = deepcopy(Ms)
return Ms
if __name__ == '__main__':
S = {"s1": ["p1", "p2"], "s2": ["p1"]}
Ppref = {"p1": [ "s2"], "p2": [ "s2"]}
Pc = {"p1":1, "p2": 1}
Ms = {"s1": [], "s2": []}
Mp = {"p1": [], "p2": []}
MsPrev = []
for M in Ms:
print(Ms[M])
res = SPA(S, Ppref, Pc, Ms, Mp, MsPrev)
for student in res:
print(student,res[student])
# subject choices for requisites in faculty dashboard
subject_choices = (
('CS601', 'CS601'),
('CS725', 'CS725'),
('CS699','CS699'),
('CS626','CS626'),
('CS747','CS747')
)
# Language choices for student to select for their projects
language_choices = (
('Python', 'Python'),
('Java', 'Java'),
('C','C'),
('C++','C++'),
('HTML','HTML'),
('CSS','CSS'),
('Javascript','Javascript'),
('Scala','Scala'),
('Go','Go'),
('Ruby','Ruby'),
('Matlab','Matlab'),
('Angular','Angular'),
('Django','Django'),
('Other','Other')
)
# Color mappings for languages used in project
language_color_mappings = {
'Python':'teal',
'Java':'yellow',
'C':'inverted yellow',
'C++':'inverted orange',
'HTML':'inverted red',
'CSS':'primary',
'Javascript':'inverted olive',
'Scala':'brown',
'Go':'inverted violet',
'Ruby':'purple',
'Matlab':'olive',
'Angular':'inverted green',
'Django':'red',
'Other':'grey'
}
# Choices for student for education details
exam_choices = (
('BE/BTech','BE/BTech'),
('10+2','10+2'),
('SSLC','SSLC'),
('MTech','MTech'),
('PhD','PhD')
)
color_choices = (
'teal',
'brown',
'violet',
'olive',
'grey',
'purple',
'orange',
'primary'
'inverted yellow',
'inverted olive',
'inverted violet',
'inverted green',
'inverted red'
)
\ No newline at end of file
from django.forms.models import inlineformset_factory
from django.forms import ModelForm, TextInput, NumberInput, Select, Textarea, DateInput
from .models import PositionsModel, RequisitesModel, StudentDetailModel, StudentProjectsModel, StudentEducationModel
from .models import PositionsModel, RequisitesModel, StudentDetailModel, StudentProjectsModel, StudentEducationModel, RoundDetailsModel
# Form to get the project details from faculty
......@@ -63,3 +63,15 @@ StudentProjectFormset = inlineformset_factory(StudentDetailModel,StudentProjects
StudentEducationFormset = inlineformset_factory(StudentDetailModel,StudentEducationModel,form=StudentEducationModelForm,
extra=1,can_delete=False)
# Form to get round details from facAd
class RoundDetailsModelForm(ModelForm):
class Meta:
model = RoundDetailsModel
exclude = ()
widgets = {
'roundNo': NumberInput(attrs={'type':'hidden'}),
'startDate': DateInput(attrs={'placeholder':'yyyy-mm-dd'}),
'endDate': DateInput(attrs={'placeholder':'yyyy-mm-dd'})
}
This diff is collapsed.
......@@ -90,10 +90,47 @@ class StudentResumeModel(models.Model):
student = models.ForeignKey(StudentDetailModel,related_name="resume",on_delete=models.CASCADE)
file = models.ForeignKey(StoredUpload,on_delete=models.DO_NOTHING)
# Model to store priorities of student for ongoing round
class StudentPriorities(models.Model):
student = models.ForeignKey(StudentDetailModel,related_name='priorities',on_delete=models.CASCADE,db_column="student_id")
project = models.ForeignKey(PositionsModel,related_name='student_priorities',on_delete=models.CASCADE,db_column="project_id")
current_priority = models.IntegerField(verbose_name="Priority Value",null=False,blank=False,default=-1)
date = models.DateField(verbose_name="Application Date",null=False,blank=False,default=datetime.now)
# Model to store priorities of student for previous rounds
class StudentPrioritiesArchive(models.Model):
roundNo = models.IntegerField(verbose_name="Round Number",null=False,blank=False,default=1)
student = models.ForeignKey(StudentDetailModel,related_name='archived_priorities',on_delete=models.CASCADE,db_column="student_id")
project = models.ForeignKey(PositionsModel,related_name='archived_student_priorities',on_delete=models.CASCADE,db_column="project_id")
current_priority = models.IntegerField(verbose_name="Priority Value",null=False,blank=False,default=-1)
date = models.DateField(verbose_name="Application Date",null=False,blank=False,default=datetime.now)
# Model to store priorities of project for ongoing round
class ProjectPriorities(models.Model):
project = models.ForeignKey(PositionsModel,related_name='priorities',on_delete=models.CASCADE,db_column="project_id")
student = models.ForeignKey(StudentDetailModel,related_name='project_priorities',on_delete=models.CASCADE,db_column="student_id")
current_priority = models.IntegerField(verbose_name="Priority Value",null=False,blank=False,default=-1)
date = models.DateField(verbose_name="Application Date",null=False,blank=False,default=datetime.now)
# Model to store priorities of project for previous rounds
class ProjectPrioritiesArchive(models.Model):
roundNo = models.IntegerField(verbose_name="Round Number",null=False,blank=False,default=1)
project = models.ForeignKey(PositionsModel,related_name='archived_priorities',on_delete=models.CASCADE,db_column="project_id")
student = models.ForeignKey(StudentDetailModel,related_name='archived_project_priorities',on_delete=models.CASCADE,db_column="student_id")
current_priority = models.IntegerField(verbose_name="Priority Value",null=False,blank=False,default=-1)
date = models.DateField(verbose_name="Application Date",null=False,blank=False,default=datetime.now)
# Model to store the details of every round
class RoundDetailsModel(models.Model):
roundNo = models.IntegerField(verbose_name="Round Number",null=False,blank=False,default=1,primary_key = True)
startDate = models.DateField(verbose_name="Round Start Date",null=False,blank=False,default=datetime.now)
endDate = models.DateField(verbose_name="Round End Date",null=False,blank=False,default=datetime.now()+timedelta(days=10))
allocated = models.IntegerField(verbose_name="Count of Alloted students",null=True,blank=True)
unallocated = models.IntegerField(verbose_name="Count of Unalloted students",null=True,blank=True)
# Model to store generated mappings for every round
class GeneratedMappingsModel(models.Model):
roundNo = models.IntegerField(verbose_name="Round Number",null=False,blank=False,default=1)
project = models.ForeignKey(PositionsModel,related_name="student_mappings",on_delete=models.DO_NOTHING,db_column="project_id")
faculty = models.ForeignKey(User,on_delete=models.DO_NOTHING,db_column="faculty_id")
student = models.ForeignKey(StudentDetailModel,related_name="student_allotment",on_delete=models.DO_NOTHING,db_column="student_id")
student = models.ForeignKey(StudentDetailModel,related_name="student_allotment",on_delete=models.DO_NOTHING,db_column="student_id")
\ No newline at end of file
\documentclass{article}%
\usepackage[T1]{fontenc}%
\usepackage[utf8]{inputenc}%
\usepackage{lmodern}%
\usepackage{textcomp}%
\usepackage{lastpage}%
\usepackage{geometry}%
\geometry{margin=0.4in}%
\usepackage{ragged2e}%
\usepackage{longtable}%
\usepackage{tabu}%
\usepackage{booktabs}%
\usepackage{multirow}%
%
%
%
\begin{document}%
\normalsize%
\begin{center}%
\begin{Large}%
\textbf{Summary}%
\end{Large}%
\end{center}%
\renewcommand{\arraystretch}{2.0}%
\setlength{\tabcolsep}{1in}%
\begin{longtabu}{|c c|}%
\hline%
\textbf{No. of Students applied}&2\\%
\textbf{No. of Slots Offered}&4\\%
\textbf{No. of Students alloted}&2\\%
\hline%
\end{longtabu}%
\renewcommand{\arraystretch}{2.0}%
\setlength{\tabcolsep}{0.35in}%
\begin{longtabu}{|c c c c|}%
\hline%
\textbf{GuideId}&\textbf{Guide Name}&\textbf{Requirements}&\textbf{Alloted}\\%
\hline%
\hline%
fac{-}1&Faculty 1&4&\textbf{2}\\%
\hline%
\end{longtabu}%
\begin{center}%
\begin{Large}%
\textbf{Student{-}Guide Mapping Result for Seminar}%
\end{Large}%
\end{center}%
\renewcommand{\arraystretch}{2.0}%
\setlength{\tabcolsep}{0.2in}%
\begin{longtabu}{@{}|c|c|c|c|c|@{}}%
\toprule%
\midrule%
\textbf{GuideId}&\textbf{GuideName}&\textbf{Topic\_offered}&\textbf{AllotedStudentId}&\textbf{AllotedStudentName}\\%
\midrule%
\midrule%
\endhead%
\multirow{2}{*}{fac{-}1}&\multirow{2}{*}{Faculty 1}&\multirow{2}{*}{1}&1&darshan\\%
\cmidrule{4%
-%
5}%
&&&2&student{-}1\\%
\cmidrule{4%
-%
5}%
\cmidrule{3%
-%
5}%
\cmidrule{1%
-%
5}\bottomrule%
%
\end{longtabu}%
\end{document}
\ No newline at end of file
\documentclass{article}%
\usepackage[T1]{fontenc}%
\usepackage[utf8]{inputenc}%
\usepackage{lmodern}%
\usepackage{textcomp}%
\usepackage{lastpage}%
\usepackage{geometry}%
\geometry{margin=0.4in}%
\usepackage{ragged2e}%
\usepackage{longtable}%
\usepackage{tabu}%
\usepackage{booktabs}%
\usepackage{multirow}%
%
%
%
\begin{document}%
\normalsize%
\begin{center}%
\begin{Large}%
\textbf{Summary}%
\end{Large}%
\end{center}%
\renewcommand{\arraystretch}{2.0}%
\setlength{\tabcolsep}{1in}%
\begin{longtabu}{|c c|}%
\hline%
\textbf{No. of Students applied}&3\\%
\textbf{No. of Slots Offered}&4\\%
\textbf{No. of Students alloted}&2\\%
\hline%
\end{longtabu}%
\renewcommand{\arraystretch}{2.0}%
\setlength{\tabcolsep}{0.35in}%
\begin{longtabu}{|c c c|}%
\hline%
\textbf{Guide Name}&\textbf{Requirements}&\textbf{Alloted}\\%
\hline%
\hline%
Faculty 1&4&\textbf{2}\\%
\hline%
\end{longtabu}%
\begin{center}%
\begin{Large}%
\textbf{Student{-}Guide Mapping Result for MTP}%
\end{Large}%
\end{center}%
\renewcommand{\arraystretch}{2.0}%
\setlength{\tabcolsep}{0.2in}%
\begin{longtabu}{@{}|c|c|c|c|@{}}%
\toprule%
\midrule%
\textbf{GuideName}&\textbf{Topic\_offered}&\textbf{AllotedStudentId}&\textbf{AllotedStudentName}\\%
\midrule%
\midrule%
\endhead%
\multirow{2}{*}{Faculty 1}&\multirow{2}{*}{1}&1&darshan\\%
\cmidrule{3%
-%
4}%
&&2&student{-}1\\%
\cmidrule{3%
-%
4}%
\cmidrule{2%
-%
4}%
\cmidrule{1%
-%
4}\bottomrule%
%
\end{longtabu}%
\end{document}
\ No newline at end of file
......@@ -103,6 +103,7 @@
<a class="item" data-tab="second">Shortlisted Applications</a>
<a class="item" data-tab="third">Open positions</a>
<a class="item" data-tab="fourth">Alloted students</a>
{% if user_type == 'facad' %}<a class="item" data-tab="fifth">FacAd dashboard</a>{% endif %}
</div>
<div class="ui tab active" data-tab="first">
......@@ -394,6 +395,159 @@
</div>
{% if user_type == 'facad' %}
<div class="ui tab" data-tab="fifth" style="padding-top: 2em;">
<div class="ui stackable height stretched grid">
<div class="nine wide column">
<div class="ui fluid raised card">
<div class="content">
<h3 class="ui center aligned" style="color:slategrey;">Round Details</h3>
</div>
<div class="content">
<form class="ui form" method="POST">
<table class="ui celled brown definition table center aligned">
<thead>
<tr>
<th>Actions</th>
<th>Round Number</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
</thead>
<tbody>
{% for roundDetail in roundDetails %}
{% if forloop.counter != roundDetails|length %}
<tr>
<td class="collapsing">
<button type="button" class="ui small button inverted blue disabled">Update</button>
</td>
<td>Round {{ forloop.counter }}</td>
<td>{{ roundDetail.startDate }}</td>
<td>{{ roundDetail.startDate }}</td>
</tr>
{% else %}
<tr class="olive">
{% csrf_token %}
<input type="hidden" name="roundDetailUpdate" value="true">
<td class="collapsing">
<div class="latest-round-form" style="display: none;">
<button type="submit" class="ui small button secondary">Submit</button>
</div>
<div class="latest-round-detail">
<button type="button" class="ui small button blue" onclick="show_round_detail_form()">Update</button>
</div>
</td>
<td>
<div class="" style="display: none;">
{{ RoundUpdateform.roundNo }}
</div>
<div class="">
{{ forloop.counter }}
</div>
</td>
<td>
<div class="latest-round-form" style="display: none;">
<div class="ui calendar date_picker">
<div class="ui input left icon">
<i class="calendar icon"></i>
{{ RoundUpdateform.startDate }}
</div>
</div>
</div>
<div class="latest-round-detail">
{{ roundDetail.startDate }}
</div>
</td>
<td>
<div class="latest-round-form" style="display: none;">
<div class="ui calendar date_picker">
<div class="ui input left icon">
<i class="calendar icon"></i>
{{ RoundUpdateform.endDate }}
</div>
</div>
</div>
<div class="latest-round-detail">
{{ roundDetail.endDate }}
</div>
</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
</form>
</div>
<div class="content">
<div class="center aligned four wide column">
<form action="{% url 'gap:generateMapping' %}" method="POST" class="ui column">
{% csrf_token %}
<button class="fluid ui flexible labeled teal icon button"type="submit" onclick="return confirm('Do you want to SHORTLIST this application?');" >
Generate Mappings
</button>
</form>
</div>
</div>
</div>
</div>
<div class="seven wide column">
<div class="ui fluid teal card">
<div class="content">
<div class="ui center aligned header" style="color:slategrey;">Alloted students vs Unalloted students</div>
</div>
<div class="content">
<canvas id="alloted-unalloted" ></canvas>
</div>
</div>
</div>
<div class="sixteen wide column" style="padding-top: 2em;">
<div class="ui fluid teal card">
<div class="content">
<div class="ui center aligned header" style="color:slategrey;">Allotments done so far
<button class="ui right floated flexible labeled teal icon button" onclick="$(this).find('a')[0].click()" >
<i class="file download icon"></i>
<a href="{% static 'guideAllocationPortal/allocationResults.pdf' %}" style="display: none;" target="_blank"></a>
Download allotments
</button>
</div>
</div>
<div class="content">
<table id="generatedAllotments" class="ui table raised segment center aligned" style="width:100%">
<thead>
<tr>
<th>ROUND NUMBER</th>
<th>STUDENT</th>
<th>FACULTY</th>
<th>PROJECT</th>
</tr>
</thead>
<tbody>
{% for allotment in AllotmentsSoFar %}
<tr>
<td>
{{ allotment.roundNo }}
</td>
<td>
{{ allotment.student.student.get_full_name }}
</td>
<td>
{{ allotment.faculty.get_full_name }}
</td>
<td>
{{ allotment.project.title }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endif %}
{% endblock %}
......@@ -1134,9 +1288,112 @@ $(document).ready(function() {
});
{% endfor %}
{% endif %}
{% if user_type == 'facad' %}
render_stats_tab();
{% endif %}
} );
{% if user_type == 'facad' %}
function render_stats_tab(){
var lineChartData = {
labels: [ {% for round in roundDetails %}'Round {{ round.roundNo }}', {% endfor %}],
datasets: [{
label: 'Allotted Students',
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgb(255, 99, 132)',
fill: false,
data: [{% for round in roundDetails %}{% if forloop.counter != roundDetails|length %}{{ round.allocated }}, {% endif %}{% endfor %}],
},
{
label: 'Unallotted Students',
borderColor: 'rgb(132, 99, 255)',
backgroundColor: 'rgb(132, 99, 255)',
fill: false,
data: [ {% for round in roundDetails %}{% if forloop.counter != roundDetails|length %}{{ round.unallocated }}, {% endif %}{% endfor %} ],
}]
};
var ctx = document.getElementById('alloted-unalloted').getContext('2d');
myLine = new Chart(ctx, {
type: 'line',
data: lineChartData,
options: {
responsive: true,
interaction: {
mode: 'index'
},
stacked: false,
title: {
display: false,
},
scales: {
yAxes: [{
scaleLabel: {
display: true,
labelString: 'Cumulative number of Students'
}
}]
},
}
});
var facultyallocationData = {
labels: ['Faculty 1', 'Faculty 2', 'Faculty 3', 'Faculty 4', 'Faculty 5'],
datasets: [{
data: [10,15,20,22,23],
backgroundColor:['red','orange','teal','green','blue'],
}]
};
var ctx = document.getElementById('faculty-allocation').getContext('2d');
myLine = new Chart(ctx, {
type: 'doughnut',
data: facultyallocationData,
options: {
responsive: true,
interaction: {
mode: 'index'
},
title: {
display: false,
},
animation: {
animateScale: true,
animateRotate: true
},
}
});
var facultyunallocationData = {
labels: ['Faculty 1', 'Faculty 2', 'Faculty 3', 'Faculty 4', 'Faculty 5'],
datasets: [{
data: [10,15,20,22,23],
backgroundColor:['red','orange','teal','green','blue'],
}]
};
var ctx = document.getElementById('faculty-unallocation').getContext('2d');
myLine = new Chart(ctx, {
type: 'doughnut',
data: facultyunallocationData,
options: {
responsive: true,
interaction: {
mode: 'index'
},
title: {
display: false,
},
animation: {
animateScale: true,
animateRotate: true
},
}
});
}
function show_round_detail_form(){
$('.latest-round-detail').hide();
$('.latest-round-form').show();
}
{% endif %}
function sync_total_forms(){
......
......@@ -117,4 +117,4 @@
{% endif %}
</body>
</html>
</html>
\ No newline at end of file
from django.urls import path, include
from .views import LoginView, LogoutView, dashboardView, shortlistView, updatePriorityView
from .views import LoginView, LogoutView, dashboardView, shortlistView, updatePriorityView, generateMappingsView
urlpatterns = [
path('login',LoginView.as_view(),name="login"),
path('logout',LogoutView,name="logout"),
path('',dashboardView.as_view(),name="dashboard"),
path('shortlist',shortlistView,name="shortlist"),
path('updatepriorities',updatePriorityView,name="updatePriorities")
]
path('updatepriorities',updatePriorityView,name="updatePriorities"),
path('generatemapping',generateMappingsView,name="generateMapping")
]
\ No newline at end of file
This diff is collapsed.
Team - DePReSs
git link to the project:
https://git.cse.iitb.ac.in/darshanp/Team_DePReSs_Project
Team Members :
Piyush Sharma - 203050055 piyusharma@cse.iitb.ac.in
Sandeep Parihar - 203050083 sandy@cse.iitb.ac.in
Darshan Prabhu - 203059005 darshanp@cse.iitb.ac.in
Rajiv Vaidyanathan Natarajan - 203059003 rajivvn@cse.iitb.ac.in
==================================================================================
Motivation:
In many university departments, students seek to undertake a project under some faculty. Typically there will be a wide range of available projects that is offered, and usually the total number of project places exceeds the number of students, to provide something of a choice.
Each professor will offer a variety of projects, but have very limited intake. Each students has preferences over the available projects the he/she finds acceptable, similarly professor will have some preferences over students that he/she is willing to supervise.
Motivation behind this project is to facilitate the professor handling large number of applications and shortlisting of students at one place. This portal makes it easier for them to view and shortlist students on a GUI interface. It saves their time and mostly reduces manual work.
Detailed Description of this project is discussed in the Developer Manual and User Manual.
==================================================================================
How to use:
Guide Allocation Portal is easy to use and very handy.
You must install below mentioned dependencies before starting the project.
To install pip3, run the following command:
sudo apt-get -y install python3-pip
To install all requirements on ubuntu, run the following command in your terminal.
virtualenv -p python3 gapenv
source gapenv/bin/activate
pip3 install -r requirements.txt
All other dependencies that is required to install is mentioned in the requirements.txt
To open the project one need to git clone the project. Open the terminal, go to project main directory and run the following commands.
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py runserver
Now the server is running. Open the web browser and type the link : "localhost:8000". You can now access the Guide Allocation Portal.
certifi==2020.11.8
chardet==3.0.4
cycler==0.10.0
Django==2.2
django-drf-filepond==0.3.0
django-multiselectfield==0.1.12
django-storages==1.10.1
djangorestframework==3.12.2
idna==2.10
kiwisolver==1.3.1
matplotlib==3.3.3
numpy==1.19.4
ordered-set==4.0.2
Pillow==8.0.1
PyLaTeX==1.4.1
pyparsing==2.4.7
python-dateutil==2.8.1
pytz==2020.4
requests==2.25.0
shortuuid==1.0.1
six==1.15.0
sqlparse==0.4.1
urllib3==1.26.2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment