CSC/ECE 517 Fall 2021 - E2153. Improving search facility in Expertiza

From Expertiza_Wiki
Jump to navigation Jump to search

Introduction

The Expertiza project takes advantage of peer-review among students to allow them to learn from each other. It is an open-source application running on Ruby on Rails. It is used for the management of courses and the assignments for respective courses, by the faculties and the students. The manage content section of the application has different views that display information about the users, courses, assignments, questionnaires, and reviews.

The application should have a fully functional search functionality throughout the views, so that a user can search any type of data with ease, on the basis of any number of parameters depending on his requirements. Users should be searched on the basis of one more parameter which includes name, full name, email, etc. Similarly, assignments should be searched on the basis of name, created date, updated date, etc.

However, the search functionality in the existing application is constrained to just a single parameter for users and assignments. Questionnaires management does not have a search functionality implemented as yet. This project works on improving the search functionality of Expertiza, by adding search bars if not present, introducing an advanced search feature where user can search on the basis of more than one parameters, and making the search functionality appear more elegant.

Test Login Credentials

  • UserId: instructor6
  • Password: password
  • Problem Statement

    1. An instructor or administrator can search for a user by name, user-ID, or other characteristics.
    2. An instructor should be able to search for assignments by name, due date, or other characteristics.
    3. An instructor should be able to search for rubrics (or other questionnaires) by name, or by the courses or assignments they have been used in.
      1. For the instructor, there also needs to be a way to quickly find rubrics (and other questionnaires) that have been used in a single course. It should be possible to search or click somewhere to bring up a list of questionnaires used in the course, expanding only the applicable questionnaires in the list of questionnaires.
      2. One should also be able to search for questionnaires by words used in questions that belong to the questionnaires.
    4. There should be a way to search all reviews of a particular team’s work for particular scores or text strings. Reviews should be able to be filtered by score, text comment length, reviewer, and reviewee.
    5. An instructor or administrator should be able to search for all the assignments that a particular user has participated in.
    6. If more than one criterion needs to be specified, there should be an 'Advanced Search' button.

    E2153 Our Result

    1. E2153 Github Repository
    2. E2153 Pull Request
    3. Demo Video

    E2079 Previous Implementation

    1. E2079 Github Repository
    2. E2079 Pull Request
    3. Video Link

    Issue With Previous Implementation

    1. All implementation are working on javascript inside tree_display.jsx.
    2. With compatibility issue, these work can't be check-in currently.
    3. Format are not aligned between course search/assignment search and user search/rubric search.
    4. Questionnaire search is not straightforward and the list is not working.
    5. Searching of user with "name" and "full name" is confusing.
    6. Searching criteria can't be accumulated.
    7. Instructors and administrators can't find assignments with participants.

    Proposed Solution

    Demo Video

    The design proposed in this iteration of the project is not much different from a high level than the design proposed form last year in Fall 2020 Design. Below you will see a similar description of the solution previously proposed and some additional design choices added to improve upon the previous iteration of this issue. Changes from the previous design will be denoted by clear statements indicating the revision.

    Three main objects in this application are used as the basis for expanding search functionality. These are the user, assignment and questionnaire. Each of these points are searchable by the title of the object or not searchable at all. The remaining sections note the current situation and propose a tentative solution.

    Search for User:

    In the current system workflow, the Manage Users view can search users by Username, Full name, and email. We will retain these 3 searching criteria, except changing "Username" into "User ID" to avoid confusion with "Full name". We will allow searching for fields irrespective of the case of the searched string. The user will be able to apply multiple filters at a time and the output of the query will match all filters applied. If no results are found, an empty list will be returned.

    Implementation

    User has its own "list" controller, so it will directly implemented in list form with a "_search" html form after apply the search result. Since only this class has rails list, so only this file will implement in ruby code. Our goal is to maintain the logic and search alike.

    1. Delete the original simple search in "app/views/users/list.html.erb"
      1. Add a render for search form
      2. Align the UI for direct user access, which is not part of our project, but to make the page looks similar, we also change the style of it
      3. Align the user list table UI with style "class="table table-hover""
    2. Add a form in "app/views/users/_search.html.erb"
      1. Note that to align the UI design, the "Search" button will using style "class='btn btn-primary'"
      2. Note that to align the UI design, the "text blank" will using the style "class:'form-control'"
      3. Advanced Search toggle button is done with javascript (jquery) inside this form individually, and the form is divided into 2 separate field
        1. search_button_field: This part should always be displayed
        2. advance_search_form: This part should only display after the "Advanced Search" be toggled
    3. Add a form input handler in the "users_controller.rb" to parse the form, which should only do parsing and send parameters to model
    4. Add a advanced search feature to the User model "user.rb" inside the method "get_user_list"
      1. This change will cause this method to take up 3 parameters with (user id, full name, e-mail)
      2. We use regular expression to match the search with user fields, and it should allow multiple input for comparison
      3. The result will return back to controller in @users, and list view will render it again with paginated users

    Search for Courses:

    In the current system implementation, searching via the name of the course is supported with a partial or complete course name. In the proposed system, the user will be able to search for a course using additional filters after they press the Advanced Search button. The filters will have creation date, updated date and a checkbox represent whether it include a quiz. The user could apply multiple filters at a time and the output of the query would match all filters applied.

    To search for a course by Date, the user will have a drop down list to choose search by created or updated date. The following will prompt with a calendar where he can select a date and all the courses created/update on or before the selected date will be displayed.

    To apply multiple filters, the user can tap on the Advanced Search button available, adjacent to the Search button; a hidden div will then be rendered below-containing text boxes for all the columns. All courses that match the filters will be returned. An empty list will be returned if the search criteria don't match any records in the database.nce.

    Implementation

    This part is solely listed within the file "app/assets/javascripts/tree_display.jsx", so we can only implement this part with javascript. The interactive dropdown advanced search code will maintain the same format as "User Advanced Search". By using AdditionalSearchDropDown, DatePicker, and HASQUIZ_TOGGLE components, we build a pop-up advanced search functionality in React component FilterableTable.

    1. Getting sub-contents when a user press on a course
      1. The getSubFolderData() from FilterableTable will send HTTP POST request.
      2. After retrieving the data, it will update the state of FilterableTable component.
      3. Once the state is updated, it will trigger an update to ContentTable component and rerender the component.
    2. Searching for courses
      1. The searching method is handled by ContentTable component, which filters out courses' names that match the user's input.

    Due to the similarity of course search and assignment search, they share the same code in FilterableTable component.

    Search for Assignments:

    In the current system implementation, searching via the name of the assignment is supported with a partial or complete assignment name. In the proposed system, the user will be able to search for an assignment using additional filters after they press the Advanced Search button. The filters will have creation date, updated date and a checkbox represent whether it include a quiz. The user could apply multiple filters at a time and the output of the query would match all filters applied.

    To search for an assignment by Date, the user will have a drop down list to choose search by created or updated date. The following will prompt with a calendar where he can select a date and all the assignments created/update on or before the selected date will be displayed.

    To apply multiple filters, the user can tap on the Advanced Search button available, adjacent to the Search button; a hidden div will then be rendered below-containing text boxes for all the columns. All assignments that match the filters will be returned. An empty list will be returned if the search criteria don't match any records in the database.

    Implementation

    This part is solely listed within the file "app/assets/javascripts/tree_display.jsx", so we can only implement this part with javascript. The interactive dropdown advanced search code will maintain the same format as "User Advanced Search". By using AdditionalSearchDropDown, DatePicker, and HASQUIZ_TOGGLE components, we build a pop up advanced search functionality in React component FilterableTable.

    1. Searching for courses
      1. The searching method is handled by ContentTable component, which filters out courses' names that match the user's input.

    Due to the similarity of course search and assignment search, they share the same code in FilterableTable component.

    Search for Questionnaires:

    The proposed system will implement search functionality for searching via below criteria:

    1. Keyword within Name of Questionnaire: A text field
    2. Keyword or a string in a single question within a questionnaire: A text field
    3. Course Name: A text field for the course name
    4. Assignment Name: A text field for the assignment

    The user will be able to apply multiple filters at a time and the output of the query will match all the filters applied. If no results are found, an empty list will be returned.

    There will be a default search box of the name of questionnaire as a simple search, and if a user want to apply multiple filters, the user can tap on the "Advanced Search" button which is adjacent to the "Search" button, and a hidden field will be rendered below-containing text boxes for all the columns. All the matched questionnaires will be listed at once.

    Implementation

    This part is solely listed within the file "app/assets/javascripts/tree_display.jsx", so we can only implement this part with javascript. The interactive dropdown advanced search code will maintain the same format as "User Advanced Search."

    1. Getting sub-contents when a user press on a course
      1. The getSubFolderData() from FilterableTable will send HTTP POST request.
      2. After retrieving the data, it will update the state of FilterableTable component.
      3. Once the state is updated, it will trigger an update to ContentTable component and rerender the component.
    2. Searching for questionnaire
      1. The searching method is handled by FilterableTable component. Once the search button is pressed, it filters all the sub-contents from every questionnaire category based on the user input.
      2. handleQuestionnaireSearchChange() in FilterableTable component keeps track of the search input field. It will trigger an update when the input field has been cleared.

    Lo-fi UI Example

    Flowchart

    Test Plan

    Rspec Unit Tests

    Automated tests can be written to test the following functionalities:

    1. Given an unfiltered search result which should show all
    2. Given a filtered search, the result renders a list of objects containing the filtered search item
    3. Given an invalid search, an empty list returns

    RSpec tests will be written to cover the depth of each test point above for all four search objects mentioned in the proposed solution.

    Code Snippet Added

    Before checking the code, here's some preliminary:

    1. We are testing the only function that related to the search function in model/user.rb which is used to output search result
    2. get_user_list(arg1, arg2, arg3), where (arg1, arg2, arg3) represents (userid, full name, email)
    3. For each test, we are trying to find the users with "keyword", that is, if there is user with the keyword in selected field, it should return in the list, otherwise null.
    4. For each test, we also checked the search function with multiple input, that is, with or without either userid, full name or email.
    # spec/models/user_spec.rb
    context 'when current user is super admin and search by user name' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", "", "")).to eq([user1, user2])
          end
        end
    
        context 'when current user is super admin and search by user name' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abcd", "", "")).to eq([])
          end
        end
    
        context 'when current user is super admin and search by user full name' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "abc bbc", "")).to eq([user1, user2])
          end
        end
        context 'when current user is super admin and search by user full name' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "abc bbcd", "")).to eq([])
          end
        end
    
        context 'when current user is super admin and search by user email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "", "abcbbe@gmail.com")).to eq([user2])
          end
        end
    
        context 'when current user is super admin and search by user email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "", "abcbbc@gmail.com")).to eq([user1])
          end
        end
    
        context 'when current user is super admin and search by user email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "", "abcbbcd@gmail.com")).to eq([])
          end
        end
    
        context 'when current user is super admin and search by user name and email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", "", "abcbbc@gmail.com")).to eq([user1])
          end
        end
    
        context 'when current user is super admin and search by user name and email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", "", "abcbbe@gmail.com")).to eq([user2])
          end
        end
    
        context 'when current user is super admin and search by user full name and email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "abc bbc", "abcbbe@gmail.com")).to eq([user2])
          end
        end
    
        context 'when current user is super admin and search by user full name and email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("", "abc bbc", "abcbbc@gmail.com")).to eq([user1])
          end
        end
    
        context 'when current user is super admin and search by user name, full name' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", " bbc", "")).to eq([user1, user2])
          end
        end
    
        context 'when current user is super admin and search by user name, full name' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", "abc bbc", "")).to eq([user1, user2])
          end
        end
    
        context 'when current user is super admin and search by user name, full name and email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", " bbc", "abcbbe@gmail.com")).to eq([user2])
          end
        end
    
        context 'when current user is super admin and search by user name, full name and email' do
          it 'fetches all users with abc' do
            allow(user).to receive_message_chain("role.super_admin?") { true }
            expect(user.get_user_list("abc", "abc bbc", "abcbbc@gmail.com")).to eq([user1])
          end
        end
      end
    

    Manual UI Testing

    UI tests will be performed to reproduce the behavior previously mentioned. These steps were reproduced from the previously proposed solution for this issue. Please pair with our Demo Video to confirm our testing

    Search for User

    1. Log into expertiza to view the home page
    2. Go to Manage > Users
    3. Type the search string in the search box available on the UI and select the column to search for from the dropdown.
    4. To perform a search based on multiple filters, the user can tap on the Advanced Search button adjacent to the Search button, the view renders a hidden div containing text boxes for all the columns, allowing the user to search based on multiple columns.
    5. All the entries that match the specified criteria will be returned.
    6. An empty list is returned if the search criteria don't match any valid records in the database.

    Search for Assignment

    1. Log into expertiza to view the home page
    2. Go to Manage > Assignments
    3. Type the search criteria in the available search criteria and select the appropriate field from the dropdown.
    4. To perform a search based on multiple filters, the user can tap on the Advanced Search button adjacent to the Search button, the view renders a hidden div containing text boxes for all the columns, allowing the user to search based on multiple columns.
    5. All the entries that match the given criteria will be returned.
    6. An empty list is returned if the search criteria don't match any valid records in the database.

    Search for Questionnaire

    1. Log into expertiza to view the home page
    2. Go to Manage > Questionnaires
    3. Type the search criteria in the available search criteria and select the appropriate field from the dropdown.
    4. To perform a search based on multiple filters, the user can tap on the Advanced Search button adjacent to the Search button, the view renders a hidden div containing text boxes for all the columns, allowing the user to search based on multiple columns.
    5. All the entries that match the given criteria will be returned.
    6. An empty list is returned if the search criteria don't match any valid records in the database.

    Resulting Snapshots

    The following screenshots show before and after an advanced search for courses, assignments, and users.

    You can also watch the demo video here

    User Search UI

  • Before Change
  • After Change
  • The first picture shows the page of USER search UI. The second picture shows the USER page that search by userid, name and e-mail. Note that it doesn't necessarily need all parameters to search. One can search with one or two or all parameters.

    Course Search UI

  • Before Change
  • After Change
  • The first picture shows the main page of COURSE searching UI. The second picture shows the searching result that search by created date. Note that it doesn't necessarily need all parameters to search. One can search with one or two or all parameters.

    Assignment Search UI

  • Before Change
  • After Change
  • The first picture shows the main page of ASSIGNMENT searching UI. The second picture shows the searching result that search by updated date. Note that it doesn't necessarily need all parameters to search. One can search with one or two or all parameters.

    Questionnaire Search UI

  • Before Change
  • After Change
  • The first picture shows the main page of questionnaire searching UI. The second picture shows the questionnaire searching page with advance search and detail of review questionnaire. Note that it doesn't necessarily need all parameters to search. One can search with one or two or all parameters.

    Project Mentor

    Ed Gehringer (efg@ncsu.edu)

    Team Members

    Yu-Hsuan Lo (ylo@ncsu.edu)

    Fu-Jen Yen (fyen@ncsu.edu)

    Shao-Yo Chao (schao2@ncsu.edu)

    References

    1. Fall 2019 Design
    2. Fall 2020 Design
    3. Expertiza on GitHub
    4. RSpec Documentation