CSC/ECE 517 Spring 2025 - E2526 Reimplement Teams and Participant hierarchies

From Expertiza_Wiki
Jump to navigation Jump to search

Introduction

This project reimplements the Team and Participant hierarchies within the new Expertiza system. It introduces cleaner, modular structures for Participant, AssignmentParticipant, and CourseParticipant. The redesign also addresses legacy code smells and shifts logic to follow SOLID principles, improving maintainability, testability, and extensibility.

Requirements

  • Reimplement Participant-related Classes: Fully reimplement the Participant, AssignmentParticipant, and CourseParticipant classes using clean object-oriented design, ensuring each class has a well-defined responsibility and follows SOLID principles.
  • Refactor the Team Hierarchy: Integrate the Team hierarchy refactoring from OSS Project 3, improving upon it by addressing feedback provided in Pull Request #2941 .
  • Address Code Smells and Design Flaws: Eliminate all SRP violations and code smells from the original Participant, AssignmentParticipant, and CourseParticipant implementations.
  • Write Comprehensive Tests: Implement thorough RSpec tests for all model behaviors, including edge cases.

Existing Issues

1. Participant Hierarchy Violations

The current implementations of participant.rb , assignment_participant.rb , and course_participant.rb contain multiple issues that must be addressed:

  • Refactor code to fully comply with the Single Responsibility Principle (SRP).
  • Eliminate code smells such as misplaced methods.
  • Write sufficient RSpec tests to verify correct behavior under various conditions.
  • Enhance inline documentation and comments to clearly explain:
    • The purpose of each method.
    • Justification for retaining or removing existing logic.
    • Any key design decisions made during the implementation.

2. Team Hierarchy Refactor

The existing team.rb , assignment_team.rb , course_team.rb , and mentored_team.rb classes require rework to align with the updated architecture:

  • Reimplement these classes using the clean design introduced in OSS Project 3.
  • Address key feedback from Pull Request #2941 , such as:
    • Rename methods like user? to more expressive terms like has_as_member? to improve clarity.
    • Remove or clearly justify any commented-out legacy code.
    • Refactor create_new_team() to better reflect intent (e.g., assign_team_to_topic) and clean up legacy logic based on outdated user-team assumptions.

Design / Proposed Solution

team.rb Reimplementation

In the new team.rb implementation, we renamed is_member? to has_as_member?. The original method name implied that the team was a member of the user, rather than the other way around. Additionally, we moved the add_participant() method from AssignmentTeam to Team to apply the Factory Method Pattern. This change allows both CourseTeam and AssignmentTeam to reuse the same logic for participant creation while deferring type-specific behavior (like selecting the correct Participant subclass) to the factory method. All of this was done based on the feedback from the instructor provided in Pull Request #2941 .

Below is a breakdown of each method that was changed/added in the revised Team class and its role:

has_as_member? Method

Description

This method checks whether a given user is a member of the team.

Changes Made

Renamed from is_member? to has_as_member? for clarity.

add_participant Method

Description

Adds a Participant to the team, given a user object. It first checks if a corresponding participant already exists, and if not, creates a new one using the appropriate subclass, either AssignmentParticipant or CourseParticipant.

Changes Made

Moved from AssignmentTeam to the parent Team class to promote reuse and apply the Factory Method Pattern.

assignment_team.rb Reimplementation

In the new assignment_team.rb implementation, we added the participant_class method to apply the Factory Method pattern, as used in the Team class's add_participant method. Additionally, we renamed link_user_and_topic to assign_team_to_topic to reflect the modern team-based signup model. These changes were made in response to the instructor’s feedback, as noted in Pull Request #2941 .

Below is a breakdown of each method that was changed/added in the revised AssignmentTeam class and its role:

participant_class Method

Description

This method implements the Factory Method Pattern by returning the class responsible for handling participants associated with an AssignmentTeam, which is AssignmentParticipant.

Changes Made

Introduced as part of the Factory Method refactor. It enables the shared Team methods (like add_participant) to dynamically resolve and instantiate the appropriate subclass of Participant (AssignmentParticipant in this case) based on the context of the team type (AssignmentTeam).

assign_team_to_topic Method

Description

This method assigns a team to a signup topic and links all its members to the corresponding team node.

Changes Made

Was changed from link_user_and_topic to assign_team_to_topic to reflect the modern team-based signup model. Previously, it accepted a user ID, which was a remnant from when users not teams were assigned to topics.

course_team.rb Reimplementation

In the new course_team.rb implementation, we decided to add a participant_class method to apply the Factory Method Pattern that is used in the Team class add_participant Method based on the feedback from the instructor provided in Pull Request #2941 .

Below is a breakdown of each method that was changed/added in the revised CourseTeam class and its role:

participant_class Method

Description

This method implements the Factory Method Pattern by returning the class responsible for handling participants associated with a CourseTeam, which is CourseParticipant.

Changes Made

Introduced as part of the Factory Method refactor. It enables the shared Team methods (like add_participant) to dynamically resolve and instantiate the appropriate subclass of Participant (CourseParticipant in this case) based on the context of the team type (CourseTeam).

mentored_team.rb Reimplementation

In the new mentored_team.rb implementation, we decided to remove the MentorManagement class and integrate its functionality directly into MentoredTeam and change add_member() to take participant instead of user and assignment id. This decision was made not only to improve cohesion and eliminate unnecessary indirection, but also to address structural feedback from the instructor provided in Pull Request #2941 .

Below is a breakdown of each method that was changed/added in the revised MentoredTeam class and its role:

add_member Method

Description

Adds a participant to the team using the superclass implementation and then automatically assigns a mentor to the team if the conditions are met (such as minimum team size and absence of an existing mentor).

Changes Made

Changed from add_member(user, assignment_id = nil) to add_member(participant), since the participant contains all this information.

import_team_members Method

Description

Takes a hash of team member names and iterates through them. For each valid name, it looks up the corresponding user, ensures they are not already on the team, finds their AssignmentParticipant, and adds them to the team via add_member. It also triggers mentor assignment as part of this process.

Changes Made

Changed the call inside it for add_member(user, assignment_id = nil) to add_member(participant).

assign_mentor Method

Description

A private method that encapsulates the full logic of mentor assignment. It checks several conditions (e.g., whether mentoring is enabled, team has a topic, mentor already exists, etc.). If all conditions are satisfied, it selects an available mentor using the select_mentor method and adds them to the team, followed by notification emails.

Changes Made

No functional changes were made; the method was simply moved from MentorManagement to MentoredTeam.

select_mentor Method

Description

A private method that implements the algorithm for choosing the most suitable mentor. It selects among participants marked as mentors for the given assignment and returns the one who is currently mentoring the fewest teams. Ties are automatically broken by Hash#sort_by. This ensures a balanced distribution of mentor assignments.

Changes Made

No functional changes were made; the method was simply moved from MentorManagement to MentoredTeam.

zip_mentors_with_team_count Method

Description

A private method that generates a mapping of mentor user_ids to the number of teams each is currently mentoring, used by the select_mentor method. It performs a grouped count on the TeamsUser table and returns a sorted list of mentors by workload.

Changes Made

No functional changes were made; the method was simply moved from MentorManagement to MentoredTeam.

mentors_for_assignment Method

Description

A private method that returns all Participant records for a given assignment where the participant has can_mentor: true. This filters potential mentor candidates from the larger participant pool and serves as the base query for mentor selection logic.

Changes Made

No functional changes were made; the method was simply moved from MentorManagement to MentoredTeam.

notify_team_of_mentor_assignment Method

Description

A private method that sends an email notification to all members of a team informing them that a mentor has been assigned. The message includes the mentor’s name and email, the assignment name, and a list of team members.

Changes Made

No functional changes were made; the method was simply moved from MentorManagement to MentoredTeam.

notify_mentor_of_assignment Method

Description

A private method that sends an email to the newly assigned mentor notifying them of their assignment. The email includes the assignment name and a full list of current team members to help the mentor familiarize themselves with the team.

Changes Made

No functional changes were made; the method was simply moved from MentorManagement to MentoredTeam.

participant.rb Reimplementation

In the new implementation of the Participant model, we refactored several methods to improve clarity, maintainability, and alignment with the Single Responsibility Principle (SRP). The topic_name method was removed, as topics are associated with teams rather than participants, making its presence in Participant a design inconsistency. We also relocated the mail_assigned_reviewers method to a dedicated mailer class, where notification logic more appropriately belongs. The authorization method was renamed for clarity, and sort_by_name was eliminated due to its overly narrow use case and lack of general applicability. These changes help decouple responsibilities and make the class easier to test and extend.

Below is a breakdown of each method that was changed/added in the revised Participant class and its role:

name Method

Description

Returns the participant’s full name by delegating the call to the associated user’s fullname method.

Changes Made

Renamed method from fullname to name.

responses Method

Description

Returns a list of responses by mapping each response map associated with the participant to its corresponding response.

Changes Made

No functional changes were made; the method was reimplemented as is.

username Method

Description

Returns the participant’s name by delegating the call to the associated user’s `name` method.

Changes Made

Renamed method from name to username.

delete Method

Description

Deletes the participant if no associated response maps or team exist, or if forced; otherwise, raise an exception.

Changes Made

No functional changes were made; the method was reimplemented as is.

force_delete Method

Description

Destroys all associated response maps and remove the team if this is the last participant; then delete the participant itself.

Changes Made

No functional changes were made; the method was reimplemented as is.

task_role Method

Description

Determines the participant’s role (e.g., mentor, reviewer, submitter) based on permission flags.

Changes Made

Was renamed to task_role() instead of authorization()

self.export Method

Description

Exports participant data to a CSV file based on the selected options for personal details, role, parent, email settings, and handle.

Changes Made

Update to align with new framework https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_Spring_2019/E1923_New_Framework_For_Import/Export

self.export_fields Method

Description

Returns a list of CSV header fields to include in the export, based on the provided options.

Changes Made

The method was updated to align with new framework https://wiki.expertiza.ncsu.edu/index.php?title=CSC517_Spring_2019/E1923_New_Framework_For_Import/Export

parent_absent? Method

Description

Ensures that a Participant belongs to exactly one parent entity, either an Assignment or a Course, but not both.

Changes Made

It was added as a private method for validation purposes.

assignment_participant.rb Reimplementation

In the revised implementation of the AssignmentParticipant model, we focused on improving code clarity, reducing duplication, and strengthening adherence to robust object-oriented principles. Several methods were delegated to the Participant superclass to promote reuse and maintain DRYness, particularly team, path, and set_handle, whose logic applies universally across all participant types. For instance, the get_ prefix was removed from reviewer to align with Ruby idioms and enhance readability. Additionally, methods tied to the deprecated TeamsUser model, such as team_user and duty_id, were removed in favor of the newly introduced TeamsParticipant abstraction. These changes support a cleaner class hierarchy, minimize SRP violations, and establish a more modular foundation for future extensions to participant behavior.

Below is a breakdown of each method that was changed or added in the revised AssignmentParticipant class and its role:

dir_path Method

Description

Returns the directory path of the assignment associated with this participant.

Changes Made

Renamed for directory_path for clarity and used safe navigation (&.).

reviewers Method

Description

Fetches all participants who reviewed the team this participant is part of.

Changes Made

Replaced loop and .push with map for conciseness.

set_current_user Method

Description

Stub method added for interface compatibility with other components like AssignmentTeam.

Changes Made

No functional changes were made; preserved as is for future maintainers.

copy_to_course Method

Description

Creates a CourseParticipant entry for the same user in a specified course if it doesn't already exist.

Changes Made

Used ::CourseParticipant explicitly to avoid class ambiguity and renamed parent_id to course_id.

feedback Method

Description

Retrieves feedback maps (peer review feedback) related to this participant.

Changes Made

No functional changes were made; the method was reimplemented as is.

reviews Method

Description

Returns all peer review responses for the participant’s team.

Changes Made

No functional changes were made; the method was reimplemented as is.

get_reviewer Method

Description

Returns the reviewer context: either the team or the participant itself, depending on whether team reviewing is enabled for the assignment.

Changes Made

Renamed to reviewer because get_ prefix is non-idiomatic in Ruby.

get_logged_in_reviewer_id Method

Description

Returns this participant's ID. Intended as a polymorphic method to match the interface in AssignmentTeam.

Changes Made

Renamed to logged_in_reviewer_id for clarity thereby adhering to Ruby's idiomatic naming conventions.

current_user_is_reviewer? Method

Description

Checks if the current user is the same as the one associated with this participant.

Changes Made

No functional changes were made; the method was reimplemented as is.

quizzes_taken Method

Description

Returns quiz response maps submitted by this participant.

Changes Made

No functional changes were made; the method was reimplemented as is.

metareviews Method

Description

Returns all metareview response maps (i.e., reviews of reviews) for this participant.

Changes Made

No functional changes were made; the method was reimplemented as is.

teammate_reviews Method

Description

Returns teammate review maps for this participant. Reflects peer evaluations among team members.

Changes Made

No functional changes were made; the method was reimplemented as is.

bookmark_reviews Method

Description

Returns any bookmark rating response maps for this participant.

Changes Made

No functional changes were made; the method was reimplemented as is.

files(directory) Method

Description

Recursively collects all files within the specified directory.

Changes Made

Replaced recursive loop with Dir.glob for simplicity and efficiency.

team Method

Description

Fetches the AssignmentTeam instance this participant belongs to by delegating to a class method.

Changes Made

Removed duplicate team method from assignment_participant.rb to promote DRYness.

self.import Method

Description

Imports a participant from a given row. If the user does not exist, it creates one and then adds them to the assignment.

Changes Made

Refactored to use keyword arguments (session:, assignment_id:); improved error messaging; renamed parent_id to assignment_id.

assign_copyright Method

Description

Assigns publishing rights by verifying a digital signature with a private key.

Changes Made

No functional changes were made; the method was reimplemented as is because logic is participant-specific.

verify_digital_signature Method

Description

Checks if the user’s public key matches the digital signature generated from the provided private key.

Changes Made

Renamed to verify_signature; streamlined OpenSSL usage.

set_handle Method

Description

Sets a unique handle for the participant based on their user’s handle or name. Ensures no duplication within the assignment.

Changes Made

Improved condition readability using strip.empty?; renamed parent_id to assignment_id; removed unnecessary ! from save!

path Method

Description

Returns the complete file path for this participant's team, based on the assignment path and team directory number.

Changes Made

Used File.join for path construction; added early return if assignment or team is nil.

review_file_path Method

Description

Constructs a file path for uploading review artifacts. Handles both team and non-team scenarios.

Changes Made

Refactored logic for clarity; used guard clauses and File.join; removed legacy parameterization logic.

current_stage Method

Description

Returns the current stage of the assignment for this participant, accounting for topic signup.

Changes Made

Commented out due to schema incompatibility; marked for future support.

stage_deadline Method

Description

Returns the due date for the current stage, handling both staggered and non-staggered assignments.

Changes Made

Commented out due to schema incompatibility; marked for future support.

duty_id Method

Description

Returns the duty ID from the TeamsUser record for this participant’s team.

Changes Made

Removed as TeamsUser has been fully replaced by TeamsParticipant.

team_user Method

Description

Finds the TeamsUser linking this participant’s user to their team.

Changes Made

Removed as TeamsUser has been fully replaced by TeamsParticipant.

course_participant.rb Reimplementation

In the revised implementation of the CourseParticipant model, we focused on improving cohesion, reducing redundant logic, and aligning more closely with object-oriented principles such as SRP and the Liskov Substitution Principle. The copy method was refactored to streamline control flow without violating class responsibilities. The import method, originally overloaded with multiple responsibilities, was modularized using helper functions to promote clarity and reduce code smells. Additionally, the path method was moved to the Participant superclass to enable reuse across participant types, thereby reducing duplication and enhancing maintainability. These changes make the class easier to understand, extend, and test.

Below is a breakdown of each method that was changed or added in the revised CourseParticipant class and its role:

copy_to_assignment Method

Description

Copies the course participant into a specific assignment by creating an AssignmentParticipant record if it doesn't already exist. It also assigns a handle to the new participant.

Changes Made

Refactored to reduce inline creation logic and improve readability; specifically, removed manual nil check and kept logic self-contained in CourseParticipant, respecting the Liskov Substitution Principle. Also, changed the name from copy() to copy_to_assignment().

self.import Method

Description

Imports a course participant from a hash. If the user doesn't exist, it is created and then added to the course.

Changes Made

The import method for CourseParticipant was refactored to improve clarity, robustness, and data integrity.

set_handle Method

Description

This method assigns a unique and valid handle to the CourseParticipant based on the associated user's information.

Changes Made

Added as a helper method to copy_to_assignment()

SOLID Principle(s)

Single Responsibility Principle: "A class should only have one responsibility and should never have more than one reason to change."

There are many violations of the Single Responsibility Principle (SRP) across all Participant classes. For example, AssignmentParticipant contains methods like reviews() and get_reviewer(), which should be the responsibility of the Team class. Similarly, Participant includes mail_assigned_reviewers() and email(), which should belong to the Mailer class.

Test Plan

We will write tests to ensure that all model validations function correctly for each class, including Participant, AssignmentParticipant, CourseParticipant, and all team-related models. We will verify that belongs_to, has_many, and other associations are correctly configured and that no orphaned or dangling records remain after creation or deletion. Special attention will be given to business logic, particularly methods reused or inherited across subclasses. Additionally, we will test edge conditions like minimum team size thresholds, permission flags (e.g., can_mentor), and mentor-selection criteria to ensure the intended behavior is preserved.

Team Information

Mentor:

  • Ed Gehringer

Team Members:

  • Ahmed Hassan (aohassan)
  • Rameez Malik (remalik)
  • Moaad Benkaraache (mbenkar)

Links