diff --git a/app/constants.py b/app/constants.py
index ee5021cb652997635393f7707fd24fb623821a6d..4c37a3fe9e60a8de3a9b399016eaf02cb78feb3a 100644
--- a/app/constants.py
+++ b/app/constants.py
@@ -2,6 +2,3 @@ from datetime import datetime
 
 STUDENT = "student"
 STAFF = "staff"
-
-DEADLINE_FOR_STUDENT_CHANGES = datetime(2023, 2, 9, 19, 0)
-DEADLINE_FOR_STAFF_CHANGES = datetime(2025, 2, 9, 19, 0)
diff --git a/app/forms/project.py b/app/forms/project.py
index 9cddae3db78e6d92802b29f088b2798cb9a28763..bd952133484395382b613b185a2cd7f8f5ddc4cc 100644
--- a/app/forms/project.py
+++ b/app/forms/project.py
@@ -8,15 +8,26 @@ from wtforms import (
     TextAreaField,
     validators,
 )
-from wtforms.validators import DataRequired, ValidationError
+from wtforms.validators import DataRequired, StopValidation, ValidationError
+
+
+def empty_to_none(form, field):
+    if field.data == "":
+        field.data = None
+    else:
+        raise StopValidation()
 
 
 class ProjectForm(FlaskForm):
     title = StringField("Title", validators=[DataRequired()])
     description = TextAreaField("Description", validators=[DataRequired()])
-    background_skills = TextAreaField("Background skills")
+    background_skills = TextAreaField(
+        "Background skills", validators=[empty_to_none, validators.Optional()]
+    )
     is_student_proposal = BooleanField("Student Proposal", default=False)
-    on_behalf = StringField("from", default=None)
+    on_behalf = StringField(
+        "from", default=None, validators=[empty_to_none, validators.Optional()]
+    )
     category = SelectField("Category", coerce=str)
     meeting_modes = [("", "N/A"), ("remote", "Remote"), ("in-person", "In person")]
     meeting_mode = SelectField(
diff --git a/app/messages/__init__.py b/app/messages/__init__.py
index 62f52746bc679d9392b986f8351deb00102cc85a..56fa876982b21f370603b262826451a763c03ec0 100644
--- a/app/messages/__init__.py
+++ b/app/messages/__init__.py
@@ -6,6 +6,8 @@ from .message_builders import (
     login_unsuccessful_error,
     project_not_found,
     shortlist_not_found,
+    successful_staff_ranking_update,
+    successful_student_ranking_update,
 )
 
 #########################################################################
@@ -22,3 +24,6 @@ INVALID_CATEGORY = invalid_category()
 
 DEADLINE_EXPIRED_FOR_STUDENTS = deadline_expired_for_students()
 DEADLINE_EXPIRED_FOR_STAFF = deadline_expired_for_staff()
+
+SUCCESSFUL_STAFF_RANKING_UPDATE = successful_staff_ranking_update()
+SUCCESSFUL_STUDENT_RANKING_UPDATE = successful_student_ranking_update()
diff --git a/app/messages/message_builders.py b/app/messages/message_builders.py
index 8caa642939f374ed1c4629459b753ae6880113a2..5caa94b3781e85d63570f1ca0bbea161359b7153 100644
--- a/app/messages/message_builders.py
+++ b/app/messages/message_builders.py
@@ -1,6 +1,6 @@
 from markupsafe import Markup
 
-from .styles import ERROR, INFO
+from .styles import ERROR, INFO, SUCCESS
 
 
 class Message:
@@ -80,7 +80,7 @@ def deadline_expired_for_students():
     return MessageEncoder.encode(
         Message(
             header="<h3><strong>Deadline expired</strong></h3>",
-            body="<p>The deadline to make changes has now expired, and you cannot make changes to your shortlisting and ranking. If you have questions, please contact Lorenzo Picinali.</p>",
+            body="<p>The deadline to make changes has now expired, and you cannot make changes to your shortlisting and ranking. If you have questions, please contact Andrea Callia D'Iddio.</p>",
             style=ERROR,
         )
     )
@@ -94,3 +94,23 @@ def deadline_expired_for_staff():
             style=ERROR,
         )
     )
+
+
+def successful_staff_ranking_update():
+    return MessageEncoder.encode(
+        Message(
+            header="<h3><strong>Ranking updated</strong></h3>",
+            body="<p>The ranking has been updated.</p>",
+            style=SUCCESS,
+        )
+    )
+
+
+def successful_student_ranking_update():
+    return MessageEncoder.encode(
+        Message(
+            header="<h3><strong>Ranking updated</strong></h3>",
+            body="<p>The ranking has been updated.</p>",
+            style=SUCCESS,
+        )
+    )
diff --git a/app/models/category.py b/app/models/category.py
index d5262bbd3d0d74a87533207065f89e96259011cb..a741776e66de1271fed6ff9f725cb5999e7b78ef 100644
--- a/app/models/category.py
+++ b/app/models/category.py
@@ -1,3 +1,5 @@
+from datetime import datetime
+
 from ..database import db
 
 
@@ -10,3 +12,11 @@ class Category(db.Model):
     @property
     def name(self) -> str:
         return self.title if self.title else self.code
+
+    @property
+    def is_deadline_expired_for_staff(self):
+        return datetime.utcnow() > self.deadline_for_staff_change
+
+    @property
+    def is_deadline_expired_for_students(self):
+        return datetime.utcnow() > self.deadline_for_student_changes
diff --git a/app/templates/pages/staff/project-view.html b/app/templates/pages/staff/project-view.html
index 15d307382441046d4d5a81d79f84705f38b47d74..51969f8ece6db55cd25a20cd3f9467cf76278bf3 100644
--- a/app/templates/pages/staff/project-view.html
+++ b/app/templates/pages/staff/project-view.html
@@ -22,7 +22,7 @@
             {% if project.background_skills %}
                 {{ project_details_section('Background skills', project.background_skills) }}
             {% endif %}
-            {% if project.is_remote %}
+            {% if project.is_remote != None %}
                 {{ project_details_section('Meeting mode', "Remote" if project.is_remote else "In person") }}
             {% endif %}
             {% if project.proposed_start_date %}
@@ -31,10 +31,10 @@
             {% if project.duration_in_weeks %}
                 {{ project_details_section('Duration in weeks', project.duration_in_weeks) }}
             {% endif %}
-            {% if project.is_part_time %}
+            {% if project.is_part_time != None %}
                 {{ project_details_section('Time commitment', "Part-time" if project.is_part_time else "Full-time") }}
             {% endif %}
-            {% if project.is_lab_based %}
+            {% if project.is_lab_based != None %}
                 {{ project_details_section('Lab usage', "Lab-based" if project.is_lab_based else "Not lab-based") }}
             {% endif %}
         </div>
diff --git a/app/templates/pages/staff/shortlisted-projects.html b/app/templates/pages/staff/shortlisted-projects.html
index 4e270b5e00b9eefe91ea6c69f7ac20aa31a65340..8c1c6dbec267d77d9c3f9b7327bfdbbce116be9b 100644
--- a/app/templates/pages/staff/shortlisted-projects.html
+++ b/app/templates/pages/staff/shortlisted-projects.html
@@ -9,22 +9,27 @@
                 <h1 class="w3-center w3-text-{{ theme_colour }}">Who wants to do a project with you</h1>
                 {% if projects %}
                     <ul class="w3-ul" id="projects">
-                        {% for shortlisting in projects %}
-                            <li class="w3-display-container" data-id="{{ shortlisting.id }}">
-                            <span class="w3-bar-item sort-list-handle">
-                                <i class="fa-solid fa-bars"></i>&ensp;
-                            </span>
-                                <span>
-                                {{ shortlisting.project.title }} - {{ full_names[shortlisting.id] }}
-                            </span>
-                            </li>
-                        {% endfor %}
+                    {% for category in categories %}
+                        {% if not category.is_deadline_expired_for_staff %}
+                            <h2 class="w3-center w3-text-{{ theme_colour }}">{{ category.title }}</h2>
+                            {% for shortlisting in projects[category.code] %}
+                                <li class="w3-display-container" data-group="{{ category.code }}" data-id="{{ shortlisting.id }}" data-handle=".sort-list-handle">
+                                    <span class="w3-bar-item sort-list-handle">
+                                        <i class="fa-solid fa-bars"></i>&ensp;
+                                    </span>
+                                    <span>
+                                        {{ shortlisting.project.title }} - {{ full_names[shortlisting.id] }}
+                                    </span>
+                                </li>
+                            {% endfor %}
+                        {% endif %}
+                    {% endfor %}
                     </ul>
-                    </section>
                     <button id="save-button" type="button" class="w3-btn w3-{{ theme_colour }} w3-right">Save</button>
                 {% else %}
                     {{ utils.placeholder_text("No projects to show yet.") }}
                 {% endif %}
+            </section>
         </div>
     </div>
 
@@ -37,6 +42,7 @@
         const sortableProjectList = Sortable.create(projectList, {
             handle: ".sort-list-handle",
             ghostClass: "ghost",
+            onMove: function(evt) {return (evt.dragged.getAttribute("data-group") === evt.related.getAttribute("data-group")) ;}
         })
         const saveButton = document.getElementById("save-button")
         saveButton.addEventListener("click", async () => {
diff --git a/app/templates/pages/student/shortlisted-projects.html b/app/templates/pages/student/shortlisted-projects.html
index d0e90249a0cd0706173b5699a79cd5c98f83c6be..2e207ccfccaee1f0bdad9a92ee81bbf3b1275fc3 100644
--- a/app/templates/pages/student/shortlisted-projects.html
+++ b/app/templates/pages/student/shortlisted-projects.html
@@ -9,16 +9,21 @@
                 <h1 class="w3-center w3-text-blue">Your shortlisted projects</h1>
                 {% if projects %}
                     <ul class="w3-ul" id="projects">
-                        {% for project in projects %}
-                            <li class="w3-display-container" data-id="{{ project.id }}">
-                            <span class="w3-bar-item sort-list-handle">
-                                <i class="fa-solid fa-bars"></i>&ensp;
-                            </span>
-                                <span>
-                                {{ project.title }} - {{ full_names[project.id] }}
-                            </span>
-                            </li>
-                        {% endfor %}
+                    {% for category in categories %}
+                        {% if not category.is_deadline_expired_for_students %}
+                            <h2 class="w3-center w3-text-{{ theme_colour }}">{{ category.title }}</h2>
+                            {% for project in projects[category.code] %}
+                                <li class="w3-display-container" data-group="{{ category.code }}" data-id="{{ project.id }}" data-handle=".sort-list-handle">
+                                    <span class="w3-bar-item sort-list-handle">
+                                        <i class="fa-solid fa-bars"></i>&ensp;
+                                    </span>
+                                    <span>
+                                        {{ project.title }} - {{ full_names[project.id] }}
+                                    </span>
+                                </li>
+                            {% endfor %}
+                        {% endif %}
+                    {% endfor %}
                     </ul>
                     </section>
                     <button id="save-button" type="button" class="w3-btn w3-{{ theme_colour }} w3-right">Save</button>
@@ -37,6 +42,7 @@
         const sortableProjectList = Sortable.create(projectList, {
             handle: ".sort-list-handle",
             ghostClass: "ghost",
+            onMove: function(evt) {return (evt.dragged.getAttribute("data-group") === evt.related.getAttribute("data-group")) ;}
         })
         const saveButton = document.getElementById("save-button")
         saveButton.addEventListener("click", async () => {
diff --git a/app/utils/decorators.py b/app/utils/decorators.py
index 9940ece1ba68eb9169a37bb5f8ea4b5d84313275..787852c65eed3f671184b1fc13370391131a838d 100644
--- a/app/utils/decorators.py
+++ b/app/utils/decorators.py
@@ -1,17 +1,10 @@
-from datetime import datetime
 from functools import wraps
 
-from flask import flash, url_for
+from flask import url_for
 from flask_login import current_user
 from werkzeug.utils import redirect
 
-from app import messages
-from app.constants import (
-    DEADLINE_FOR_STAFF_CHANGES,
-    DEADLINE_FOR_STUDENT_CHANGES,
-    STAFF,
-    STUDENT,
-)
+from app.constants import STAFF, STUDENT
 
 
 def staff_only(func):
@@ -32,25 +25,3 @@ def students_only(func):
         return redirect(url_for(f"{current_user.role}.projects"))
 
     return inner
-
-
-def only_before_deadline_for_students(func):
-    @wraps(func)
-    def inner(*args, **kwargs):
-        if datetime.utcnow() <= DEADLINE_FOR_STUDENT_CHANGES:
-            return func(*args, **kwargs)
-        flash(messages.DEADLINE_EXPIRED_FOR_STUDENTS)
-        return redirect(url_for(f"{current_user.role}.projects"))
-
-    return inner
-
-
-def only_before_deadline_for_staff(func):
-    @wraps(func)
-    def inner(*args, **kwargs):
-        if datetime.utcnow() <= DEADLINE_FOR_STAFF_CHANGES:
-            return func(*args, **kwargs)
-        flash(messages.DEADLINE_EXPIRED_FOR_STAFF)
-        return redirect(url_for(f"{current_user.role}.projects"))
-
-    return inner
diff --git a/app/views/staff.py b/app/views/staff.py
index 96b7a8a6ebc9bb7ef08ad5217a772b12d30c7019..b2c4b84dc51234049e434a52bd822d1e0db6e8ec 100644
--- a/app/views/staff.py
+++ b/app/views/staff.py
@@ -5,14 +5,13 @@ from flask_login import current_user, login_required
 from sqlalchemy import and_
 
 from app import messages
-from app.constants import DEADLINE_FOR_STAFF_CHANGES
 from app.database import db
 from app.forms.project import ProjectForm
 from app.models.category import Category
 from app.models.person import Person
 from app.models.project import Project
 from app.models.shortlist import Shortlisting
-from app.utils.decorators import only_before_deadline_for_staff, staff_only
+from app.utils.decorators import staff_only
 
 bp = Blueprint("staff", __name__, url_prefix="/staff")
 
@@ -47,7 +46,6 @@ def projects():
     deadlines: dict[str, datetime] = {
         c.code: c.deadline_for_staff_change for c in categories
     }
-    allow_edit = True if datetime.utcnow() <= DEADLINE_FOR_STAFF_CHANGES else False
     own_projects: list[Project] = (
         Project.query.filter_by(proposer=current_user.username)
         .filter(Project.category.in_(category_codes))
@@ -72,9 +70,8 @@ def projects():
     )
 
 
-def is_deadline_expired_for_staff(category_code):
-    category = Category.query.get(category_code)
-    return datetime.utcnow() > category.deadline_for_staff_change
+def equals_or_none(first, second):
+    return first == second if first is not None else None
 
 
 @bp.route("/projects/create", methods=["GET", "POST"])
@@ -87,7 +84,8 @@ def create_project():
     categories: list[Category] = Category.query.filter(
         Category.code.in_(category_codes)
     ).all()
-    form = ProjectForm()
+    project = Project(proposer=current_user.username)
+    form = ProjectForm(obj=project)
     form.category.choices = [("", "Choose an option")] + [
         (c.code, c.name) for c in categories
     ]
@@ -95,31 +93,17 @@ def create_project():
         project = Project(
             title=form.title.data,
             description=form.description.data,
-            background_skills=form.background_skills.data
-            if form.background_skills.data not in [None, ""]
-            else None,
+            background_skills=form.background_skills.data,
             proposer=current_user.username,
-            on_behalf=form.on_behalf.data if form.is_student_proposal.data else None,
+            on_behalf=form.on_behalf.data,
             category=form.category.data,
-            is_remote=(
-                form.meeting_mode.data == "remote"
-                if form.meeting_mode.data is not None
-                else None
-            ),
-            is_part_time=(
-                form.time_commitment.data == "part-time"
-                if form.time_commitment.data is not None
-                else None
-            ),
-            is_lab_based=(
-                form.lab_usage.data == "lab-based"
-                if form.lab_usage.data is not None
-                else None
-            ),
+            is_remote=equals_or_none(form.meeting_mode.data, "remote"),
+            is_part_time=equals_or_none(form.time_commitment.data, "part-time"),
+            is_lab_based=equals_or_none(form.lab_usage.data, "lab-based"),
             proposed_start_date=form.proposed_start_date.data,
             duration_in_weeks=form.duration_in_weeks.data,
         )
-        if is_deadline_expired_for_staff(form.category.data):
+        if Category.query.get(form.category.data).is_deadline_expired_for_staff:
             flash(messages.DEADLINE_EXPIRED_FOR_STAFF)
         else:
             db.session.add(project)
@@ -143,7 +127,9 @@ def delete_project(project_id):
         Person.query.filter_by(username=current_user.username).first().categories
     )
     project = Project.query.get(project_id)
-    if (project is not None) and is_deadline_expired_for_staff(project.category):
+    if (project is not None) and Category.query.get(
+        project.category
+    ).is_deadline_expired_for_staff:
         flash(messages.DEADLINE_EXPIRED_FOR_STAFF)
     elif (
         (project is not None)
@@ -160,12 +146,12 @@ def delete_project(project_id):
 @bp.route("/projects/<project_id>/edit", methods=["GET", "POST"])
 @login_required
 @staff_only
-@only_before_deadline_for_staff
 def edit_project(project_id):
     # show_box is a boolean used to decide if we show the text box for student full name. by default this is not shown
     show_box = False
     person = None
     can_edit = True
+    deadline_expired = False
     category_codes: list[str] = (
         Person.query.filter_by(username=current_user.username).first().categories
     )
@@ -177,6 +163,9 @@ def edit_project(project_id):
         can_edit = False
     elif project.category not in category_codes:
         can_edit = False
+    elif Category.query.get(project.category).is_deadline_expired_for_staff:
+        can_edit = False
+        deadline_expired = True
     if can_edit:
         form = ProjectForm()
         form.category.choices = [(c.code, c.name) for c in categories]
@@ -186,18 +175,44 @@ def edit_project(project_id):
         if form.validate_on_submit():
             project.title = form.title.data
             project.description = form.description.data
+            project.background_skills = form.background_skills.data
             project.on_behalf = (
                 form.on_behalf.data if form.is_student_proposal.data else None
             )
             project.category = form.category.data
+            project.is_remote = equals_or_none(form.meeting_mode.data, "remote")
+            project.is_part_time = equals_or_none(
+                form.time_commitment.data, "part-time"
+            )
+            project.is_lab_based = equals_or_none(form.lab_usage.data, "lab-based")
+            project.proposed_start_date = form.proposed_start_date.data
+            project.duration_in_weeks = form.duration_in_weeks.data
             db.session.commit()
             if project.on_behalf and on_behalf_changed:
                 shortlist_proposer(project)
             return redirect(url_for("staff.projects"))
         form = ProjectForm(obj=project)
-        form.meeting_mode.data = "remote" if project.is_remote is True else ""
-        form.time_commitment.data = "part-time" if project.is_part_time is True else ""
-        form.lab_usage.data = "lab-based" if project.is_lab_based is True else ""
+        form.meeting_mode.data = (
+            "remote"
+            if project.is_remote is True
+            else "in-person"
+            if project.is_remote is False
+            else ""
+        )
+        form.time_commitment.data = (
+            "part-time"
+            if project.is_part_time is True
+            else "full-time"
+            if project.is_part_time is False
+            else ""
+        )
+        form.lab_usage.data = (
+            "lab-based"
+            if project.is_lab_based is True
+            else "non-lab-based"
+            if project.is_lab_based is False
+            else ""
+        )
         form.category.choices = [(c.code, c.name) for c in categories]
 
         if project.on_behalf is not None:
@@ -212,7 +227,10 @@ def edit_project(project_id):
             show_box=show_box,
             person=person,
         )
-    flash(messages.PROJECT_NOT_FOUND)
+    if deadline_expired:
+        flash(messages.DEADLINE_EXPIRED_FOR_STAFF)
+    else:
+        flash(messages.PROJECT_NOT_FOUND)
     return redirect(url_for("staff.projects"))
 
 
@@ -245,7 +263,15 @@ def projects_ranking():
         .all()
     )
 
+    category_codes: list[str] = (
+        Person.query.filter_by(username=current_user.username).first().categories
+    )
+    categories: list[Category] = Category.query.filter(
+        Category.code.in_(category_codes)
+    ).all()
+
     full_names = {}
+    projects_by_category = {c: [] for c in category_codes}
 
     for shortlisting in own_projects:
         person = Person.query.filter(
@@ -256,9 +282,13 @@ def projects_ranking():
             person.full_name if person.full_name else person.username
         )
 
+        if shortlisting.project.category in projects_by_category:
+            projects_by_category[shortlisting.project.category].append(shortlisting)
+
     return render_template(
         "pages/staff/shortlisted-projects.html",
-        projects=own_projects,
+        projects=projects_by_category,
+        categories=categories,
         full_names=full_names,
     )
 
@@ -266,7 +296,6 @@ def projects_ranking():
 @bp.route("/projects/rankings", methods=["PUT"])
 @login_required
 @staff_only
-@only_before_deadline_for_staff
 def update_ranking():
     shortlisting_ids = request.json
     current_shortlist: list[Shortlisting] = Shortlisting.query.join(Project).filter(
@@ -275,7 +304,22 @@ def update_ranking():
             Project.proposer == current_user.username,
         )
     )
+    deadline_errors = False
     for shortlisting in current_shortlist:
-        shortlisting.staff_ranking = shortlisting_ids.index(shortlisting.id) + 1
+        if Category.query.get(
+            Project.query.get(shortlisting.project_id).category
+        ).is_deadline_expired_for_staff:
+            if (
+                shortlisting.staff_ranking
+                != shortlisting_ids.index(shortlisting.id) + 1
+            ):
+                deadline_errors = True
+        else:
+            shortlisting.staff_ranking = shortlisting_ids.index(shortlisting.id) + 1
+    if deadline_errors:
+        flash(messages.DEADLINE_EXPIRED_FOR_STAFF)
+        return redirect(url_for(f"{current_user.role}.projects"))
+    else:
+        flash(messages.SUCCESSFUL_STAFF_RANKING_UPDATE)
     db.session.commit()
     return "", 204
diff --git a/app/views/student.py b/app/views/student.py
index a89a2a2aa31bdf45ebe9828b6ad21feea1e3ca1f..8588be3f65e8e7532ae5e3ac4a19fa7bfb9beda2 100644
--- a/app/views/student.py
+++ b/app/views/student.py
@@ -4,10 +4,11 @@ from sqlalchemy import or_
 
 from app import messages
 from app.database import db
+from app.models.category import Category
 from app.models.person import Person
 from app.models.project import Project
 from app.models.shortlist import Shortlisting
-from app.utils.decorators import only_before_deadline_for_students, students_only
+from app.utils.decorators import students_only
 
 bp = Blueprint("student", __name__, url_prefix="/student")
 
@@ -47,7 +48,15 @@ def projects_ranking():
         .all()
     )
 
+    category_codes: list[str] = (
+        Person.query.filter_by(username=current_user.username).first().categories
+    )
+    categories: list[Category] = Category.query.filter(
+        Category.code.in_(category_codes)
+    ).all()
+
     full_names = {}
+    projects_by_category = {c: [] for c in category_codes}
 
     for shortlisting in shortlisted_projects:
         username = (
@@ -64,9 +73,13 @@ def projects_ranking():
             person.full_name if person.full_name else person.username
         )
 
+        if shortlisting.category in projects_by_category:
+            projects_by_category[shortlisting.category].append(shortlisting)
+
     return render_template(
         "pages/student/shortlisted-projects.html",
-        projects=shortlisted_projects,
+        projects=projects_by_category,
+        categories=categories,
         full_names=full_names,
     )
 
@@ -74,14 +87,25 @@ def projects_ranking():
 @bp.route("/projects/rankings", methods=["PUT"])
 @login_required
 @students_only
-@only_before_deadline_for_students
 def update_ranking():
     project_ids = request.json
     current_shortlist: list[Shortlisting] = Shortlisting.query.filter(
         Shortlisting.project_id.in_(project_ids)
     ).filter_by(student=current_user.username)
+    deadline_errors = False
     for shortlisting in current_shortlist:
-        shortlisting.ranking = project_ids.index(shortlisting.project_id) + 1
+        if Category.query.get(
+            Project.query.get(shortlisting.project_id).category
+        ).is_deadline_expired_for_students:
+            if shortlisting.ranking != project_ids.index(shortlisting.project_id) + 1:
+                deadline_errors = True
+        else:
+            shortlisting.ranking = project_ids.index(shortlisting.project_id) + 1
+    if deadline_errors:
+        flash(messages.DEADLINE_EXPIRED_FOR_STUDENTS)
+        return redirect(url_for(f"{current_user.role}.projects"))
+    else:
+        flash(messages.SUCCESSFUL_STUDENT_RANKING_UPDATE)
     db.session.commit()
     return "", 204
 
@@ -116,44 +140,51 @@ def view_project(project_id):
 @bp.route("/projects/<project_id>/shortlist")
 @login_required
 @students_only
-@only_before_deadline_for_students
 def shortlist_project(project_id):
     can_shortlist = True
     category_codes: list[str] = (
         Person.query.filter_by(username=current_user.username).first().categories
     )
     project = Project.query.get(project_id)
-    if not project:
-        can_shortlist = False
-    elif project.category not in category_codes:
-        can_shortlist = False
-    if can_shortlist:
-        shortlisting = Shortlisting(
-            student=current_user.username, project_id=project_id
-        )
-        db.session.add(shortlisting)
-        db.session.commit()
+    if (project is not None) and Category.query.get(
+        project.category
+    ).is_deadline_expired_for_students:
+        flash(messages.DEADLINE_EXPIRED_FOR_STUDENTS)
     else:
-        flash(messages.PROJECT_NOT_FOUND)
+        if not project:
+            can_shortlist = False
+        elif project.category not in category_codes:
+            can_shortlist = False
+        if can_shortlist:
+            shortlisting = Shortlisting(
+                student=current_user.username, project_id=project_id
+            )
+            db.session.add(shortlisting)
+            db.session.commit()
+        else:
+            flash(messages.PROJECT_NOT_FOUND)
     return redirect(url_for("student.projects"))
 
 
 @bp.route("/projects/<project_id>/unshortlist")
 @login_required
 @students_only
-@only_before_deadline_for_students
 def unshortlist_project(project_id):
-    if Project.query.get(project_id):
-        shortlist: Shortlisting = (
-            Shortlisting.query.filter(Shortlisting.project_id == project_id)
-            .filter_by(student=current_user.username)
-            .first()
-        )
-        if shortlist:
-            db.session.delete(shortlist)
-            db.session.commit()
+    project = Project.query.get(project_id)
+    if project:
+        if Category.query.get(project.category).is_deadline_expired_for_students:
+            flash(messages.DEADLINE_EXPIRED_FOR_STUDENTS)
         else:
-            flash(messages.SHORTLIST_NOT_FOUND)
+            shortlist: Shortlisting = (
+                Shortlisting.query.filter(Shortlisting.project_id == project_id)
+                .filter_by(student=current_user.username)
+                .first()
+            )
+            if shortlist:
+                db.session.delete(shortlist)
+                db.session.commit()
+            else:
+                flash(messages.SHORTLIST_NOT_FOUND)
     else:
         flash(messages.PROJECT_NOT_FOUND)
     return redirect(url_for("student.projects"))