Skip to content

Commit

Permalink
Final workflow (#47)
Browse files Browse the repository at this point in the history
* modified extensions_controller for extension setup flow

* fixed extensions_controller_spec.rb

* updated extensions_controller_spec.rb as per extensions_controller

* fixed routes for extensions_controller_spec.rb

* Add models for course_to_lms

* Implement creating association in course_to_lms

* Test for creating association in course_to_lms

* correcting rspec for extensions controller

* testing of api call completed

* quick typo fix

* added space in schema for canvas data

* Replace the external_course_id from courses table to course_to_lmss table

* More detailed extensions req, still needs more

* Take external_course_id into consideration

* I think set up correctly, needs rest of models to test

* Adjust Assignment Table, which should rely on course_to_lms instead of only lms

* Add assignment model

* Implement route of create in assignment controller

* Add course, lms and course_to_lms model for Assignment Controller test

* Add test for create in assignment controller

* Refactor to pass the Codeclimate

* Refactor the controller, by adding intger validation and putting 
ender from helper function to create function

* test coverage badge update

* test coverage badge update 2

* code climate yml file updated

* code climate yml file updated 2

* badge fix to linux

* added codeclimate test reporter

* added gems

* simple cov version downgraded

* simplecov v17

* secret added

* secret added2

* secret added3

* secret added4

* initial changes to create user

* drafted

* validation email added

* chnages added: new+save, has many asso for extension

* Merge latest main into feature branch and resolve conflict

* Refactor the controller and add integer validation

* tests pass. finally.

* improving test coverage

* slightly clarified tests

* remove render json of strings

* Fix potential issue in  lmss_controller

* Fix minor issue based on pr comments

* Add one test to reach a full LOC test coverage

* starting to refactor

* further refactoring

* fixing everything that broke because someone decided to change the schema without telling anyone else...

* everything works for demo

* fixing failing tests due to prev updates

* missed one merge

* including validation helper

* fixed comments as per PR46 (except line 30 of extensions_controller_spec, idk why it errors when I try to update those hashes to new syntax)

* fix: ensure test succeed

* style: format for readability

---------

Co-authored-by: zee6197 <[email protected]>
Co-authored-by: Zzz212zzZ <[email protected]>
Co-authored-by: Sepehr Behmanesh Fard <[email protected]>
Co-authored-by: Connor Bernard <[email protected]>
  • Loading branch information
5 people authored Apr 30, 2024
1 parent cd1ed11 commit 601a5c7
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 107 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,5 @@ yarn-debug.log*
/config/master.key

/config/credentials/production.key

.DS_Store
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ group :test do
gem 'cucumber-rails-training-wheels'
gem 'database_cleaner'
gem 'timecop'
gem 'webmock'
end

group :development do
Expand Down
10 changes: 10 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ GEM
coderay (1.1.3)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
crack (1.0.0)
bigdecimal
rexml
crass (1.0.6)
cucumber (9.1.2)
builder (~> 3.2, >= 3.2.4)
Expand Down Expand Up @@ -176,6 +179,7 @@ GEM
guard (~> 2.1)
guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0)
hashdiff (1.1.0)
httparty (0.21.0)
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
Expand Down Expand Up @@ -310,6 +314,7 @@ GEM
regexp_parser (2.9.0)
reline (0.4.2)
io-console (~> 0.5)
rexml (3.2.6)
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
Expand Down Expand Up @@ -376,6 +381,10 @@ GEM
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webmock (3.23.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.8.1)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
Expand Down Expand Up @@ -423,6 +432,7 @@ DEPENDENCIES
turbo-rails
tzinfo-data
web-console
webmock

RUBY VERSION
ruby 3.3.0p0
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/api/v1/assignments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ module Api
module V1
class AssignmentsController < ApplicationController
include CanvasValidationHelper

before_action :validate_ids!, only: [:create]
skip_before_action :verify_authenticity_token

def index
render json: { message: 'not yet implemented'} , status: 501
Expand All @@ -12,7 +14,6 @@ def index
def create
# Check if the course_to_lms association exists
course_to_lms = CourseToLms.find_by(course_id: params[:course_id], lms_id: params[:lms_id])

unless course_to_lms
render json: { error: 'No such Course_LMS association' }, status: :not_found
return
Expand All @@ -23,7 +24,6 @@ def create
render json: { message: 'Record already exists' }, status: :ok
return
end

# Create and render the assignment
assignment = Assignment.new(course_to_lms_id: course_to_lms.id, name: params[:name], external_assignment_id: params[:external_assignment_id])
if assignment.save
Expand Down
69 changes: 61 additions & 8 deletions app/controllers/api/v1/extensions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,71 @@
module Api
module V1
class ExtensionsController < BaseController
def create
render :json => 'not yet implemented'.to_json, status: 501
end

before_action :set_facade

def index
render :json => 'not yet implemented'.to_json, status: 501
render json: { message: 'not yet implemented'}, status: 501
end

def create
find_extension_params
# Get External Assignment object to find initial due date
assignment_response = @canvas_facade.get_assignment(
@course_to_lms.external_course_id.to_i,
@assignment.external_assignment_id.to_i,
)
if (assignment_response.status != 200)
render json: assignment_response.to_json, status: 500
return
end
assignment_json = JSON.parse(assignment_response.body)

# Provision Extension
response = @canvas_facade.provision_extension(
@course_to_lms.external_course_id.to_i,
params[:student_uid].to_i,
@assignment.external_assignment_id.to_i,
params[:new_due_date],
)
if !response.success?
render json: response.body, status: response.status
return
end
assignment_override = JSON.parse(response.body)

@extension = Extension.new(
assignment_id: @assignment.id,
student_email: nil,
initial_due_date: assignment_json["due_at"],
new_due_date: assignment_override["due_at"],
external_extension_id: assignment_override["id"],
last_processed_by_id: nil,
)
if !@extension.save
render json: {"error": "Extension requested, but local save failed"}.to_json, status: 500
return
end
render json: @extension.to_json, status: 200
end

def destroy
render :json => 'not yet implemented'.to_json, status: 501
render json: { message: 'not yet implemented'}, status: 501
end

private

def set_facade
Rails.logger.info "Using CANVAS_URL: #{ENV['CANVAS_URL']}"
# not sure if auth key will be in the request headers or in cookie
@canvas_facade = CanvasFacade.new(request.headers['Authorization'])
end

def find_extension_params
@lms = Lms.find(params[:lms_id])
@course = Course.find(params[:course_id])
@assignment = Assignment.find(params[:assignment_id])
@course_to_lms = CourseToLms.find(@assignment.course_to_lms_id)
end

end
end
end
end
13 changes: 7 additions & 6 deletions app/facades/canvas_facade.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,13 @@ def get_assignment_overrides(courseId, assignmentId)
# @return [Faraday::Response] information about the new override.
def create_assignment_override(courseId, assignmentId, studentIds, title, dueDate, unlockDate, lockDate)
@canvasApi.post("courses/#{courseId}/assignments/#{assignmentId}/overrides", {
student_ids: studentIds,
title: title,
due_at: dueDate,
unlock_at: unlockDate,
lock_at: lockDate,
assignment_override: {
student_ids: studentIds,
title: title,
due_at: dueDate,
unlock_at: unlockDate,
lock_at: lockDate,
}
})
end

Expand Down Expand Up @@ -143,7 +145,6 @@ def provision_extension(courseId, studentId, assignmentId, newDueDate)
get_current_formatted_time(),
newDueDate,
)

# Either successful or error that is not explicitly handled here.
if (createOverrideResponse.status != 400)
return createOverrideResponse
Expand Down
9 changes: 8 additions & 1 deletion app/models/extension.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# assignment_id: foreign key to local assignment
# student_email: requires another api request to find student data (sid is given in first response). This currently doesn't exist in CanvasFacade
# initial_due_date: also requires an api request to find assignment data (assignment id is given in first response)
# Note that the assignment.due_at shows the due date as it is for whoever's logged in (which if it's a teacher, should be the original due date) but the actual original due date is never saved anywhere
# new_due_date:
# external_extension_id:
# last_processed_by_id: Requires login/sessions to be properly implemented
class Extension < ApplicationRecord
#Relationship with Assignment
belongs_to :assignment

#Relationship with User
has_one :user
end
end
2 changes: 2 additions & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,6 @@

# Raise error when a before_action's only/except options reference missing actions
config.action_controller.raise_on_missing_callback_actions = true

config.hosts << "flextensions.lvh.me:3000"
end
48 changes: 11 additions & 37 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,7 @@

canvas = Lms.create!({
lms_name: "Canvas",
use_auth_token: true
})


test_assignment = Assignment.create!({
lms_id: canvas.id,
name: "Test Assignment",
external_assignment_id: "11111"
use_auth_token: true,
})


Expand All @@ -37,7 +30,13 @@
test_course_to_lms = CourseToLms.create!({
lms_id: canvas.id,
course_id: test_course.id,
external_course_id: "22222"
external_course_id: "22222",
})

test_assignment = Assignment.create!({
course_to_lms_id: test_course_to_lms.id,
name: "Test Assignment",
external_assignment_id: "11111",
})

test_user = User.create!({
Expand All @@ -47,7 +46,7 @@
test_user_to_course = UserToCourse.create!({
user_id: test_user.id,
course_id: test_course.id,
role: "test"
role: "test",
})

test_extension = Extension.create!({
Expand All @@ -56,37 +55,12 @@
initial_due_date: DateTime.iso8601('2024-04-20'),
new_due_date: DateTime.iso8601('2024-04-30'),
last_processed_by_id: test_user.id,
external_extension_id: "33333"
external_extension_id: "33333",
})

test_lms_credential = LmsCredential.create!({
user_id: test_user.id,
lms_name: "canvas",
token: "test token",
external_user_id: "44444"
})

real_course = Course.create!({
course_name: "CS169L Flextension",
})

real_course_to_lms = CourseToLms.create!({
lms_id: canvas.id,
course_id: real_course.id,
external_course_id: "1534405"
external_user_id: "44444",
})

real_assignment = Assignment.create!({
lms_id: canvas.id,
name: "Seed Data Testing",
external_assignment_id: "8741483"
})

real_extension = Extension.create!({
assignment_id: real_assignment.id,
student_email: "[email protected]",
initial_due_date: DateTime.iso8601('2024-04-20'),
new_due_date: DateTime.iso8601('2024-04-27'),
last_processed_by_id: test_user.id,
external_extension_id: "270163"
})
4 changes: 2 additions & 2 deletions spec/Facades/canvas_facade_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,13 @@
it 'has correct request body' do
expect(conn).to receive(:post).with(
createAssignmentOverrideUrl,
{
{ assignment_override: {
student_ids: [mockStudentId],
title: mockTitle,
due_at: mockDate,
unlock_at: mockDate,
lock_at: mockDate,
}
}}
)

facade.create_assignment_override(
Expand Down
12 changes: 8 additions & 4 deletions spec/controllers/api/v1/assignments_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ def json_response
end

after do
Assignment.delete_all
CourseToLms.delete_all
Course.delete_all
Lms.delete_all
LmsCredential.destroy_all
Extension.destroy_all
Assignment.destroy_all
CourseToLms.destroy_all
UserToCourse.destroy_all
Course.destroy_all
Lms.destroy_all
User.destroy_all
end

describe "GET /api/v1/courses/:course_id/lmss/:lms_id/assignments" do
Expand Down
12 changes: 6 additions & 6 deletions spec/controllers/api/v1/courses_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@ module V1
describe 'POST #create' do
context "when the new course is successfully created" do
let(:course_name) { "New Course" }

it "creates and saves a new course" do
post :create, params: { course_name: course_name }

expect(response).to have_http_status(:created)
expect(Course.find_by(course_name: course_name)).to be_present
expect(flash[:success]).to eq("Course created successfully")
expect(JSON.parse(response.body)['course_name']).to eq('New Course')
end
end

context "when a course with the same name already exists" do
let!(:existing_course) { Course.create(course_name: "Existing Course") }

it "does not create a new course with the same name and returns an error" do
post :create, params: { course_name: existing_course.course_name }

expect(Course.find_by(course_name: existing_course.course_name)).to be_present
expect(response).to have_http_status(:unprocessable_entity)
expect(JSON.parse(response.body)).to eq({ "message" => "A course with the same course name already exists." })
Expand All @@ -45,7 +45,7 @@ module V1

describe 'add_user' do
let(:test_course) { Course.create(course_name: "Test Course") }
let(:test_user) { User.create(email: "testuser@example.com") }
let(:test_user) { User.create!(email: "testuniqueuser@example.com") }

context "Provided parameters are valid" do
it "adds an existing user to an existing course" do
Expand Down
Loading

0 comments on commit 601a5c7

Please sign in to comment.