CSC/ECE 517 Fall 2024 - E2484. Reimplement participants controller.rb

From Expertiza_Wiki
Jump to navigation Jump to search

About Expertiza

Expertiza is an open source project based on Ruby on Rails framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.

Introduction

This project aims to reimplement the participants_controller.rb and participants_helper.rb in the new Expertiza system. The participants_controller.rb manages participants within assignments, and this reimplementation focuses on streamlining its methods, eliminating redundancy, and enhancing code readability and maintainability.

Requirements

  • Implement participants_controller.rb Methods: Fully implement each controller method with the same functionality as the current controller.
  • Import from participants_helper.rb : Integrate relevant helper methods to streamline functionality and remove redundancy.
  • API Creation: Expose API endpoints for all necessary methods to enable seamless access and integration from the frontend. Ensure that each endpoint follows best practices for RESTful API design, including proper error handling and secure data access.
  • Testing with rswag: Create test cases for all methods, focusing on edge cases, and generate rswag documentation.
  • Swagger UI Video Documentation: Record a video walkthrough of API endpoints in Swagger UI, showcasing each method’s functionality.
  • Existing Issues

    Reimplement participants_controller.rb while addressing the following:

  • Refactor code to comply with the Open-Closed Principle and the Single Responsibility Principle.
  • Introduce dependency injection where necessary.
  • Reduce excessive conditional statements.
  • Include sufficient code tests to verify functionality.
  • Enhance comments to better explain each method's functionality, purpose, and rationale for keeping or modifying particular aspects of the code.
  • Provide a more detailed explanation of design choices and refactoring steps.
  • Design / Proposed Solution

    Controller Diagram

    participants_controller.rb Methods / API Calls

     #  Method Endpoint Description
    1 index GET /participants/user/:user_id Return a list of participants for a given user
    2 index GET /participants/assignment/:assignment_id Return a list of participants for a given assignment
    3 show GET /participants/:id Return a specified participant
    4 add POST /participants/:role Assign the specified role to the participant and add them to an assignment
    5 destroy DELETE /participants/:id Delete a participant
    6 participant_params - Permitted parameters for creating a Participant object

    The following methods were removed from participants_controller.rb :

  • action_allowed? - No impact on functionality
  • controller_locale - No impact on functionality
  • update_authorizations - Since there is a direct relationship between the User and Role classes, and therefore the Participant and Role classes, it would be redundant to handle anything permissions-related here.
  • inherit - Since there is no direct relationship between the Participant and Course classes, this logic is redundant and no longer necessary
  • bequeath_all - Since there is no direct relationship between the Participant and Course classes, this logic is redundant and no longer necessary
  • change_handle - The User class has a `handle` field already. It would be redundant to have one in Participant as well.
  • delete - Handled in the remove_participant method of the AssignmentsController ( assignments_controller.rb )
  • view_copyright_grants - Incorrectly implemented in the old implementation
  • get_user_info - All needed user data can be accessed by leveraging the Participant model's belongs_to relationship to the User model
  • get_signup_topics_for_assignment - Handled in the index method of the SignUpTopicsController ( sign_up_topics_controller.rb )
  • participants_helper.rb Methods

    The methods in participants_helper.rb are outdated and do not impact any functionality in participants_controller.rb.
    As a result, these methods will not be carried forward to the new implementation:

  • upload_users - Logic for creating a User specifically for the Assignment and Course classes. Since there is no direct relationship between the User and these classes, this logic is redundant and no longer necessary
  • define_attributes - Same reason as above
  • define_user - Same reason as above
  • create_new_user - Same reason as above
  • add_user_to_assignment - Same reason as above. Furthermore, since the Participant and Assignment classes are directly related, this functionality has been replaced by the add_participant method in AssignmentsController (assignments_controller.rb)
  • add_user_to_course - Same reason as above
  • get_config - Same reason as above
  • store_item - Same reason as above
  • participant_permissions - Outdated way of updating permissions, handled more effectively by the update_permissions method in ParticipantsController (participants_controller.rb)
  • Pattern(s)

    Facade: "A simplified interface that performs many other actions behind the scenes."
    The participants_controller.rb uses the Facade Design Pattern to streamline interactions with the Expertiza backend, abstracting away complex logic and data handling tasks into a simplified API layer. A lot of calls to various services, objects, and features are abstracted, providing a unified, cohesive interface. By centralizing these calls, the controller can reduce dependencies on specific backend structures, making it easier for the front end to perform actions with minimal knowledge of what is going on in the backend, enhancing the maintainability and scalability of our codebase. Some such examples would be to call all the participants of a specific assignment, or pulling information about the course from a participant. Things that would otherwise complicate the front end due to the need to hunt through the backend for information that they need can be abstracted away into the facade interface. The current implementation already employs the facade pattern by its nature, but we will improve it by specifically targeting features of the facade design pattern.

    SOLID Principle(s)

    Open and Closed Principle: "Software entities should be open for extension, but closed for modification."
    Currently, the code directly checks the type of curr_object to determine whether it’s an Assignment or Course, which can make it challenging to extend or modify. To address this, we will implement polymorphism by moving participant-related logic into the respective classes (Assignment, Course, etc.). Each class will define its own behavior for handling participants by overriding a common interface or inheriting from a shared base class. For example, A ParticipantHelper file will define methods like add_user_to_course/assignment, store item, participant_permissions, and numerous other non-idiomatic methods that go against the model view controller design pattern. Method operations that implement business logic, such as the methods listed before, should generally not be the responsibility of the controller.

    Single Responsibility Principle: "A class should only have one responsibility and should never have more than one reason to change."
    The current implementation of the participant controller mostly aligns with the Single Responsibility Principle, but some methods have more than one responsibility, such as combining backend logic with UI feedback. Many methods within the ParticipantsController class have this type of combined logic, for example, list, add, and inherit methods. These methods blend participant management logic with flash message handling. To make our code comply with the Single Responsibility Principle, we can move these flash messages into a helper method. These modifications reduce the controller’s responsibilities, improving our code’s readability and reusability. Lastly, the frontend developers will have predictable API behavior and consistent responses when our code adheres to the Single Responsibility Principle.

    Implementation

    Implement participants_controller.rb Methods

    Refer to the participants_controller.rb Methods / API Calls section for a brief overview of its use

    Old Method Name Action New Method Name
    action_allowed? Removed -
    controller_locale Removed -
    list Renamed index
    add No Change add
    update_authorizations Removed -
    destroy No Change destroy
    inherit Removed -
    bequeath_all Removed -
    change_handle Removed -
    delete Removed -
    view_copyright_grants Removed -
    participant_params No Change participant_params
    get_user_info Removed -
    get_signup_topics_for_assignment Removed -
    - Added show

    index Method

    Description:

    Retrieves and returns a list of participant objects. The returned participants depend on the provided filters. Specifically:

    • If a user_id (optional) is provided in the parameters, it returns all participants associated with that user.
    • If an assignment_id (optional) is provided, it returns all participants related to that assignment.

    Parameters:

    user_id: The ID of the user whose participants you want to retrieve. If the user does not exist, the method returns without further action.
    assignment_id: The ID of the assignment whose participants you want to retrieve. If the assignment does not exist, the method returns without further action.

    Behavior:

    • The method validates the presence and existence of the user_id or assignment_id.
      • If either is invalid (i.e., the corresponding user or assignment doesn't exist), the method stops execution and does not proceed with participant retrieval.
      • If a valid user or assignment is provided, then it will retrieve all participants and filter in the ones of the provided user or assignment.
        • The final filtered list of participants is returned as a JSON response.

    create Method

    Description:

    Creates a new participant associated with a specific user and assignment. This method validates the presence of the user and assignment before creating the participant.

    Parameters:

    • user_id (required, from request parameters): The ID of the user who will be associated with the participant.
    • assignment_id (required, from request parameters): The ID of the assignment to link with the participant.

    Behavior:

    • Validates and retrieves the user based on the provided user_id. If the user is not found, the method terminates.
    • Validates and retrieves the assignment based on the provided assignment_id. If the assignment is not found, the method terminates.
    • Builds a new Participant instance linked to the validated user and assignment.
    • Attempts to save the Participant:
      • If successful: Returns a JSON response containing the created Participant and a 201 Created status.
      • If unsuccessful: Returns a JSON response containing validation errors and a 422 Unprocessable Entity status.

    destroy Method

    Description:

    Deletes a specified Participant based on the provided ID.

    Parameters:

    • id (required): The ID of the Participant to be deleted.

    Behavior:

    • Retrieves the Participant using the provided id.
    • Attempts to delete the Participant:
      • If successful: Returns a JSON response containing a confirmation message and a 200 OK status.
      • If unsuccessful: Returns a JSON response containing validation errors and a 422 Unprocessable Entity status.

    show Method

    Description:

    Retrieves and returns a specific Participant based on the provided ID.

    Parameters:

    • id (required): The ID of the Participant to be retrieved.

    Behavior:

    • Fetches the Participant from the database using the provided id.
    • Attempts to fetch the Participant:
      • If successful: Returns a JSON response containing a confirmation message and a 200 OK status.
      • If unsuccessful: Returns a JSON response containing validation errors and a 422 Unprocessable Entity status.

    participant_params Method

    Description:

    Defines the permitted parameters for creating or updating a Participant object.

    Parameters:

    The method expects a Participant object within the request parameters. It permits the following attributes:

    • user_id (required): The ID of the user associated with the Participant.
    • assignment_id (required): The ID of the assignment linked to the Participant.
    • team_id (optional): The ID of the team the Participant belongs to.
    • join_team_request_id (optional): The ID of any pending team join request related to the Participant.
    • permission_granted (optional): A boolean indicating whether the Participant has specific permissions granted.
    • topic (optional): The topic assigned to the Participant (could be a string or other data type depending on the application context).
    • current_stage (optional): The current progress stage of the Participant.
    • stage_deadline (optional): The deadline for the current stage.

    Behavior:

    • Ensures that only allowed parameters are passed when creating a Participant object.

    filter_participants Method

    Description:

    Retrieves and filters participants based on the provided user and/or assignment. It applies filters dynamically depending on which parameters are supplied.

    Parameters:

    • user (optional): An instance of the User model. If provided, the method filters participants associated with this user.
    • assignment (optional): An instance of the Assignment model. If provided, the method filters participants linked to this assignment.

    Behavior:

    • Fetches all participants from the database.
      • If a user is provided, the method filters participants where the user_id matches the given user's ID.
      • If an assignment is provided, the method filters participants where the assignment_id matches the given assignment's ID.
    • The final list of participants is then ordered by their id in ascending order.

    find_user Method

    Description: Retrieves a User object based on the user_id provided in the participant_params. If the user is not found, it returns an error response and halts further execution.

    Parameters:

    user_id (optional): The ID of the user to be retrieved. Extracted from the permitted parameters.

    Behavior:

    • Attempts to find the user in the database using the provided user_id.
      • If the user is not found (nil), it renders a JSON response with an error message and 404 Not found status
      • If the user exists, it returns the user object with 200 ok status.

    find_assignment Method

    Description:

    Retrieves an Assignment object based on the assignment_id provided in the participant_params. If the Assignment is not found, it returns an error response and halts further execution.

    Parameters:

    assignment_id (optional): The ID of the assignment to be retrieved. Extracted from the permitted parameters.

    Behavior:

    • Attempts to find the assignment in the database using the provided assignment_id.
      • If the assignment is not found (nil), it renders a JSON response with an error message and 404 Not found status
      • If the assignment exists, it returns the assignment object with 200 ok status.

    deletion_message Method

    Description:

    Generates a customized success message after a participant has been deleted. The message varies depending on whether the participant was associated with a specific team.

    Parameters:

    • params (required): A hash containing the following keys:
      • id (required): The ID of the deleted participant.
      • assignment_id (required): The ID of the assignment the participant belonged to.
      • team_id (optional): The ID of the team the participant was part of, if applicable.

    Behavior:

    • Check for Team Association:
      • If team_id is not associated (nil), the message references only the participant and assignment.
      • If team_id is associated, the message includes the team information as well.
    • Constructs and returns a string message based on the presence or absence of team_id.

    build_participant Method

    Description:

    Builds and initializes a new Participant object with the provided user and assignment. It assigns the user_id and assignment_id to the participant.

    Parameters:

    • user (required): An instance of the User model. The user_id of this object will be assigned to the participant.
    • assignment (required): An instance of the Assignment model. The assignment_id of this object will be assigned to the participant.

    Behavior:

    • Creates a new Participant object using the permitted parameters from participant_params.
    • Sets the user_id to the ID of the provided user.
    • Sets the assignment_id to the ID of the provided assignment.
    • Returns the newly built Participant object without saving it to the database. Further actions (like validation or saving) are expected to be performed outside this method.

    Import from participants_helper.rb

    Refer to the participants_helper.rb Methods section for all design-related inquiries

    Old Method Name Action New Method Name
    upload_users Removed -
    define_attributes Removed -
    define_user Removed -
    create_new_user Removed -
    add_user_to_assignment Removed -
    add_user_to_course Removed -
    get_config Removed -
    store_item Removed -
    participant_permissions Removed -

    Model

    The following unnecessary and redundant database columns have been removed from the participants model entirely.

    Column Name Reason for removal
    can_submit Redundant as this is already handled by Role.
    can_review Redundant as this is already handled by Role.
    handle Redundant as this is already handled by User.

    API Creation

    Refer to the participants_controller.rb Methods / API Calls section for all design-related inquiries

    Testing with rswag

    Refer to the Testing Plan section
    To be expanded upon during implementation

    Swagger UI Video Documentation

    To be added at a later time

    Testing Plan

    rswag
    We will use rswag to test and document our project’s API endpoints. Rswag integrates RSpec testing with Swagger, allowing us to define test cases in RSpec to validate functionality while automatically generating interactive Swagger documentation. This documentation, accessible through Swagger UI, provides developers and stakeholders with a user-friendly way to explore and interact with our API endpoints.

    Tests

    Test ID Test Description
    1 Test 'index' with valid model (Assignment) and ID - Should list participants
    2 Test 'index' with invalid model (Assignment) and ID - Should return an error message
    3 Test 'index' when there are no participants - Should return an empty list
    4 Test 'show' with valid participant ID - Should return the specified participant details
    5 Test 'show' with invalid participant ID - Should return participant not found
    6 Test 'create' with valid user detail - Should successfully create a new participant
    7 Test 'create' with duplicate user information - Should return an error message indicating that the participant already exists
    8 Test 'create' with invalid data format - Should return a validation error
    9 Test 'destroy' with valid participant ID - Should delete the specified participant
    10 Test 'destroy' with invalid participant ID - Should return participant not found message
    11 Test 'destroy for participant who has associated records - Should return an error message or handle the cascading deletions

    Team

    Mentor

    • Jay Patel <jhpatel9@ncsu.edu>

    Students

    • Pierce Whelan <pwwhelan@ncsu.edu>
    • Calvin Jiang <crjiang@ncsu.edu>
    • Hechun Zhang <hzhang56@ncsu.edu>

    Relevant Links

    Pull Request [1]
    GitHub Repository [2]
    GitHub Project Board [3]
    participants_controller.rb in Old Expertiza [4]
    participants_helper.rb in Old Expertiza [5]