diff --git a/app/controllers/api/v1/lmss_controller.rb b/app/controllers/api/v1/lmss_controller.rb index 499af77..15e1961 100644 --- a/app/controllers/api/v1/lmss_controller.rb +++ b/app/controllers/api/v1/lmss_controller.rb @@ -1,30 +1,67 @@ module Api module V1 class LmssController < BaseController - before_action :validate_name!, only: [:create] - - def create - render :json => 'not yet implemented'.to_json, status: 501 - end + include CanvasValidationHelper + before_action :validate_ids!, only: [:create] def index - render :json => 'not yet implemented'.to_json, status: 501 + render json: { message: 'not yet implemented'}, status: 501 end def destroy - render :json => 'not yet implemented'.to_json, status: 501 + render json: { message: 'not yet implemented'}, status: 501 end - ## - # Validator definitions. - # TODO: this should be exported to its own (validator) class. - # TODO: this validation should also check the config file for the name of lms's. - # - def validate_name! - if params['name'].blank? - render :json => 'name parameter is required', status: 401 + # POST /courses/:course_id/lmss + def create + course_id = params[:course_id] + lms_id = params[:lms_id] + external_course_id = params[:external_course_id] + + # Ensure that the course and LMS exist + unless Course.exists?(course_id) + render json: { error: 'Course not found' }, status: :not_found + return + end + unless Lms.exists?(lms_id) + render json: { error: 'Lms not found' }, status: :not_found + return + end + # Ensure that the association does not already exist + existing_entry = CourseToLms.find_by(course_id: course_id, lms_id: lms_id, external_course_id: external_course_id) + if existing_entry + render json: { message: 'The association between the specified course and LMS already exists.' }, status: :ok + return + end + # Create the association + course_to_lms = CourseToLms.new( + course_id: course_id, + lms_id: lms_id, + external_course_id: external_course_id + ) + + if course_to_lms.save + render json: course_to_lms, status: :created + else + render json: course_to_lms.errors, status: :unprocessable_entity + end + end + + private + + def validate_ids! + begin + params.require([:course_id, :lms_id, :external_course_id]) + rescue ActionController::ParameterMissing => e + render json: { error: e.message }, status: :bad_request + return + else + unless is_valid_course_id(params[:course_id].to_i) && is_valid_lms_id(params[:lms_id].to_i) + render json: { error: 'Invalid course_id or lms_id' }, status: :bad_request + return + end end end end end -end +end \ No newline at end of file diff --git a/app/helpers/canvas_validation_helper.rb b/app/helpers/canvas_validation_helper.rb index 44009df..99a295d 100644 --- a/app/helpers/canvas_validation_helper.rb +++ b/app/helpers/canvas_validation_helper.rb @@ -19,6 +19,15 @@ def is_valid_lms_id(lmsId) lmsId.is_a?(Integer) && lmsId > 0 end + ## + # Checks if the provided lms id is valid. + # + # @param [Integer] lmsId the lms id to check. + # @return [Boolean] whether the provided id is valid. + def is_valid_lms_id(lmsId) + lmsId.is_a?(Integer) && lmsId > 0 + end + ## # Checks if the provided assignment id is valid. # diff --git a/spec/controllers/api/v1/lmss_controller_spec.rb b/spec/controllers/api/v1/lmss_controller_spec.rb index 19c6c27..9da5084 100644 --- a/spec/controllers/api/v1/lmss_controller_spec.rb +++ b/spec/controllers/api/v1/lmss_controller_spec.rb @@ -2,26 +2,93 @@ module Api module V1 describe LmssController do - let(:mock_course_id) { 16 } - let(:mock_course_name) { 'testCourseName' } - describe 'create' do - it 'throws a 501 error' do - post :create, params: { - course_id: :mock_course_id, - name: :mock_course_name, - } - expect(response.status).to eq(501) + def json_response + JSON.parse(response.body) + end + + before do + # Manually create a course and LMS in the database + @course = Course.create!(course_name: "Mock CS169 Course") + @lms = Lms.create!(lms_name: "Mock Canvas", use_auth_token: true) + @external_course_id = "mock_external_course_id" + end + + after do + # Clean up the specifically created data + CourseToLms.delete_all + Course.delete_all + Lms.delete_all + end + + describe 'POST #create' do + + context 'when lms_id is missing' do + it 'returns status :bad_request' do + post :create, params: { course_id: @course.id, external_course_id: @external_course_id} + expect(response).to have_http_status(:bad_request) + expect(response.body).to include('param is missing or the value is empty: lms_id') + end + end + + context 'when course_id and lms_id are not invalid' do + it 'returns status :bad_request' do + post :create, params: { course_id: '-1', lms_id: '-1', external_course_id: @external_course_id } + expect(response).to have_http_status(:bad_request) + expect(response.body).to include('Invalid course_id or lms_id') + end + end + + context 'when valid parameters are provided' do + it 'creates a new course_to_lms association and returns status :created' do + post :create, params: { course_id: @course.id, lms_id: @lms.id, external_course_id: @external_course_id} + expect(response).to have_http_status(:created) + expect(json_response['course_id']).to eq(@course.id) + expect(json_response['lms_id']).to eq(@lms.id) + end + end + context 'when course_to_lms fails to save' do + it 'returns status :unprocessable_entity' do + allow_any_instance_of(CourseToLms).to receive(:save).and_return(false) + post :create, params: { course_id: @course.id, lms_id: @lms.id, external_course_id: @external_course_id} + expect(response).to have_http_status(:unprocessable_entity) + end + end + + context 'when course does not exist' do + it 'returns status :not_found' do + # Ensure that the course does not exist + selected_course = Course.find_by(id: @course.id) + selected_course.destroy if selected_course + post :create, params: { course_id: @course.id, lms_id: @lms.id, external_course_id: @external_course_id} + expect(response).to have_http_status(:not_found) + expect(response.body).to include('Course not found') + end end - it 'throws a 401 error if the name is not specified' do - post :create, params: { - course_id: :mock_course_id, - } - expect(response.status).to eq(401) - expect(response.body).to eq('name parameter is required') + context 'when lms does not exist' do + it 'returns status :not_found' do + # Ensure that the LMS does not exist + selected_lms = Lms.find_by(id: @lms.id) + selected_lms.destroy if selected_lms + + post :create, params: { course_id: @course.id, lms_id: 1, external_course_id: @external_course_id} + expect(response).to have_http_status(:not_found) + expect(response.body).to include('Lms not found') + end + end + + context 'when the association already exists' do + it 'returns status :ok' do + CourseToLms.create!(course_id: @course.id, lms_id: @lms.id, external_course_id: @external_course_id) + post :create, params: { course_id: @course.id, lms_id: @lms.id, external_course_id: @external_course_id} + expect(response).to have_http_status(:ok) + expect(response.body).to include('The association between the specified course and LMS already exists.') + end end end + + describe 'index' do it 'throws a 501 error' do get :index, params: { course_id: :mock_course_id }