Skip to content

refactor: Replace status string comparisons in templates with enum predicates #106

Description

@ebouchut

Problem

Several Thymeleaf templates compare an enum's name() to a hard-coded string literal to decide which lifecycle actions to render, for example:

<form th:if="${course.status.name() == 'ARCHIVED'}" ...>

Raised in a review remark on PR #104: https://github.com/ebouchut/learn-dev/pull/104/changes#r3580267912

This pattern is fragile and stringly-typed:

  • Renaming an enum constant breaks the templates at runtime (the condition silently becomes false), not at compile time.
  • The rule "an enrollment can be dropped" (ENROLLED || IN_PROGRESS) is duplicated between a template and EnrollmentService.drop(), so the two can drift apart.

The pattern appears 14 times across 4 templates:

Template Occurrences Enum
admin/courses.html 4 PublicationStatus
instructor/course-form.html 6 PublicationStatus
instructor/students.html 2 EnrollmentStatus
courses/detail.html 2 both

The Java code is not affected (it already compares enum constants type-safely).

Suggested fix

Add boolean predicates on the enums (rather than accessors like course.isArchived() on each entity, which would need the same three delegators duplicated on Course and Lesson):

  • PublicationStatus: isDraft(), isPublished(), isArchived() (each a one-line this == ...). Serves both Course and Lesson from a single definition.
  • EnrollmentStatus: isDropped() and isDroppable() (this == ENROLLED || this == IN_PROGRESS, the drop transition rule from the lifecycle diagrams in CONTRIBUTING.md). Note these two are not complements: COMPLETED is neither.

Thymeleaf then reads them as properties, with no string literal and no T(...) type expression:

<form th:if="${course.status.archived}" ...>
<form th:if="${enrollment.status.droppable}" ...>

Precedent in the codebase: PasswordResetToken.isUsable(now) already models a domain predicate as a method.

Scope

  1. Add the predicates to course/entity/PublicationStatus.java and course/entity/EnrollmentStatus.java.
  2. Mechanically replace the 14 template occurrences (the compound condition in instructor/students.html collapses to a single droppable check).
  3. Small Java consistency sweep: EnrollmentService.drop() uses isDroppable().
    The != DROPPED stream filters in CourseController and DashboardController use !isDropped(). The requireStatus(...) varargs guards stay as they are.

Verification

  • make test stays green (the existing flow tests exercise every affected template branch: publish/archive/restore buttons, roster Remove visibility, Register/Quit on the course page).
  • grep -rn "status.name() ==\|status.name() !=" src/main/resources/templates/ returns nothing.

Metadata

Metadata

Assignees

Projects

Status
Product Backlog

Relationships

None yet

Development

No branches or pull requests

Issue actions