Skip to content

Commit 41e23a7

Browse files
authored
Move supervisor id in researcher table. (#40)
Fix #28
1 parent 17d2466 commit 41e23a7

File tree

8 files changed

+91
-44
lines changed

8 files changed

+91
-44
lines changed

db.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,14 @@ class User(db.Model):
2323
is_admin = db.Column(db.Boolean, default=False)
2424
is_teacher = db.Column(db.Boolean, default=False)
2525
active = db.Column(db.Boolean, default=True)
26-
supervisor_id = db.Column(db.Integer, db.ForeignKey('user.id'))
2726
organization_id = db.Column(db.Integer, db.ForeignKey('organization.id'))
2827

29-
supervisor = db.relationship('User', remote_side=[id], backref='supervisees')
3028
organization = db.relationship('Organization', back_populates='users')
3129

3230
@validates('active')
3331
def validate_active(self, key, value):
3432
if not value:
35-
if self.supervisees:
33+
if self.researchers:
3634
raise ValueError("Cannot deactivate a supervisor who has supervisees.")
3735
if self.user_teacher:
3836
raise ValueError("Cannot deactivate a teacher assigned to a course.")
@@ -81,6 +79,15 @@ class Researcher(db.Model):
8179
user = db.relationship('User', backref=db.backref('researcher_profile', uselist=False))
8280

8381

82+
class ResearcherSupervisor(db.Model):
83+
__tablename__ = 'researcher_supervisor'
84+
researcher_id = db.Column(db.Integer, db.ForeignKey('researcher.id'), primary_key=True)
85+
supervisor_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
86+
87+
researcher = db.relationship('Researcher', backref=db.backref('supervisors', lazy=True))
88+
supervisor = db.relationship('User', backref=db.backref('researchers', lazy=True))
89+
90+
8491
class Teacher(db.Model):
8592
__tablename__ = 'teacher'
8693
id = db.Column(db.Integer, primary_key=True)

static/scripts/util.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function handleYearSelectChange() {
1717
});
1818
}
1919

20-
function addBadge(selectElement, containerSelector) {
20+
function addBadge(selectElement, containerSelector, name) {
2121
var selectedOption = $(selectElement).find('option:selected');
2222
var selectedValue = selectedOption.val();
2323
var selectedText = selectedOption.text();
@@ -41,7 +41,7 @@ function addBadge(selectElement, containerSelector) {
4141
}).appendTo(tagHtml);
4242
$('<input>', {
4343
type: 'hidden',
44-
name: 'organization_code[]',
44+
name: name + '[]',
4545
value: selectedValue
4646
}).appendTo(tagHtml);
4747

templates/add_course.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ <h2 class="text-center mb-4">New Course</h2>
7474
</select>
7575
</div>
7676
<div id="tags-container"></div>
77-
7877
</div>
7978
</div>
8079
<br>
@@ -90,7 +89,7 @@ <h2 class="text-center mb-4">New Course</h2>
9089
$(document).ready(function () {
9190
$('#organization_code').change(function () {
9291
var containerSelector = '#tags-container';
93-
addBadge(this, containerSelector);
92+
addBadge(this, containerSelector, 'organization_code');
9493
});
9594
});
9695
</script>

templates/register.html

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,15 @@ <h2 class="text-center mb-4">New user</h2>
7777
<div class="row justify-content-center">
7878
<div class="col-sm-4" id="supervisor_select" style="display: none;">
7979
<br>
80-
<label for="supervisor">Supervisor</label>
81-
<select class="form-select" id="supervisor" name="supervisor">
82-
{% for supervisor in supervisors %}
83-
<option value="{{ supervisor.id }}">{{ supervisor.first_name }} {{ supervisor.name }}</option>
84-
{% endfor %}
85-
</select>
80+
<div class="form-group">
81+
<label for="supervisor">Supervisor</label>
82+
{% with is_disabled=false, show_selected_supervisors=false %}
83+
{% include "search_supervisor.html"%}
84+
{% endwith %}
85+
</div>
8686
</div>
8787
</div>
88+
8889
<div class="row justify-content-center">
8990
<div class="col-sm-4" id="researcher_type_select" style="display: none;">
9091
<br>

templates/search_supervisor.html

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<style>
2+
.badge a {
3+
color: black;
4+
text-decoration: none;
5+
}
6+
7+
.badge a:hover {
8+
color: red;
9+
}
10+
</style>
11+
12+
<select class="form-select" id="supervisor" name="supervisor" {% if is_disabled %} disabled {% endif %}>
13+
<option value="" disabled selected>Select a supervisor</option>
14+
{% for supervisor in supervisors %}
15+
<option value="{{ supervisor.id }}">
16+
{{ supervisor.name }} {{ supervisor.first_name }}
17+
</option>
18+
{% endfor %}
19+
</select>
20+
21+
22+
<div id="tags-container">
23+
{% if show_selected_supervisors %}
24+
{% for selected in researcher.supervisors %}
25+
<div class="badge bg-primary" data-id="{{ selected.supervisor.id }}">
26+
{{ selected.supervisor.name }} {{ selected.supervisor.first_name }}&nbsp;
27+
{% if session["is_admin"] %} <a href="#" class="remove-tag">&times;</a> {% endif %}
28+
<input type="hidden" name="supervisor[]" value="{{ selected.supervisor.id }}">
29+
</div>
30+
{% endfor %}
31+
{% endif %}
32+
</div>
33+
34+
35+
<script>
36+
$(document).ready(function () {
37+
$(document).on('change', '#supervisor', function () {
38+
var containerSelector = '#tags-container';
39+
40+
addBadge($(this), containerSelector, 'supervisor');
41+
});
42+
});
43+
</script>

templates/user_profile.html

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ <h2>Your informations</h2>
8686
<dd>
8787
{% if session["is_admin"] %}
8888
<div class="form-check">
89-
9089
<input type="checkbox" class="form-check-input" id="is_admin"
9190
name="is_admin"
9291
{% if requested_user.is_admin %}checked{% endif %}
@@ -113,36 +112,22 @@ <h2>Your informations</h2>
113112
<div class="form-group" id="supervisor_select" style="display: none;">
114113
<dt>Supervisor</dt>
115114
<dd>
116-
<select class="form-select" id="supervisor" name="supervisor"
117-
{% if not session.is_admin %} disabled {% endif %}>
118-
{% if requested_user.supervisor == None and not session.is_admin %}
119-
<option value="" selected>None</option>
120-
{% else %}
121-
{% for supervisor in supervisors %}
122-
<option value="{{ supervisor.id }}"
123-
{% if supervisor.id == requested_user.supervisor.id %}selected{% endif %}>
124-
{{ supervisor.first_name }} {{ supervisor.name }}
125-
</option>
126-
{% endfor %}
127-
{% endif %}
128-
</select>
115+
{% with is_disabled=(not session["is_admin"]), show_selected_supervisors=true %}
116+
{% include "search_supervisor.html" %}
117+
{% endwith %}
129118
</dd>
130119
</div>
131120
<div class="form-group" id="researcher_type_display" style="display: none;">
132121
<dt>Researcher type</dt>
133122
<dd>
134123
<select class="form-select" id="researcher_type" name="researcher_type"
135124
{% if not session.is_admin %} disabled {% endif %}>
136-
{% if is_researcher and not session.is_admin %}
137-
<option value="" selected>None</option>
138-
{% else %}
139125
{% for type in researcher_type %}
140126
<option value="{{ type }}"
141127
{% if type == researcher.researcher_type %}selected{% endif %}>
142128
{{ type }}
143129
</option>
144130
{% endfor %}
145-
{% endif %}
146131
</select>
147132
</dd>
148133
</div>
@@ -272,7 +257,8 @@ <h2>Course preferences</h2>
272257
{% if session.is_admin == False %} disabled {% endif %}>
273258
{% for config in configurations %}
274259
<option value="{{ config.year }}" {% if config.year == current_year %}
275-
selected {% endif %} data-redirect="{{ url_for('user.user_profile', user_id=requested_user.id, current_year=config.year) }}">
260+
selected {% endif %}
261+
data-redirect="{{ url_for('user.user_profile', user_id=requested_user.id, current_year=config.year) }}">
276262
{{ config.year }}-{{ config.year + 1 }}
277263
</option>
278264
{% endfor %}

templates/users.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ <h4>Users</h4>
6969
<td>{{ user.email }}</td>
7070
<td><span class="badge bg-primary">{{ user.organization.name }}</span></td>
7171
{% if user_type == 'researcher' %}
72-
<td>{{ user.user_researcher.researcher_type }}</td>
73-
<td>{{ user.user_researcher.max_loads }}</td>
72+
<td>{{ user.researcher_profile.researcher_type }}</td>
73+
<td>{{ user.researcher_profile.max_loads }}</td>
7474
<td></td>
7575
{% endif %}
7676
{% if user_type == 'archived' %}
7777
{% if user.is_teacher %}
7878
<td>Teacher</td>
7979
{% else %}
80-
<td>{{ user.user_researcher.researcher_type }}</td>
80+
<td>{{ user.researcher_profile.researcher_type }}</td>
8181
{% endif %}
8282
<td>
8383
<a href="{{ url_for('user.enable', user_id=user.id) }}"

user.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from decorators import login_required, check_access_level
2-
from db import db, User, Researcher, Course, PreferenceAssignment, Teacher, Role
2+
from db import db, User, Researcher, Course, PreferenceAssignment, Teacher, Role, ResearcherSupervisor
33
from flask import Blueprint, render_template, flash, url_for, request, make_response, redirect, session, \
44
Flask
55
from enums import DEFAULT_MAX_LOAD
@@ -17,7 +17,7 @@ def create_researcher(user_id, researcher_type, max_loads):
1717
new_researcher = Researcher(user_id=user_id, researcher_type=researcher_type, max_loads=max_loads)
1818
db.session.add(new_researcher)
1919
db.session.commit()
20-
20+
return new_researcher
2121

2222
def get_researchers():
2323
return db.session.query(User).join(Researcher).filter(User.active == True).all()
@@ -62,21 +62,28 @@ def add_user():
6262
organization_code = request.form['organization_code']
6363
is_teacher = 'is_teacher' in request.form
6464
is_researcher = 'is_researcher' in request.form
65-
supervisor_id = request.form.get('supervisor') if is_researcher else None
65+
supervisor_ids = request.form.getlist('supervisor[]') if is_researcher else None
6666
researcher_type = request.form['researcher_type'] if is_researcher else None
6767

6868
try:
6969
if db.session.query(User).filter(User.email == email).first():
7070
flash("Email already exists")
7171
else:
72-
new_user = User(name=name, first_name=first_name, email=email, supervisor_id=supervisor_id,
72+
new_user = User(name=name, first_name=first_name, email=email, is_teacher=is_teacher,
7373
organization_id=organization_code)
7474
db.session.add(new_user)
7575
db.session.commit()
7676
if is_researcher:
7777
all_loads = DEFAULT_MAX_LOAD
7878
max_load = all_loads.get(researcher_type, 0)
79-
create_researcher(new_user.id, researcher_type, max_load)
79+
new_researcher = create_researcher(new_user.id, researcher_type, max_load)
80+
81+
if supervisor_ids:
82+
supervisors = db.session.query(User).filter(User.id.in_(supervisor_ids)).all()
83+
new_researcher.supervisors = [ResearcherSupervisor(researcher=new_researcher, supervisor=s) for s in supervisors]
84+
db.session.commit()
85+
86+
flash("User added successfully.", "success")
8087
except:
8188
db.session.rollback()
8289
raise
@@ -131,6 +138,7 @@ def user_profile(user_id, current_year):
131138
if researcher:
132139
preferences = db.session.query(PreferenceAssignment).filter_by(researcher_id=researcher.id,
133140
course_year=current_year).all()
141+
134142
courses = []
135143
if current_user and requested_user.organization:
136144
courses = db.session.query(Course).filter(Course.year == current_year,
@@ -176,13 +184,12 @@ def update_user_profile(user_id):
176184
is_admin = True if 'is_admin' in request.form else False
177185
is_teacher = True if 'is_teacher' in request.form else False
178186
is_researcher = True if 'is_researcher' in request.form else False
179-
supervisor_id = request.form.get('supervisor') if is_researcher else None
187+
supervisor_ids = request.form.getlist('supervisor[]') if is_researcher else None
180188
researcher_type = request.form['researcher_type'] if is_researcher else None
181189
max_loads = request.form['max_load'] if is_researcher else None
182190

183191
user = db.session.query(User).filter(User.id == user_id).first()
184192
researcher = db.session.query(Researcher).filter(Researcher.user_id == user.id).first()
185-
teacher = db.session.query(Teacher).filter(Teacher.user_id == user.id).first()
186193
if user is None:
187194
return make_response("User not found", 404)
188195

@@ -194,16 +201,20 @@ def update_user_profile(user_id):
194201
user.organization_id = organization_code
195202
user.is_admin = is_admin
196203
user.is_teacher = is_teacher
197-
user.supervisor_id = supervisor_id
204+
user.is_researcher = is_researcher
198205
if is_researcher:
199206
if researcher is None:
200207
create_researcher(user.id, researcher_type, max_loads)
201208
else:
202209
researcher.max_loads = max_loads
203210
researcher.researcher_type = researcher_type
211+
212+
if supervisor_ids:
213+
db.session.query(ResearcherSupervisor).filter_by(researcher_id=researcher.id).delete()
214+
supervisors = db.session.query(User).filter(User.id.in_(supervisor_ids)).all()
215+
researcher.supervisors = [ResearcherSupervisor(researcher=researcher, supervisor=s) for s in supervisors]
204216
else:
205217
delete_researcher(user.id)
206-
207218
db.session.commit()
208219
except Exception as e:
209220
db.session.rollback()

0 commit comments

Comments
 (0)