diff --git a/assignment.py b/assignment.py index 3a0c48b..bd407cb 100644 --- a/assignment.py +++ b/assignment.py @@ -1,3 +1,4 @@ +from sqlalchemy import func from decorators import login_required, check_access_level from db import db, User, Course, PreferenceAssignment, Teacher, Researcher, Organization, \ ResearcherSupervisor, Role, AssignmentDraft, AssignmentPublished @@ -11,6 +12,7 @@ @assignment_bp.route('/assignments', methods=['GET']) @login_required +@check_access_level(Role.ADMIN) def assignments(): return render_template('assignment.html') @@ -72,6 +74,7 @@ def load_data(): @assignment_bp.route('/publish_assignments', methods=['POST']) @login_required +@check_access_level(Role.ADMIN) def publish_assignments(): data = request.get_json() if not data: @@ -130,3 +133,27 @@ def publish_assignments(): except Exception as e: db.session.rollback() return jsonify({"error": f"Failed to publish assignments: {str(e)}"}), 500 + + +def count_course_assignments(): + # Counts the number of times each user has taught each course + current_year = get_current_year() + assignment_counts = (db.session.query( + AssignmentDraft.researcher_id, + AssignmentDraft.course_id, + func.count(AssignmentDraft.course_id).label('count') + ).filter(AssignmentDraft.course_year < current_year).group_by( + AssignmentDraft.researcher_id, + AssignmentDraft.course_id + ).distinct().all()) + + return assignment_counts + + +@assignment_bp.route('/course_assignments_count', methods=['GET']) +@login_required +@check_access_level(Role.ADMIN) +def get_course_assignments_count(): + results = count_course_assignments() + return jsonify( + results=[{'user_id': user_id, 'course_id': course_id, 'count': count} for user_id, course_id, count in results]) diff --git a/course.py b/course.py index cac8d77..e09e83e 100644 --- a/course.py +++ b/course.py @@ -117,7 +117,7 @@ def add_course(): @check_access_level(Role.ADMIN) def courses(year): courses = db.session.query(Course).filter_by(year=year).all() - return render_template('courses.html', courses=courses, current_year=year) + return render_template('courses.html', courses=courses, year=year) @course_bp.route('/search_teachers') diff --git a/db.py b/db.py index bdff5ec..d5ad1c7 100644 --- a/db.py +++ b/db.py @@ -109,6 +109,7 @@ class Teacher(db.Model): class PreferenceAssignment(db.Model): __tablename__ = 'preference_assignment' + rank = db.Column(db.Integer, nullable=False) id = db.Column(db.Integer, primary_key=True) rank = db.Column(db.Integer, nullable=False) course_id = db.Column(db.Integer, nullable=False) diff --git a/static/scripts/assignment_table.js b/static/scripts/assignment_table.js index f89fdc5..2d2b8ba 100644 --- a/static/scripts/assignment_table.js +++ b/static/scripts/assignment_table.js @@ -184,6 +184,15 @@ fetch('/assignment/load_data') } } + function getCountCourseAssignment() { + return fetch('/assignment/course_assignments_count') + .then(response => response.json()) + .then(data => { + return data.results; + }) + .catch(error => console.log(error)) + } + const table = new Handsontable(document.getElementById("handsontable"), { data: data, fixedColumnsLeft: lenFixedHeaders, @@ -277,16 +286,34 @@ fetch('/assignment/load_data') }); } }, - afterRenderer: function (TD, row, col, prop, value, cellProperties) { + afterRenderer: async function (TD, row, col, prop, value, cellProperties) { if ((col >= lenFixedHeaders && row >= lenFixedRowsText) && (row % 2 === 1) && (value !== '')) { TD.style.fontWeight = 'bold'; // Bold text TD.style.textAlign = 'left'; // Left alignment } - //Style first col if needed - if (col === 0 && row < lenFixedRowsText) { - TD.style.fontWeight = 'bold'; - TD.style.textAlign = 'left'; + + if (row >= lenFixedRowsText && col >= lenFixedHeaders && (row % 2 === 0)) { + const assignmentCount = await getCountCourseAssignment(); + + const user_id = this.getDataAtRowProp(row, 'researchers.id'); // Retrieves user ID + const course_id = this.getDataAtCol(col)[0]; // Retrieves the course ID + + const assignment = assignmentCount.find(item => item.user_id === user_id && item.course_id === course_id); + + if (assignment && value !== '' && value !== null) { + // Colouring based on the number of assignments + const count = assignment.count; + TD.style.color = 'black'; // to better see the preferences when the cell is coloured + if (count === 1) { + TD.style.backgroundColor = '#A0A7D5'; + } else if (count === 2) { + TD.style.backgroundColor = '#555DB0'; + } else if (count >= 3) { + TD.style.backgroundColor = '#1C2793'; + } + } } + //(row%2) === 1 to avoid empty lines if (row >= lenFixedRowsText && (row % 2) === 0 && col < lenFixedHeaders) { const rowValue = this.getDataAtRow(row); diff --git a/templates/assignment.html b/templates/assignment.html index ba2f264..015ff1d 100644 --- a/templates/assignment.html +++ b/templates/assignment.html @@ -51,11 +51,11 @@
Course Header Colors :
+
+
Cell Colors:
+ +
@@ -85,8 +105,7 @@

diff --git a/templates/courses.html b/templates/courses.html index f574819..0e8b65a 100644 --- a/templates/courses.html +++ b/templates/courses.html @@ -52,7 +52,7 @@

Courses

- + {{ course.code }} - {{ course.title }} diff --git a/templates/layout.html b/templates/layout.html index 2e992c2..5b0fff8 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -116,6 +116,19 @@ + {% endif %} {% block additionalnav %}{% endblock %}