CSC/ECE 517 Spring 2024 - E2442 Reimplement student task controller: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
Line 139: Line 139:


== UML ==
== UML ==
[[File:Student task uml.jpeg | 1000 px]]
[[File:Student task uml.jpeg | 1200 px]]


== Testing ==
== Testing ==

Revision as of 08:14, 9 April 2024

Github repository

Front end: https://github.com/ychen-207523/reimplementation-front-end

Back end: https://github.com/ychen-207523/reimplementation-back-end

Expertiza

Expertiza is a Moodle-like open source project developed with Ruby on Rails, designed to enhance the educational experience by allowing students, TAs and instructors to interact on assignments and projects. For instructors, Expertiza can help to create new assignments, review and grade the students’ submissions. For students, Expertiza can provide features to form teams, submit assignments, and provide peer evaluations.

Problem Statement

The scope of this project is the continuation of E2429. In the previous part, we have implemented the student_task table with React and TypeScript. On this project, we are going to work on the student_task_controller.rb and student_task.rb based on the original design of Expertiza and reimplement them.

student_task.rb: This file represents the student task model, will be where we define the relationship between student tasks and other entities such as courses, participants and assignments in the system, as well as any custom logic related to student tasks

student_task_controller.rb: This file is the controller of student task, we will implement features related with authentication and listing, viewing the student tasks.The main functions this project will focus on are list, which is to gather and organize student tasks to facilitate the display of tasks, and view, which is to display detailed information about a specific student task based on the student id.

The student task is highly related with other models such as participant and topic, which have not been implemented or finished yet. For the scope of this project, we will establish the foundational elements of the StudentTask to ensure its capability to interface with the frontend effectively. This approach allows us to set up a framework that can support future teams to incorporate the future implementation into student_task.

Principles

In order to ensure our code is maintainable, extensible, and as simple as possible, we will follow several universal design principles. Similarly, we will be conscious of and attempt to avoid design smells that can indicate code is too rigid, fragile, complex, or difficult to understand.

While developing the student task controller and model, the single responsibility principle (SRP) is important to maintain. The SRP states that each class should not have more than one reason to change- in other words, it should do one thing and do it well. The first implication of this principle is that the controller should not contain significant application logic; the controller’s primary responsibility is to handle requests and call the appropriate methods. Therefore, it should delegate to the model class for any complex logic. The principle can also be applied to functions within the model class itself. Ideally, the student task controller will call simple and reusable functions in the model class that each perform one task.

The reusability of components follows another important principle- do not repeat yourself, also known as DRY . Essentially, the same code should not exist in two different places if it does the same thing- instead, the design of components should enable the code to be written once and called multiple times. This reduces the complexity of the application, ensures the code always does the same thing, and makes testing the code simpler and more effective. We will consider the DRY principle throughout development, ensuring we develop simple, granular, and reusable functions for the student task model that can be reused by other components in the future.

The open-closed principle states that classes should be open for extension but closed for modification. Following this principle, the student task controller should interact with the model through method calls encapsulated in the model and not modify any data for the model itself. Additionally, we need to be cognizant of the overall design of the model and controller so they don’t need to change in order to implement new functionality in the future. Again, this will be achieved by keeping the code modular and ensuring the student task model’s methods adhere to principles of encapsulation and single responsibility.

Finally, it’s important to make code as readable as possible. If developers understand code more quickly, the code is more maintainable, extensible, and less likely to cause unforeseen errors. Therefore, we will follow several best practices for code readability:

  • Narrowest Scope: Give a variable the narrowest scope you can. By giving the narrowest scope by default, we constrain variables to the context in which they are needed, reducing the need for developers to reason about too many variables.
  • Conciseness: Code should be as concise as possible while being simple to understand.
  • Variable Names: Variable names should be long enough to be descriptive, but not longer than necessary. Variables that are only used once or twice may be a bit longer than variables used throughout the code, since the developer may be much more familiar with these variables.
  • Consistency: Follow conventions that exist in the present code. Unless there are fundamental differences, a problem should not be solved in different ways by the same code base. By using existing solutions and conventions, we make our code easier to use in the context of the system and help developers understand the implementation.
  • Commenting: Provide informative comments about the purpose of code. Obvious things that are clarified by concise and readable syntax don’t need to be explained; instead, we will focus on providing developers with context for any sequence of operations that merits explanation.

Implementation

Prerequisite: Given that the StudentTask heavily relies on data from the Participant table, we will utilize the existing Participant model, controller, database table, and schema. Once the new Participant model and controller are completed, the future team should integrate these updates to ensure that the StudentTask remains fully functional.
Another inseparable element of the StudentTask table is the topic; however, implementing the supporting backend for topics is beyond the scope of our current project. Therefore, we will utilize JSON data to mimic the interaction and data structure of topics. This method allows us to simluate the topic without implementing. Also, The future team can integrate the implemented topic part into student task easily without conflict.

student_task.rb: The first step to approach is to clearly define the model's attributes, relationships, and foundamental functionalities. Based on the previous implementation we understand that the student task is created based on participant. To maintain the consistency, we plan to implement the method for creating StudentTask instances directly from participants. Utilitze the existing participant is to follow the approach of Do not Repeat Yourself (DRY) and Single Responsibility Principle.

  def initialize(args)
    @assignment = args[:assignment]
    @current_stage = args[:current_stage]
    @participant = args[:participant]
    @stage_deadline = args[:stage_deadline]
    @topic = args[:topic]
  end

  def self.from_participant(participant)
    StudentTask.new(
      participant: participant,
      assignment: participant.assignment,
      topic: participant.topic,
      current_stage: participant.current_stage,
      stage_deadline: (begin
                         Time.parse(participant.stage_deadline)
                       rescue StandardError
                         Time.now + 1.year
                       end)
    )
  end

Also, we will add other functions such as complete?, not_started?, and other facilitating methods to enrich the model's interactivity and user feedback capabilities.This approach is to follow Open/Closed Principle that student_task can have more behaviors by adding new functions but existing functions remain the same.

student_task_controller.rb: This file will be the main part we focus on. To start with, we will implement list function based on the current design:

 def list
    if current_user.is_new_user
      redirect_to(controller: 'eula', action: 'display')
    end
    session[:user] = User.find_by(id: current_user.id)
    @student_tasks = StudentTask.from_user current_user
    if session[:impersonate] && !impersonating_as_admin?

      if impersonating_as_ta?
        ta_course_ids = TaMapping.where(ta_id: session[:original_user].id).pluck(:course_id)
        @student_tasks.select! { |t| ta_course_ids.include? t.assignment.course_id }
      else
        @student_tasks.select! { |t| t.assignment.course && (session[:original_user].id == t.assignment.course.instructor_id) || !t.assignment.course && (session[:original_user].id == t.assignment.instructor_id) }
      end
    end
    @student_tasks.select! { |t| t.assignment.availability_flag }

    # #######Tasks and Notifications##################
    @tasknotstarted = @student_tasks.select(&:not_started?)
    @taskrevisions = @student_tasks.select(&:revision?)

    ######## Students Teamed With###################
    @students_teamed_with = StudentTask.teamed_students(current_user, session[:ip])
  end

The current implementation first checks if the current user is a new user, if so, the user is redirected to a "End User License Agreement" (EULA) page. Then, it stores the current user's information in the session to improve the efficiency of the subsequent actions. Next, it retrieves list of student tasks related to the current user by calling StudentTask.from_user current_user. It also handles the impersonation, which provides a filter based on the role. It also handles notification and get the students who have teamed with the current user.
After we finish the implementation of list, we will move on to view. Here is the current design of view:

  def view
    StudentTask.from_participant_id params[:id]
    @participant = AssignmentParticipant.find(params[:id])
    @can_submit = @participant.can_submit
    @can_review = @participant.can_review
    @can_take_quiz = @participant.can_take_quiz
    @authorization = @participant.authorization
    @team = @participant.team
    denied unless current_user_id?(@participant.user_id)
    @assignment = @participant.assignment
    @can_provide_suggestions = @assignment.allow_suggestions
    @topic_id = SignedUpTeam.topic_id(@assignment.id, @participant.user_id)
    @topics = SignUpTopic.where(assignment_id: @assignment.id)
    @use_bookmark = @assignment.use_bookmark
    # Timeline feature
    @timeline_list = StudentTask.get_timeline_data(@assignment, @participant, @team)
    # To get the current active reviewers of a team assignment.
    # Used in the view to disable or enable the link for sending email to reviewers.
    @review_mappings = review_mappings(@assignment, @team.id) if @team
  end

The current design is to provide detailed information about a specific sutdent task based on the participant id, then it gathers different information from the participant along with the pther required information such as topic and time line. Therefore, the student task is highly related with participant.
For our project, we intend to keep the same design idea, we will start from implementing list function to provide a comprehensive and filtered overview of student task based on the role of the current user. This will give us a solid start point. After we finsih implementing list, we will move on to view, focusing on offering detailed information about individual student tasks. The design principles include the Single Responsibility Principle (SRP), ensuring each component of our application is tasked with a single responsibility, and the Principle of Least Privilege (PoLP), ensuring users access only the data and actions relevant to their role.

UML

Testing

The minimum scope of the project is to complete the list function in the student task controller. The purpose of the list function is to provide the user interface with data for displaying the student task table. Accordingly, we will test the following cases for the list function:

  • Ensure a user gets all their tasks with correct attributes when they request. (For this case, various users will be tested with different tasks).
  • Ensure a user is unable to view tasks for another user.
  • Ensure a user gets tasks without error when some data is missing.

Additionally, the team hopes to complete the view function, which displays information about a specific task. If this functionality is finished, the following cases will be tested:

  • Ensure a user is able to view any task retrieved from the table.
  • Ensure the user gets correct attributes when they request.
  • Ensure a user may view a task without error when some data is missing.

In early stages of development, the team will be using Postman (https://www.postman.com) in order to test API endpoints exposed by the student task controller. Specifically, the endpoints for the list function and the view function will be checked with Postman to verify their parameters, headers, and response values. By using Postman in early stages, the team hopes to quickly and simply test code changes without manually navigating through the UI each time.

After the endpoints have been implemented, they will be compiled and thoroughly tested using Swagger UI (https://swagger.io/tools/swagger-ui/). Swagger UI enables users to test various requests and view their responses in an accessible web interface. The platform will enable us to quickly test endpoints with different parameters and validate the structure of responses with models we can define.

Additionally, we will do functional testing of the controller itself, and the methods we've implemented, with Rspec (https://rspec.info/features/6-0/rspec-rails/controller-specs/). We will test success and error responses with valid and badly-formed requests in order to ensure our components are reliable and secure. Automating tests is important for preserving existing functionality, especially when changes are made.

Process

Project Board

We utilize a project board on GitHub in order to track and delegate our tasks that the reimplementation is comprised of.

project board

We initialize our tasks on the board and so that they can be tracked and our progress can be followed by each team member, regardless of their level of responsibility in a single task. That way, even if a team member isn't directly responsible for a sub-task, a single source of truth displays to everyone the state of the project at any point in time.

Moreover, our design documentation should allow us to create a roadmap and tasks before designing code, so that the course of action is clear and the tasks can be evenly delegated.

Code Quality

By laying out all of the incremental steps we have in order to reimplement the student task controller, we ensure that all boxes are checked in redesigning the software. Moreover, adequate comments throughout the code, and adherence to best practices will ensure our code is readable, robust, and inline with industry standards.

Moreover, sufficient testing and peer reviews should also ensure our code is up to the highest quality.

Communication

We communicate on a regular basis using a text group chat. Moreover, we have scheduled formal calls at least once a week to discuss current objectives and progress. Additionally we often jump on a less unscheduled calls to pair program and problem solve.

Team

Students:

David White (dawhite4@ncsu.edu)

Henry McKinney (hmckinn@ncsu.edu)

Yunfei Chen (ychen267@ncsu.edu)


Mentor:

Kashika Malick (kmalick@ncsu.edu)