CSC/ECE 517 Fall 2023 - E2384. Reimplement user controller.rb, user.rb and its child classes

From Expertiza_Wiki
Revision as of 18:04, 2 December 2023 by Svargas3 (talk | contribs) (→‎Code)
Jump to navigation Jump to search

Description of Project

The project aims at reimplementing user controller.rb, user.rb and it's associated child classes. The project reimplementing functionalities specific to the above classes and write extensive rspec tests for the same.

Problem Statement

Background: Background: The User model is a key component of the Expertiza application, handling user data and authentication/authorization features. It is linked to other models such as Participant, TeamsUser, and Invitation, allowing for associations and a personalized user experience.

Reimplementation (What needs to be done): To set up the project, follow these instructions.

  • Reimplement the search_users, find_user methods in user.rb
  • Reimplement the role, paginate_list functionality in users_controller.rb
  • Write thorough RSpec tests for the newly implemented functionalities

Objectives

  • Reimplement methods pertaining to controller.rb, user.rb and it's associated child classes. More specifically reimplement search_users, find_user methods in user.rb.
  • Reimplement the role, paginate_list functionality in users_controller.rb.
  • Ensure proper naming of the methods, variables.
  • Incorporate suggestions from project3.
  • Ensure the PR checks are successfull and all test cases are passing.
  • Compose comprehensive RSpec tests for the changes done to ensure the robustness and reliability of the entire system.

Development Strategy

We have started the development activity using TDD approach. We start by creating test cases for the functionality in hand. Since it is reimplementation, the existing code and functionality makes it much easier to select comprehensive test cases. This is followed by writing clean and simple code to pass the test cases. We are also incorporating comments we received as part of project 3. We identified few more places where naming could be better and we will be incorporating the suggested changes in the reimplementation project.

Revised User.rb:

  1. search_users Method:
    1. The 'search_users' method will be reimplemented to accept parameters such as 'role', 'user_id', 'letter', and 'search_by'.
    2. It will construct a SQL query based on the provided parameters to filter users.
    3. The method will return a list of users that match the search criteria.
  1. find_user Method:
    1. The 'find_user' method will be reimplemented to locate a user based on the provided login.
    2. It will first try to find the user by email. If not found, it will attempt to find the user by name.
    3. The method will return the found user or 'nil' if no matching user is found.

Revised UsersController.rb:

  1. role Action:
    1. The 'role' action will be reimplemented to handle requests related to user roles.
    2. It may return information about the role of a specific user or perform other role-related functionalities.
  1. paginate_list Action:
    1. The 'paginate_list' action will be reimplemented to handle paginated listing of users.
    2. It will retrieve a paginated list of users based on certain criteria, making it easier to display users in chunks.

Revised Instructor.rb:

  1. get_user_list Method:
    1. The 'get_user_list' method in the 'Instructor' class will be reimplemented to fetch a list of users based on the instructor's role.
    2. The method will likely consider the instructor's courses/assignments and return a list of users associated with those courses/assignments.

RSpec Tests:

  1. User.rb Tests:
    1. RSpec tests for the 'search_users' method will ensure that the method correctly filters users based on the provided parameters.
    2. Tests for the 'find_user' method will validate that it successfully locates users by email or name.
  1. UsersController.rb Tests:
    1. RSpec tests for the 'role' action will validate its behavior, ensuring it returns the expected role-related information.
    2. Tests for the 'paginate_list' action will check that it correctly paginates the list of users.
  1. Instructor.rb Tests:
    1. Tests for the 'get_user_list' method in the 'Instructor' class will ensure it fetches the correct list of users based on the instructor's role and associated courses/assignments.

ToDo Status:

 #  Task Status Notes
1 Reimplement search_users method in User.rb Done! This method will be updated to accept parameters such as `role`, `user_id`, `letter`, and `search_by`.
2 Reimplement find_user method in User.rb To Do This method will be updated to locate a user based on the provided login.
3 Reimplement role action in UsersController.rb To Do This action will be updated to handle requests related to user roles.
4 Reimplement paginate_list action in UsersController.rb To Do This action will be updated to handle paginated listing of users.
5 Write RSpec tests for User.rb To Do New tests will be written for the `search_users` and `find_user` methods.
6 Write RSpec tests for UsersController.rb To Do New tests will be written for the `role` and `paginate_list` actions.

Test Plan

Sr No Test Description
1 seacrh_users method in User.rb
1.1 Scenario 1: Test user search by name
1.2 Scenario 2: Test user search by email
1.3 Scenario 3: Test user search by fullname
2 find_user method in User.rb
2.1 Scenario 1: Test locate user by name
2.2 Scenario 2: Test locate user by email
3 Role method in user_controller.rb
3.1 Scenario 1: Role instance to be invalid scenario
3.2 Scenario 2: Role instance to be valid scenario for student
3.3 Scenario 3: Role instance to be valid scenario for instructor
3.4 Scenario 4: Role instance to be valid scenario for admin
4 paginate_list method in user_controller.rb
4.1 Scenario 1: checks that paginate_list does not fail with controller
4.2 Scenario 2: checks that paginate_list does not fail with post

Implementation

Create users Using rails Console

Configure Compose as a remote interpreter

Connect MySQL DB and Application


Ruby syntax for creating a new user in a Rails application using the User model.

User.create!(
 name: 'newuser', # lowercase name
 email: 'new_user@example.com',
 password: 'password123',
 full_name: 'New User',
 role: Role.find_by(name: 'Super Administrator')
)

Code

The search_users method accepts three parameters: user_id, word, and search_by. If a valid user_id is provided, the method returns an array containing the user with that specific user_id. In cases where user_id is empty or invalid, the method performs a search based on the provided word and search_by parameters. To prevent SQL injection, the method validates search_by against a predefined set of acceptable fields, including 'name', 'full_name', 'email', and 'role'. The search is then conducted using a LIKE query on the specified field, ordering the results by the user's name.

This flexible method accommodates various search scenarios, allowing users to query the system based on different criteria, enhancing the overall user experience.

  def self.search_users(user_id, word, search_by)
    if user_id.present? && (user = User.find_by(id: user_id))
      # If a valid user_id is provided, return the user with that specific user_id
      return [user]
    else
      # If user_id is empty or invalid, perform the search based on word and search_by parameters

      # Validate search_by to avoid SQL injection
      valid_search_fields = %w[name full_name email role]
      search_by = valid_search_fields.include?(search_by) ? search_by : nil

      # Perform the LIKE query on the specified field (name, full_name, email, role) and order by name
      if search_by.present?
        # Use search_by directly in the where clause
        users = User.joins(:role).where("#{search_by} LIKE ?", "%#{word}%").order(:name) if search_by == 'role'
        users ||= User.where("#{search_by} LIKE ?", "%#{word}%").order(:name)
        return users
      else
        # If search_by is not recognized, return an empty result
        return []
      end
    end
  end

The login method, was updated to fix the NIL error

 def login
   user = User.find_by(name: params[:user_name]) || User.find_by(email: params[:user_name])
 
   if user&.authenticate(params[:password])
     payload = {
       id: user.id,
       name: user.name,
       full_name: user.full_name,
       role: user.role&.name,  # Use safe navigation operator (&.) to avoid nil error
       institution_id: user.institution&.id  # Use safe navigation operator (&.) to avoid nil error
     }
 
     token = JsonWebToken.encode(payload, 24.hours.from_now)
     render json: { token: token }, status: :ok  # Include the actual token value in the response
   else
     render json: { error: 'Invalid username/password combination' }, status: :unauthorized
   end
 end

search_users Method

This method is designed to handle user search functionality in a web application. It retrieves parameters from the request to identify the current user, search criteria, and search type. It then calls the `search_users` method from the `User` model and renders the result accordingly.

Users can search by `user_id`, and if it's empty or invalid, the search extends to attributes such as `name`, `full_name`, `email`, and `role`. The search results are ordered by the user's name.


Attributes

  • name: The name of the user.
  • full_name: The full name of the user, providing a comprehensive representation.
  • email: The unique email address associated with each user, ensuring distinct identification.
  • role: A relationship with the Role model, defining the user's role and access privileges.


Result Handling

- If the result is a collection of users (`ActiveRecord::Relation`), it renders them as JSON.


 def search_users
   user_id = params[:user_id]
   word = params[:word]
   search_by = params[:search_by]
   result = User.search_users(user_id, word, search_by)
   if result.present?
     # If the result is not empty, render the users as JSON
     render json: result
   else
     # If the result is empty, render a message as JSON with a not found status
     render json: { error: 'User not found or no matching results' }, status: :not_found
   end
 end

This method facilitates dynamic user searches, allowing users to query the system based on different parameters. Users can search by `user_id`, and if it's empty or invalid, the search extends to attributes such as `name`, `full_name`, `email`, and `role`. The search results are ordered by the user's name.

API Documentation

Endpoint: Search Users

Description

This endpoint allows you to search for users based on various fields. If the requesting user is a Super Administrator, the search can include 'name', 'email', 'full_name', 'id', or 'role'. If the user is not a Super Administrator, the search is limited to the user with the provided user_id.

Request

Method: GET

URL: /api/v1/users/search_users

Parameters:

  • user_id (optional): The ID of the requesting user. If provided, it is used to check if the user is a Super Administrator.
  • word: The search term. This is used to perform a LIKE query on the specified field.
  • search_by: The field to search by. This can be 'name', 'email', 'full_name', 'id', or 'role'.

Response

Status Code: 200 OK

Body: A list of users that match the search term in the specified field. If the requesting user is not a Super Administrator, it returns the user with the given user_id.

Example

Request:

GET /api/v1/users/search_users?user_id=1&word=r&search_by=role

Response:

[
    {
        "id": 1,
        "name": "root",
        "full_name": "New Super Administrator",
        "email": "root@example.com",
        "email_on_review": false,
        "email_on_submission": false,
        "email_on_review_of_review": false,
        "role": {
            "id": 1,
            "name": "Super Administrator"
        },
        "parent": {
            "id": null,
            "name": null
        },
        "institution": {
            "id": null,
            "name": null
        }
    },
    {
        "id": 2,
        "name": "admin",
        "full_name": "Administrator",
        "email": "admin@example.com",
        "email_on_review": true,
        "email_on_submission": true,
        "email_on_review_of_review": true,
        "role": {
            "id": 2,
            "name": "Administrator"
        },
        "parent": {
            "id": 1,
            "name": "root"
        },
        "institution": {
            "id": 1,
            "name": "Institution 1"
        }
    },
    {
        "id": 3,
        "name": "user",
        "full_name": "Regular User",
        "email": "user@example.com",
        "email_on_review": false,
        "email_on_submission": false,
        "email_on_review_of_review": false,
        "role": {
            "id": 3,
            "name": "Instructor"
        },
        "parent": {
            "id": 2,
            "name": "admin"
        },
        "institution": {
            "id": 2,
            "name": "Institution 2"
        }
    }
]

Postman Implementation

Test RSpec

user_spec.rb

 describe '.search_users' do
  let(:super_admin_role) { Role.find_or_create_by(name: 'Super Administrator') }
  let(:user) { create(:user, role: super_admin_role) }
  context 'when the user is a Super Administrator' do
    it 'returns users with matching roles' do
      # Test scenario: When searching by role, it should return users with matching roles.
      result = User.search_users(user, 'Admin', 'role')
      expect(result).to include(user)
    end
    it 'returns an empty array if no users match the criteria' do
      # Test scenario: When no users match the specified criteria, it should return an empty array.
      result = User.search_users(user, 'Nonexistent', 'name')
      expect(result).to eq([])
    end
  end
  context 'when the user is not a Super Administrator' do
    let(:regular_user) { create(:user) }
    it 'returns unauthorized when the user is not a Super Administrator' do
      result = User.search_users(regular_user, 'paolajones', 'name')
      expect(result).to eq('Not Authorized')
    end
  end
 end

Test Results

Team

Mentor
  • Devashish Vachhani
Members
  • Doddaguni, Sachin R
  • Mahesh, Amogh
  • Villar, Sergio Vargas

References