|
|
(7 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
| '''E2321. Reimplement QuestionnairesController and QuestionsController'''
| |
|
| |
|
| ==Problem Statement==
| |
| The questionnaire is the superclass for all kinds of questionnaires and rubrics. Rubrics are used for evaluating submissions and teammate contributions, as well as taking quizzes and surveys, and all of these are subclasses of the Questionnaire class. In Expertiza, various types of questionnaires can be created, such as the Survey Questionnaire, Author Feedback Questionnaire, Bookmark Rating Questionnaire, Metareview Questionnaire, Quiz Questionnaire, Review Questionnaire, and Teammate Review Questionnaire. Each of these questionnaires can have zero or more questions, which are represented by the Question class. Typically, a questionnaire is associated with an assignment using the Assignment class.
| |
|
| |
| The Questionnaire Controller is responsible for performing CRUD (Create, Read, Update, Delete) operations, such as copying and viewing questionnaires. On the other hand, the Questions Controller is responsible for creating, modifying, and deleting individual questions within a questionnaire. Questions can come in various types, such as checkboxes, multiple choice, text boxes, and more. However, each question object will always belong to a particular questionnaire. However, the current implementation suffers from several issues, such as mixing the responsibilities of the two controllers, using methods with identical names for different functionalities, and unclear or unused functionalities. Therefore, to improve the code quality and functionality, the two controllers should be implemented separately and adhere to the CRUD operations as much as possible. Additionally, the code needs to be refactored and optimized for better performance, and unused or unclear methods should be discarded. Finally, comprehensive tests should be written to ensure that the code is functioning correctly and free of code smells.
| |
|
| |
|
| |
| ==Goals of this Project==
| |
| The goals of this Project are:
| |
|
| |
| *Separating the responsibilities of the Questionnaire Controller and Questions Controller:
| |
| The first step is to write controllers for the Questionnaires and Questions, which will be responsible for creating, modifying, and deleting questions. The Questionnaire Controller will only be responsible for CRUD operations related to questionnaires.
| |
| *Fix bugs in the existing functionality:
| |
| Delete questionnaire option not working, redirect to the view page after creation of a questionnaire, Update questionnaire not working for updating parameters of the questionnaire and update not working on questionnaire if it has zero questions.
| |
| *Implementing CRUD operations for each controller:
| |
| Each controller should have only CRUD operations as far as possible. The Questionnaire Controller should have methods for creating, updating, deleting, and viewing questionnaires. Similarly, the Questions Controller should have methods for creating, updating, deleting, and viewing questions.
| |
| *Improving the clarity and conciseness of code:
| |
| The code should be written in a clean and concise manner. Methods with identical names that perform different functionalities should be renamed for clarity. Functions or functionality that are not clear should be commented on or removed. Any loops or methods that can be refactored for better performance should be addressed e.g. delete all questions that belong to a questionnaire
| |
| *Discarding unused or unclear functionality:
| |
| Any unused or unclear functionality should be removed from the controllers. This will help to reduce complexity and make the code easier to maintain.-
| |
| *Writing tests for the two controllers:
| |
| Tests should be written for both the Questionnaire Controller and the Questions Controller. The tests should cover at least 80% of the code, and tools like Rubocop and Code Climate should be used to verify code smells.
| |
|
| |
| By achieving these goals, both the controllers can have their basic CRUD functionalities as well as it will also ensure that the code readability and functionality of the code for the two controllers is increased. It will also help in resolving the existing bugs which will increase correctness of the code.
| |
|
| |
|
| |
| ==Initial code of Questionnaire and Questions Controller==
| |
|
| |
| 1. Questionnaire Controller
| |
| [[File:Questionnaire_Initial_1.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_2.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_3.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_4.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_5.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_6.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_7.png|center|border|500px|]]
| |
| [[File:Questionnaire_Initial_8.png|center|border|500px|]]
| |
|
| |
| 2. Question Controller
| |
| [[File:Question_Initial_1.png|center|border|500px|]]
| |
| [[File:Question_Initial_2.png|center|border|500px|]]
| |
| [[File:Question_Initial_3.png|center|border|500px|]]
| |
|
| |
| ==Proposed Changes==
| |
|
| |
| *Solution: - Separating the responsibilities of the Questionnaire Controller and Questions Controller:
| |
| [[File:add_new_questions.png|center|border|500px|]]
| |
| Initially the add_new_questions method present in questionnaire controller was responsible for adding a new question for the given questionnaire. As questions controller is responsible for creating a question, we defined a create method in questions controller which is responsible for the adding a new question for a given questionnaire. Since, to link a question to a questionnaire, we passed questionnaire id using params and linked a new question created with the help of create method in questions controller to the required questionnaire and thus separated their responsibilities.
| |
| [[File:create_question.png|center|border|500px|]]
| |
|
| |
| *Solution: - Implementing CRUD operations for each controller:
| |
| After separating the functionalities of the two controller, the CRUD operations for each controller are :-
| |
| 1. Questionnaire Controller -
| |
| [[File:Questionnaire_Final_1.png|center|border|500px|]]
| |
| [[File:Questionnaire_Final_2.png|center|border|500px|]]
| |
| [[File:Questionnaire_Final_3.png|center|border|500px|]]
| |
| [[File:Questionnaire_Final_4.png|center|border|500px|]]
| |
|
| |
| 2. Question Controller -
| |
| [[File:Question_Final_1.png|center|border|500px|]]
| |
| [[File:Question_Final_2.png|center|border|500px|]]
| |
| [[File:Question_Final_3.png|center|border|500px|]]
| |
|
| |
| *Solution:- Discarding unused or unclear functionality:
| |
| Removing unused or unclear functionality-
| |
| After checking all the existing functionalities following code were unused or unclear and hence were removed from the reimplemented controller code.
| |
|
| |
| **create_questionnaire method of questionnaire controller -
| |
|
| |
| def create_questionnaire
| |
| @questionnaire = Object.const_get(params[:questionnaire][:type]).new(questionnaire_params)
| |
| # Create Quiz content has been moved to Quiz Questionnaire Controller
| |
| if @questionnaire.type != 'QuizQuestionnaire' # checking if it is a quiz questionnaire
| |
| @questionnaire.instructor_id = Ta.get_my_instructor(session[:user].id) if session[:user].role.name == 'Teaching Assistant'
| |
| save
| |
|
| |
| redirect_to controller: 'tree_display', action: 'list'
| |
| end
| |
| end
| |
|
| |
| Create method defined in the questionnaire controller creates a new controller hence the method create_questionnaire was unused.
| |
|
| |
| **save_all_questions method in questionnaire controller
| |
| All the questions in the questionnaire were saved with the help of update in questionnaire controller. Hence, the use of save_all_questions is unclear.
| |
|
| |
|
| |
| def save_all_questions
| |
| questionnaire_id = params[:id]
| |
| begin
| |
| if params[:save]
| |
| params[:question].each_pair do |k, v|
| |
| @question = Question.find(k)
| |
| # example of 'v' value
| |
| # {"seq"=>"1.0", "txt"=>"WOW", "weight"=>"1", "size"=>"50,3", "max_label"=>"Strong agree", "min_label"=>"Not agree"}
| |
| v.each_pair do |key, value|
| |
| @question.send(key + '=', value) unless @question.send(key) == value
| |
| end
| |
|
| |
| @question.save
| |
| flash[:success] = 'All questions have been successfully saved!'
| |
| end
| |
| end
| |
| rescue StandardError
| |
| flash[:error] = $ERROR_INFO
| |
| end
| |
|
| |
| if params[:view_advice]
| |
| redirect_to controller: 'advice', action: 'edit_advice', id: params[:id]
| |
| elsif questionnaire_id
| |
| redirect_to edit_questionnaire_path(questionnaire_id.to_sym)
| |
| end
| |
| end
| |
|
| |
| ** save method, delete_question method, save_new_question method and save method
| |
| question associated to a controller is deleted with the help of destroy method in question controller, hence the delete_question method is unused.
| |
| All the save methods use is unclear.
| |
|
| |
| def save
| |
| @questionnaire.save!
| |
| save_questions @questionnaire.id unless @questionnaire.id.nil? || @questionnaire.id <= 0
| |
| undo_link("Questionnaire \"#{@questionnaire.name}\" has been updated successfully. ")
| |
| end
| |
|
| |
| # save questions that have been added to a questionnaire
| |
| def save_new_questions(questionnaire_id)
| |
| if params[:new_question]
| |
| # The new_question array contains all the new questions
| |
| # that should be saved to the database
| |
| params[:new_question].keys.each_with_index do |question_key, index|
| |
| q = Question.new
| |
| q.txt = params[:new_question][question_key]
| |
| q.questionnaire_id = questionnaire_id
| |
| q.type = params[:question_type][question_key][:type]
| |
| q.seq = question_key.to_i
| |
| if @questionnaire.type == 'QuizQuestionnaire'
| |
| # using the weight user enters when creating quiz
| |
| weight_key = "question_#{index + 1}"
| |
| q.weight = params[:question_weights][weight_key.to_sym]
| |
| end
| |
| q.save unless q.txt.strip.empty?
| |
| end
| |
| end
| |
| end
| |
|
| |
| # delete questions from a questionnaire
| |
| # @param [Object] questionnaire_id
| |
| def delete_questions(questionnaire_id)
| |
| # Deletes any questions that, as a result of the edit, are no longer in the questionnaire
| |
| questions = Question.where('questionnaire_id = ?', questionnaire_id)
| |
| @deleted_questions = []
| |
| questions.each do |question|
| |
| should_delete = true
| |
| unless question_params.nil?
| |
| params[:question].each_key do |question_key|
| |
| should_delete = false if question_key.to_s == question.id.to_s
| |
| end
| |
| end
| |
|
| |
| next unless should_delete
| |
|
| |
| question.question_advices.each(&:destroy)
| |
| # keep track of the deleted questions
| |
| @deleted_questions.push(question)
| |
| question.destroy
| |
| end
| |
| end
| |
|
| |
| # Handles questions whose wording changed as a result of the edit
| |
| # @param [Object] questionnaire_id
| |
| def save_questions(questionnaire_id)
| |
| delete_questions questionnaire_id
| |
| save_new_questions questionnaire_id
| |
|
| |
| if params[:question]
| |
| params[:question].keys.each do |question_key|
| |
| if params[:question][question_key][:txt].strip.empty?
| |
| # question text is empty, delete the question
| |
| Question.delete(question_key)
| |
| else
| |
| # Update existing question.
| |
| question = Question.find(question_key)
| |
| Rails.logger.info(question.errors.messages.inspect) unless question.update_attributes(params[:question][question_key])
| |
| end
| |
| end
| |
| end
| |
| end
| |
|
| |
|
| |
|
| |
| *Solution:- Writing tests for the two controllers:
| |
| 1. Questionnaire Controller
| |
|
| |
| #Tests for Questionnaire Controller
| |
|
| |
| require 'swagger_helper'
| |
|
| |
| RSpec.describe 'Questionnaire API', type: :request do
| |
|
| |
| path '/api/v1/questionnaire' do
| |
| get('list questionnaires') do
| |
| tags 'Questionnaires'
| |
| produces 'application/json'
| |
|
| |
| response(200, 'successful') do
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| let(:questionnaire) { { name: '', min_question_score: 1, max_question_score: 5,type: "" } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
|
| |
| post('create questionnaire')do
| |
| tags 'Questionnaires'
| |
| consumes 'application/json'
| |
| parameter name: :questionnaire, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| name: { type: :string },
| |
| type: { type: :string },
| |
| min_question_score: { type: :integer },
| |
| max_question_score: { type: :integer }
| |
| },
| |
| required: [ 'name', 'type', 'min_question_score', 'max_question_score' ]
| |
| }
| |
|
| |
| response(201, 'Created a questionnaire') do
| |
| let(:questionnaire) { { name: 'Questionnaire 1', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| let(:questionnaire) { { name: '', type: 'AuthorFeedbackQuestionnaire',min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
| end
| |
|
| |
|
| |
| path '/api/v1/questionnaires/{id}' do
| |
| parameter name: 'id', in: :path, type: :integer, description: 'ID of the questionnaire'
| |
|
| |
| get('show questionnaire') do
| |
| tags 'Questionnaires'
| |
| consumes 'application/json'
| |
| produces 'application/json'
| |
| parameter name: :questionnaire, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| name: { type: :string },
| |
| private: { type: :boolean },
| |
| instructor_id: { type: :integer },
| |
| min_question_score: { type: :integer },
| |
| max_question_score: { type: :integer },
| |
| type: { type: :string },
| |
| display_type: { type: :string },
| |
| instruction_loc: { type: :string },
| |
| created_at: { type: :string, format: :date_time },
| |
| updated_at: { type: :string, format: :date_time }
| |
| }
| |
| required: [ 'name', 'type', 'min_question_score', 'max_question_score' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:id) { questionnaire.id }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
|
| |
| run_test!
| |
| end
| |
|
| |
| response(404, 'questionnaire not found') do
| |
| let(:id) { -1 }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
|
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
|
| |
|
| |
| patch('update questionnaire') do
| |
| tags 'Questionnaires'
| |
| consumes 'application/json'
| |
| parameter name: :questionnaire, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| name: { type: :string },
| |
| private: { type: :boolean },
| |
| instructor_id: { type: :integer },
| |
| min_question_score: { type: :integer },
| |
| max_question_score: { type: :integer },
| |
| type: { type: :string },
| |
| display_type: { type: :string },
| |
| instruction_loc: { type: :string },
| |
| created_at: { type: :string, format: :date_time },
| |
| updated_at: { type: :string, format: :date_time }
| |
| }
| |
| required: [ 'name', 'type', 'min_question_score', 'max_question_score' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:id) { Questionnaire.create({ name: 'Questionnaire150', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } ).id }
| |
| let(:questionnaire) { { name: 'Questionnaire100', type: 'AuthorFeedbackQuestionnaire',min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| let(:id) { Questionnaire.create({ name: 'Questionnaire150', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } ).id }
| |
| let(:questionnaire) { { name: '', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
| put('update questionnaire') do
| |
| tags 'Questionnaires'
| |
| consumes 'application/json'
| |
| parameter name: :questionnaire, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| name: { type: :string },
| |
| private: { type: :boolean },
| |
| instructor_id: { type: :integer },
| |
| min_question_score: { type: :integer },
| |
| max_question_score: { type: :integer },
| |
| type: { type: :string },
| |
| display_type: { type: :string },
| |
| instruction_loc: { type: :string },
| |
| created_at: { type: :string, format: :date_time },
| |
| updated_at: { type: :string, format: :date_time }
| |
| }
| |
| required: [ 'name', 'type', 'min_question_score', 'max_question_score' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:id) { Questionnaire.create({ name: 'Questionnaire100', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } ).id }
| |
|
| |
| let(:questionnaire) { { name: 'Questionnaire101', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| let(:id) { Questionnaire.create({ name: 'Questionnaire150', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } ).id }
| |
| let(:questionnaire) { { name: '', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
|
| |
| delete('delete Questionnaire') do
| |
| tags 'Questionnaires'
| |
| response(200, 'successful') do
| |
| let(:id) { '123' }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(404, 'not found') do
| |
| let(:id) { 'invalid_id' }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
| end
| |
|
| |
| path '/api/v1/questionnaires/copy/{id}' do
| |
| post('copy questionnaire') do
| |
| tags 'Questionnaires'
| |
| consumes 'application/json'
| |
| parameter name: :questionnaire, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| name: { type: :string },
| |
| type: { type: :string },
| |
| private: { type: :boolean },
| |
| min_question_score: { type: :integer },
| |
| max_question_score: { type: :integer }
| |
| },
| |
| required: [ 'name', 'type', 'min_question_score', 'max_question_score' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:questionnaire) { { name: 'Questionnaire 1', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(500, 'server error') do
| |
| let(:questionnaire) { { name: 'Questionnaire 1', type: 'AuthorFeedbackQuestionnaire', min_question_score: 1, max_question_score: 5 } }
| |
|
| |
| before do
| |
| allow(Questionnaire).to receive(:copy_questionnaire_details).and_raise(StandardError)
| |
| end
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
|
| |
|
| |
|
| |
| end
| |
| end
| |
|
| |
| 2. Question Controller
| |
|
| |
| #Tests for Question Controller
| |
|
| |
| require 'swagger_helper'
| |
|
| |
| RSpec.describe 'Question API', type: :request do
| |
|
| |
| path '/api/v1/question' do
| |
| get('list questions') do
| |
| tags 'Questions'
| |
| produces 'application/json'
| |
|
| |
| response(200, 'successful') do
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| #need to check and update this
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
| post('create question') do
| |
| tags 'Questions'
| |
| consumes 'application/json'
| |
| parameter name: :question, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| question: {
| |
| type: :object,
| |
| properties: {
| |
| txt: { type: :string },
| |
| weight: { type: :integer },
| |
| questionnaire_id: { type: :integer },
| |
| seq: { type: :string },
| |
| size: { type: :string },
| |
| alternatives: { type: :string },
| |
| break_before: { type: :boolean },
| |
| max_label: { type: :string },
| |
| min_label: { type: :string },
| |
| type: { type: :string },
| |
| },
| |
| required: ['type' ]
| |
| }
| |
| },
| |
| required: [ 'question' ]
| |
| }
| |
|
| |
| response(201, 'Created a question') do
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'Invalid request') do
| |
| let(:question) { { question: { txt: '', questionnaire_id: 692, seq: '9.0', type: 'Dropdown' } } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
| end
| |
|
| |
| path '/api/v1/questions/{id}' do
| |
| parameter name: 'id', in: :path, type: :integer, description: 'ID of the question'
| |
|
| |
| get('show question') do
| |
| tags 'Questions'
| |
| consumes 'application/json'
| |
| parameter name: :question, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| question: {
| |
| type: :object,
| |
| properties: {
| |
| txt: { type: :string },
| |
| weight: { type: :integer },
| |
| questionnaire_id: { type: :integer },
| |
| seq: { type: :string },
| |
| size: { type: :string },
| |
| alternatives: { type: :string },
| |
| break_before: { type: :boolean },
| |
| max_label: { type: :string },
| |
| min_label: { type: :string },
| |
| type: { type: :string },
| |
| },
| |
| required: ['type' ]
| |
| }
| |
| },
| |
| required: [ 'question' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:id) { question.id }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
|
| |
| run_test!
| |
| end
| |
|
| |
| response(404, 'question not found') do
| |
| let(:id) { -1 }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
|
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
|
| |
| patch('update question') do
| |
| tags 'Questions'
| |
| consumes 'application/json'
| |
| parameter name: :question, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| question: {
| |
| type: :object,
| |
| properties: {
| |
| txt: { type: :string },
| |
| weight: { type: :integer },
| |
| questionnaire_id: { type: :integer },
| |
| seq: { type: :string },
| |
| size: { type: :string },
| |
| alternatives: { type: :string },
| |
| break_before: { type: :boolean },
| |
| max_label: { type: :string },
| |
| min_label: { type: :string },
| |
| type: { type: :string },
| |
| },
| |
| required: ['type' ]
| |
| }
| |
| },
| |
| required: [ 'question' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: nil } } }
| |
|
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(404, 'question not found') do
| |
| let(:question) { { id: -1, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
|
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
| put('update question') do
| |
| tags 'Questions'
| |
| consumes 'application/json'
| |
| parameter name: :question, in: :body, schema: {
| |
| type: :object,
| |
| properties: {
| |
| id: { type: :integer },
| |
| question: {
| |
| type: :object,
| |
| properties: {
| |
| txt: { type: :string },
| |
| weight: { type: :integer },
| |
| questionnaire_id: { type: :integer },
| |
| seq: { type: :string },
| |
| size: { type: :string },
| |
| alternatives: { type: :string },
| |
| break_before: { type: :boolean },
| |
| max_label: { type: :string },
| |
| min_label: { type: :string },
| |
| type: { type: :string },
| |
| },
| |
| required: ['type' ]
| |
| }
| |
| },
| |
| required: [ 'question' ]
| |
| }
| |
|
| |
| response(200, 'successful') do
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(422, 'invalid request') do
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: nil } } }
| |
|
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(404, 'question not found') do
| |
| let(:question) { { id: -1, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
|
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
| delete('delete Question') do
| |
| tags 'Questions'
| |
| response(200, 'successful') do
| |
| let(:question) { { id: 6, question: { txt: 'This is a test', weight: 1, questionnaire_id: 692, seq: '9.0', size: nil, alternatives: nil, break_before: true, max_label: nil, min_label: nil, type: 'Dropdown' } } }
| |
| let(:id) { question.id }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
|
| |
| response(404, 'not found') do
| |
| let(:id) { 'invalid_id' }
| |
|
| |
| after do |example|
| |
| example.metadata[:response][:content] = {
| |
| 'application/json' => {
| |
| example: JSON.parse(response.body, symbolize_names: true)
| |
| }
| |
| }
| |
| end
| |
| run_test!
| |
| end
| |
| end
| |
|
| |
|
| |
|
| |
| end
| |
|
| |
| end
| |
|
| |
|
| |
| == Relevant Links ==
| |
| * '''Github Repository:'''
| |
| * '''Pull Request:'''
| |
| * '''VCL Server:'''
| |
|
| |
| ==Contributors==
| |
| This feature was created as part of Dr. Edward Gehringer's "CSC/ECE 517: Object-Oriented Design and Development" class, Spring 2023. The contributors were: Vineet Vimal Chheda, Rohan Shah, and Aditya Srivastava. Our project mentor was Ankur Mundra (amundra@ncsu.edu)
| |