Skip to content

Commit a8879b9

Browse files
authored
Issue#34 researcher preferences should be put apart (#42)
1 parent 05296ee commit a8879b9

File tree

11 files changed

+290
-249
lines changed

11 files changed

+290
-249
lines changed

course_preference.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,34 +29,32 @@ def save_preference():
2929
current_year = get_current_year()
3030

3131
if data is None:
32-
return make_response("No data received", 500)
32+
return jsonify({"error": "No data received"}), 400
33+
34+
preferences = data.get("preferences", None)
35+
if preferences is None or len(preferences) == 0:
36+
return jsonify({"error": "No preferences received"}), 400
3337

34-
preferences = data['preferences']
35-
if preferences is None:
36-
return make_response("No preferences received", 500)
3738

3839
user_id = session["user_id"]
3940
researcher = Researcher.query.filter(Researcher.user_id == user_id).first()
4041
if researcher is None:
41-
return make_response("User is not a researcher", 500)
42+
return jsonify({"error": "Researcher not found"}), 400
4243

4344
delete_old_preferences(researcher.id, current_year)
4445

45-
rank = 0
46-
for preference in preferences:
46+
for rank, preference in enumerate(preferences):
4747
try:
48-
rank += 1
4948
course_id = preference['course_id']
50-
course_year = preference['course_year']
51-
new_preference = PreferenceAssignment(rank=rank, course_id=course_id, course_year=course_year,
49+
new_preference = PreferenceAssignment(rank=rank+1, course_id=course_id, course_year=current_year,
5250
researcher_id=researcher.id)
5351
db.session.add(new_preference)
5452
db.session.commit()
5553
except Exception as e:
5654
db.session.rollback()
5755
raise e
5856

59-
return redirect(url_for("user.user_profile", user_id=user_id, current_year=current_year))
57+
return redirect(url_for("user.preferences", user_id=user_id, current_year=current_year))
6058

6159

6260
@course_preference_bp.route('/delete_preference', methods=['GET'])
@@ -72,4 +70,4 @@ def delete_preference():
7270
db.session.rollback()
7371
raise e
7472

75-
return redirect(url_for("user.user_profile", user_id=session["user_id"], current_year=current_year))
73+
return redirect(url_for("user.preferences", user_id=session["user_id"], current_year=current_year))

db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ class PreferenceAssignment(db.Model):
125125
)
126126

127127
course = db.relationship('Course', backref=db.backref('course_preference_assignment', lazy=True))
128-
researcher = db.relationship('Researcher', backref=db.backref('researcher_preference_assignment', lazy=True))
128+
researcher = db.relationship('Researcher', backref=db.backref('preferences', lazy=True))
129129

130130

131131
class Year(db.Model):

static/scripts/assignment_table.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,6 @@ fetch('/assignment/load_data')
378378
});
379379

380380
$(document).ready(function () {
381-
function updateToastContent(message) {
382-
let toastBody = document.querySelector('#toast-notification .toast-body');
383-
toastBody.textContent = message;
384-
}
385-
386381
let toastNotification = new bootstrap.Toast(document.getElementById('toast-notification'));
387382

388383
$('#button-export').click(function () {

static/scripts/util.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ function filter(page) {
9191
}
9292
}
9393

94+
function updateToastContent(message) {
95+
let toastBody = document.querySelector('#toast-notification .toast-body');
96+
toastBody.textContent = message;
97+
}
98+
9499
// Event listener for removing the organization tag
95100
$(document).on('click', '.remove-tag', function (e) {
96101
e.preventDefault();

templates/assignment.html

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,7 @@ <h2 class="accordion-header" id="controlsHeading">
110110
</div>
111111
</div>
112112
</div>
113-
114-
<div class="toast" id="toast-notification" role="alert" aria-live="assertive" aria-atomic="true">
115-
<div class="toast-header">
116-
<strong class="me-auto">Notification</strong>
117-
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
118-
</div>
119-
<div class="toast-body">
120-
</div>
121-
</div>
113+
{% include "toast_notification.html" %}
122114
<div class="row">
123115
<div class="col mb-3 ms-3 mt-1">
124116
<div id="handsontable">
@@ -127,4 +119,5 @@ <h2 class="accordion-header" id="controlsHeading">
127119
</div>
128120
</div>
129121
</div>
122+
</div>
130123
{% endblock %}

templates/layout.html

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,14 @@
3838
<ul class="navbar-nav">
3939
<li class="nav-item">
4040
<a class="nav-link"
41-
href="{{ url_for('user.user_profile', user_id=session.user_id, current_year=dynamic_year) }}">My
41+
href="{{ url_for('user.user_profile', user_id=session.user_id) }}">My
4242
Profile</a>
4343
</li>
4444
{% if is_researcher %}
45+
<li>
46+
<a class="nav-link"
47+
href="{{ url_for('user.preferences', user_id=session.user_id, current_year=dynamic_year) }}">Preferences</a>
48+
</li>
4549
<li>
4650
<a class="nav-link"
4751
href="{{ url_for('course.user_evaluation', user_id=session.user_id, current_year=dynamic_year) }}">Evaluations</a>
@@ -96,8 +100,8 @@
96100
</ul>
97101
</li>
98102
<li>
99-
<a class="nav-link"
100-
href="{{ url_for('config.manage_years', configurations=configurations) }}">Configurations</a>
103+
<a class="nav-link"
104+
href="{{ url_for('config.manage_years') }}">Configurations</a>
101105
</li>
102106
<li class="nav-item dropdown">
103107
<a class="nav-link dropdown-toggle" href="#" id="assignmentDropdown" role="button"
@@ -119,7 +123,8 @@
119123
<div class="me-0">
120124
<div class="navbar-text me-2">
121125
<input type="text" class="form-control form-control-sm" id="dynamicYearInput"
122-
value="{{ dynamic_year }} - {{ dynamic_year + 1 }}" style="width: 100px;" disabled>
126+
value="{{ dynamic_year }} - {{ dynamic_year + 1 }}" style="width: 100px;"
127+
disabled>
123128
</div>
124129
</div>
125130

templates/preferences.html

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
{% extends "layout.html" %}
2+
{% block pagetitle %}Preferences{% endblock %}
3+
{% block additionalpageheader %}
4+
<style>
5+
.move-icon {
6+
cursor: move;
7+
}
8+
9+
.delete-icon {
10+
cursor: pointer;
11+
color: red;
12+
}
13+
</style>
14+
{% endblock %}
15+
16+
{% block pagecontent %}
17+
{% include "toast_notification.html" %}
18+
<div class="container-fluid">
19+
<form id="preferencesForm" method="post">
20+
<br>
21+
<h2>The preferences of {{ researcher.user.name }} {{ researcher.user.first_name }}</h2>
22+
<table class="table table-hover" id="staticPreferencesTable">
23+
<thead>
24+
<tr>
25+
<th>Code</th>
26+
<th>Title</th>
27+
<th>Semester</th>
28+
{% if session.is_admin %}
29+
<th>
30+
<select class="form-select form-select-sm d-inline" id="yearSelect"
31+
name="yearSelect">
32+
{% for config in configurations %}
33+
<option value="{{ config.year }}" {% if config.year == current_year %}
34+
selected {% endif %}
35+
data-redirect="{{ url_for('user.preferences', user_id=researcher.user.id,
36+
current_year=config.year) }}">
37+
{{ config.year }}-{{ config.year + 1 }}
38+
</option>
39+
{% endfor %}
40+
</select>
41+
</th>
42+
{% endif %}
43+
</tr>
44+
</thead>
45+
<tbody class="table-group-divider">
46+
{% for preference in preferences %}
47+
<tr>
48+
<td>{{ preference.course.code }}</td>
49+
<td>{{ preference.course.title }}</td>
50+
<td>{{ preference.course.quadri }}</td>
51+
<td>
52+
{% if not session.is_admin %}
53+
<a href="{{ url_for('course_preference.delete_preference', preference=preference.id) }}"
54+
class="delete-icon">
55+
<i class="fas fa-trash delete-icon"></i>
56+
</a>
57+
{% endif %}
58+
</td>
59+
</tr>
60+
{% endfor %}
61+
</tbody>
62+
</table>
63+
64+
<table class="table table-hover" id="editablePreferencesTable" style="display: none;">
65+
<thead>
66+
<tr>
67+
<th colspan="2">Code</th>
68+
</tr>
69+
</thead>
70+
<tbody class="table-group-divider">
71+
{% for preference in preferences %}
72+
<tr>
73+
<td>
74+
<select class="form-control course-select">
75+
{% for course in courses %}
76+
<option value="{{ course.id }}"
77+
{% if course.id == preference.course.id %}selected{% endif %}>
78+
{{ course.code }} - {{ course.title }}
79+
</option>
80+
{% endfor %}
81+
</select>
82+
</td>
83+
<td>
84+
<i class="fas fa-trash delete-icon"></i>
85+
<i class="fas fa-arrows-alt move-icon"></i>
86+
</td>
87+
</tr>
88+
{% endfor %}
89+
90+
<!-- Hidden row template -->
91+
<tr id="template-row" style="display: none;">
92+
<td>
93+
<select class="form-control course-select">
94+
{% for course in courses %}
95+
<option value="{{ course.id }}">
96+
{{ course.code }} - {{ course.title }}
97+
</option>
98+
{% endfor %}
99+
</select>
100+
</td>
101+
<td>
102+
<i class="fas fa-trash delete-icon"></i>
103+
<i class="fas fa-arrows-alt move-icon"></i>
104+
</td>
105+
</tr>
106+
</tbody>
107+
</table>
108+
109+
{% if not session.is_admin %}
110+
<button type="button" id="addPreferencesButton" class="btn btn-primary">Edit Preferences
111+
</button>
112+
{% endif %}
113+
<button type="button" id="savePreferencesButton" class="btn btn-success"
114+
style="display: none;">
115+
Save Preferences
116+
</button>
117+
<button type="button" id="cancelEditButton" class="btn btn-secondary"
118+
style="display: none;">
119+
Cancel
120+
</button>
121+
<button type="button" id="addRowButton" class="btn btn-primary" style="display: none;">
122+
Add Row
123+
</button>
124+
</form>
125+
</div>
126+
{% endblock %}
127+
128+
{% block additionalfooter %}
129+
<script>
130+
$(document).ready(function () {
131+
// Handle year select change
132+
handleYearSelectChange();
133+
134+
let toastNotification = new bootstrap.Toast(document.getElementById('toast-notification'));
135+
136+
//Handle preferences
137+
$('#addPreferencesButton').click(function () {
138+
$('#staticPreferencesTable').hide();
139+
$('#editablePreferencesTable').show();
140+
$('#addPreferencesButton').hide();
141+
$('#savePreferencesButton').show();
142+
$('#cancelEditButton').show();
143+
$('#addRowButton').show();
144+
});
145+
146+
$('#cancelEditButton').click(function () {
147+
$('#editablePreferencesTable').hide();
148+
$('#staticPreferencesTable').show();
149+
$('#addPreferencesButton').show();
150+
$('#savePreferencesButton').hide();
151+
$('#cancelEditButton').hide();
152+
$('#addRowButton').hide();
153+
});
154+
155+
$('#addRowButton').click(function () {
156+
const newRow = $('#template-row').clone().removeAttr('id').removeAttr('style');
157+
$('#editablePreferencesTable tbody').append(newRow);
158+
159+
$("#editablePreferencesTable tbody").sortable({
160+
items: 'tr',
161+
handle: '.move-icon',
162+
axis: 'y',
163+
cursor: 'move'
164+
});
165+
});
166+
167+
// Event listener pour le bouton de suppression
168+
$(document).on('click', '.delete-icon', function () {
169+
$(this).closest('tr').remove();
170+
});
171+
172+
$('#savePreferencesButton').click(function () {
173+
const preferences = [];
174+
!$('#editablePreferencesTable tbody tr').not('#template-row').each(function () {
175+
const courseId = $(this).find('select.course-select').val();
176+
177+
if (courseId) {
178+
preferences.push({course_id: courseId});
179+
}
180+
});
181+
182+
const data = {
183+
preferences: preferences,
184+
};
185+
186+
$.ajax({
187+
type: 'POST',
188+
url: "{{ url_for('course_preference.save_preference') }}",
189+
contentType: 'application/json',
190+
data: JSON.stringify(data),
191+
success: function (response) {
192+
alert('Preferences updated successfully.');
193+
location.reload(); // Refresh the page to show the updated preferences
194+
},
195+
error: function (error) {
196+
const errorMessage = error.responseJSON.error || 'Error updating the preferences.'
197+
updateToastContent(errorMessage);
198+
toastNotification.show();
199+
}
200+
});
201+
});
202+
203+
$("#editablePreferencesTable tbody").sortable({
204+
items: 'tr',
205+
handle: '.move-icon',
206+
axis: 'y',
207+
cursor: 'move'
208+
});
209+
});
210+
</script>
211+
{% endblock %}

templates/toast_notification.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div class="toast" id="toast-notification" role="alert" aria-live="assertive" aria-atomic="true">
2+
<div class="toast-header">
3+
<strong class="me-auto">Notification</strong>
4+
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
5+
</div>
6+
<div class="toast-body">
7+
</div>
8+
</div>

0 commit comments

Comments
 (0)