add observer alert threshold CRUD
closes MBL-10122 test plan: - do CRUD operations on the observer_alert_threshold endpoints /users/<id>/observer_alert_threshold[?student_id=<id>] and /users/<id>/observer_alert_threshold/<id> Change-Id: I2c5c7700adaedd4a2068a61568217219b763339e Reviewed-on: https://gerrit.instructure.com/149147 Reviewed-by: Matthew Sessions <msessions@instructure.com> Product-Review: Matthew Sessions <msessions@instructure.com> QA-Review: Matthew Sessions <msessions@instructure.com> Tested-by: Jenkins
This commit is contained in:
parent
2de0f345b2
commit
a3f3ec6e81
|
@ -0,0 +1,85 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require 'atom'
|
||||
|
||||
class ObserverAlertThresholdsApiController < ApplicationController
|
||||
include Api::V1::ObserverAlertThreshold
|
||||
|
||||
before_action :require_user
|
||||
|
||||
def index
|
||||
thresholds = if params[:student_id]
|
||||
student_id = params[:student_id]
|
||||
link = @current_user.as_observer_observation_links.active.where(student: student_id).take
|
||||
return render_unauthorized_action unless link
|
||||
link.observer_alert_thresholds.active
|
||||
else
|
||||
links = @current_user.as_observer_observation_links.active
|
||||
return render_unauthorized_action unless links.count > 0
|
||||
links.map { |uol| uol.observer_alert_thresholds.active }.flatten
|
||||
end
|
||||
|
||||
render json: thresholds.map { |threshold| observer_alert_threshold_json(threshold, @current_user, session) }
|
||||
end
|
||||
|
||||
def show
|
||||
threshold = ObserverAlertThreshold.active.find(params[:observer_alert_threshold_id])
|
||||
link = @current_user.as_observer_observation_links.select { |uol| uol.id == threshold.user_observation_link.id }
|
||||
return render_unauthorized_action unless link.count > 0
|
||||
render json: observer_alert_threshold_json(threshold, @current_user, session)
|
||||
end
|
||||
|
||||
def create
|
||||
student_id = params[:student_id]
|
||||
link = UserObservationLink.where(observer_id: @current_user, user_id: student_id).take
|
||||
return render_unauthorized_action unless link
|
||||
|
||||
attrs = create_params.merge(user_observation_link: link)
|
||||
begin
|
||||
threshold = link.observer_alert_thresholds.create(attrs)
|
||||
render json: observer_alert_threshold_json(threshold, @current_user, session)
|
||||
rescue ActiveRecord::NotNullViolation
|
||||
render :json => ['missing required parameters'], :status => :bad_request
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
threshold = ObserverAlertThreshold.active.find(params[:observer_alert_threshold_id])
|
||||
link = @current_user.as_observer_observation_links.select { |uol| uol.id == threshold.user_observation_link.id }
|
||||
return render_unauthorized_action unless link.count > 0
|
||||
threshold.update(update_params)
|
||||
render json: observer_alert_threshold_json(threshold.reload, @current_user, session)
|
||||
end
|
||||
|
||||
def destroy
|
||||
threshold = ObserverAlertThreshold.active.find(params[:observer_alert_threshold_id])
|
||||
link = @current_user.as_observer_observation_links.select { |uol| uol.id == threshold.user_observation_link.id }
|
||||
return render_unauthorized_action unless link.count > 0
|
||||
threshold.destroy
|
||||
render json: observer_alert_threshold_json(threshold, @current_user, session)
|
||||
end
|
||||
|
||||
def create_params
|
||||
params.require(:observer_alert_threshold).permit(:alert_type, :threshold)
|
||||
end
|
||||
|
||||
def update_params
|
||||
params.require(:observer_alert_threshold).permit(:threshold)
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class ObserverAlert < ActiveRecord::Base
|
||||
belongs_to :user_observation_link, :inverse_of => :observer_alert
|
||||
belongs_to :observer_alert_threshold
|
||||
belongs_to :user_observation_link, :inverse_of => :observer_alerts
|
||||
belongs_to :observer_alert_threshold, :inverse_of => :observer_alerts
|
||||
belongs_to :context, polymorphic: [:announcement, :assignment, :course, :account_notification]
|
||||
end
|
|
@ -16,5 +16,13 @@
|
|||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
class ObserverAlertThreshold < ActiveRecord::Base
|
||||
belongs_to :user_observation_link, :inverse_of => :observer_alert_threshold
|
||||
belongs_to :user_observation_link, :inverse_of => :observer_alert_thresholds
|
||||
has_many :observer_alerts, :inverse_of => :observer_alert_threshold
|
||||
|
||||
scope :active, -> { where.not(workflow_state: 'deleted') }
|
||||
|
||||
def destroy
|
||||
self.workflow_state = 'deleted'
|
||||
self.save!
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,8 +27,8 @@ class UserObservationLink < ActiveRecord::Base
|
|||
belongs_to :observer, :class_name => 'User', inverse_of: :as_observer_observation_links
|
||||
belongs_to :root_account, :class_name => 'Account'
|
||||
|
||||
has_many :observer_alert_threshold, :inverse_of => :user_observation_link
|
||||
has_many :observer_alert, :inverse_of => :user_observation_link
|
||||
has_many :observer_alert_thresholds, :inverse_of => :user_observation_link
|
||||
has_many :observer_alerts, :inverse_of => :user_observation_link
|
||||
|
||||
after_create :create_linked_enrollments
|
||||
|
||||
|
|
|
@ -1305,6 +1305,14 @@ CanvasRails::Application.routes.draw do
|
|||
put 'users/:user_id/observees/:observee_id', action: :update
|
||||
delete 'users/:user_id/observees/:observee_id', action: :destroy
|
||||
end
|
||||
|
||||
scope(controller: :observer_alert_thresholds_api) do
|
||||
get 'users/:user_id/observer_alert_thresholds', action: :index
|
||||
post 'users/:user_id/observer_alert_thresholds', action: :create
|
||||
get 'users/:user_id/observer_alert_thresholds/:observer_alert_threshold_id', action: :show
|
||||
put 'users/:user_id/observer_alert_thresholds/:observer_alert_threshold_id', action: :update
|
||||
delete 'users/:user_id/observer_alert_thresholds/:observer_alert_threshold_id', action: :destroy
|
||||
end
|
||||
end
|
||||
|
||||
scope(controller: :custom_data) do
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module Api::V1::ObserverAlertThreshold
|
||||
include Api::V1::Json
|
||||
include ApplicationHelper
|
||||
|
||||
API_ALLOWED_OUTPUT_FIELDS = {
|
||||
:only => %w(
|
||||
id
|
||||
user_observation_link_id
|
||||
alert_type
|
||||
threshold
|
||||
workflow_state
|
||||
).freeze
|
||||
}.freeze
|
||||
|
||||
def observer_alert_threshold_json(threshold, user, session, _opts = {})
|
||||
api_json(threshold, user, session, API_ALLOWED_OUTPUT_FIELDS)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,221 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
require_relative '../api_spec_helper'
|
||||
|
||||
describe ObserverAlertThresholdsApiController, type: :request do
|
||||
include Api
|
||||
include Api::V1::ObserverAlertThreshold
|
||||
|
||||
context '#index' do
|
||||
before :once do
|
||||
observer_alert_threshold_model(active_all: true, alert_type: 'missing_assignment')
|
||||
@path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds?student_id=#{@observee.id}"
|
||||
@params = {user_id: @observer.to_param, student_id: @observee.to_param,
|
||||
controller: 'observer_alert_thresholds_api', action: 'index', format: 'json'}
|
||||
end
|
||||
|
||||
describe 'with student_id' do
|
||||
it 'returns the thresholds' do
|
||||
json = api_call_as_user(@observer, :get, @path, @params)
|
||||
expect(json.length).to eq 1
|
||||
expect(json[0]['user_observation_link_id']).to eq @observation_link.id
|
||||
expect(json[0]['alert_type']).to eq 'missing_assignment'
|
||||
end
|
||||
|
||||
it 'only returns active thresholds' do
|
||||
to_destroy = @observation_link.observer_alert_thresholds.create(alert_type: 'assignment_grade_low')
|
||||
to_destroy.destroy!
|
||||
|
||||
json = api_call_as_user(@observer, :get, @path, @params)
|
||||
expect(json.length).to eq 1
|
||||
|
||||
thresholds = @observation_link.observer_alert_thresholds.reload
|
||||
expect(thresholds.count).to eq 2
|
||||
end
|
||||
|
||||
it 'errors without proper user_observation_link' do
|
||||
user = user_model
|
||||
path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds?student_id=#{user.id}"
|
||||
params = {user_id: @observer.to_param, student_id: user.to_param,
|
||||
controller: 'observer_alert_thresholds_api', action: 'index', format: 'json'}
|
||||
|
||||
api_call_as_user(@observer, :get, path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
end
|
||||
|
||||
describe 'without student_id' do
|
||||
it 'returns the thresholds' do
|
||||
link = UserObservationLink.create(observer_id: @observer, user_id: user_model)
|
||||
link.observer_alert_thresholds.create(alert_type: 'assignment_grade_high')
|
||||
|
||||
path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds"
|
||||
params = {user_id: @observer.to_param, controller: 'observer_alert_thresholds_api',
|
||||
action: 'index', format: 'json'}
|
||||
|
||||
json = api_call_as_user(@observer, :get, path, params)
|
||||
expect(json.length).to eq 2
|
||||
end
|
||||
|
||||
it 'errors without proper user_observation_link' do
|
||||
user = user_model
|
||||
path = "/api/v1/users/#{user.id}/observer_alert_thresholds"
|
||||
params = {user_id: user.to_param, controller: 'observer_alert_thresholds_api',
|
||||
action: 'index', format: 'json'}
|
||||
|
||||
api_call_as_user(user, :get, path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#show' do
|
||||
before :once do
|
||||
observer_alert_threshold_model(active_all: true, alert_type: 'missing_assignment')
|
||||
@path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds/#{@observer_alert_threshold.id}"
|
||||
@params = {user_id: @observer.to_param, observer_alert_threshold_id: @observer_alert_threshold.to_param,
|
||||
controller: 'observer_alert_thresholds_api', action: 'show', format: 'json'}
|
||||
end
|
||||
|
||||
it 'returns the threshold' do
|
||||
json = api_call_as_user(@observer, :get, @path, @params)
|
||||
expect(json['id']).to eq @observer_alert_threshold.id
|
||||
expect(json['user_observation_link_id']).to eq @observation_link.id
|
||||
expect(json['alert_type']).to eq 'missing_assignment'
|
||||
end
|
||||
|
||||
it 'errors without proper user_observation_link' do
|
||||
user = user_model
|
||||
path = "/api/v1/users/#{user.id}/observer_alert_thresholds/#{@observer_alert_threshold.id}"
|
||||
params = {user_id: user.to_param, observer_alert_threshold_id: @observer_alert_threshold.to_param,
|
||||
controller: 'observer_alert_thresholds_api', action: 'show', format: 'json'}
|
||||
|
||||
api_call_as_user(user, :get, path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
end
|
||||
|
||||
context '#create' do
|
||||
before :once do
|
||||
@observer = user_model
|
||||
@observee = user_model
|
||||
@uol = UserObservationLink.create(observer_id: @observer, user_id: @observee)
|
||||
@path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds"
|
||||
end
|
||||
|
||||
it 'creates the threshold' do
|
||||
create_params = {alert_type: 'assignment_grade_high', threshold: "88"}
|
||||
params = {user_id: @observer.to_param, student_id: @uol.user_id, observer_alert_threshold: create_params,
|
||||
controller: 'observer_alert_thresholds_api', action: 'create', format: 'json'}
|
||||
json = api_call_as_user(@observer, :post, @path, params)
|
||||
expect(json['alert_type']).to eq 'assignment_grade_high'
|
||||
expect(json['user_observation_link_id']).to eq @uol.id
|
||||
expect(json['threshold']).to eq "88"
|
||||
end
|
||||
|
||||
it 'errors with bad student_id' do
|
||||
create_params = {alert_type: 'assignment_grade_high', threshold: "88"}
|
||||
params = {user_id: @observer.to_param, student_id: @uol.user_id + 100, observer_alert_threshold: create_params,
|
||||
controller: 'observer_alert_thresholds_api', action: 'create', format: 'json'}
|
||||
api_call_as_user(@observer, :post, @path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
|
||||
it 'errors if user_observation_link doesnt belong to user' do
|
||||
user = user_model
|
||||
path = "/api/v1/users/#{user.id}/observer_alert_thresholds"
|
||||
create_params = {alert_type: 'assignment_grade_high', threshold: "88"}
|
||||
params = {user_id: user.to_param, student_id: @uol.user_id, observer_alert_threshold: create_params,
|
||||
controller: 'observer_alert_thresholds_api', action: 'create', format: 'json'}
|
||||
api_call_as_user(user, :post, path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
|
||||
it 'errors without required params' do
|
||||
create_params = {threshold: "88"}
|
||||
params = {user_id: @observer.to_param, student_id: @uol.user_id, observer_alert_threshold: create_params,
|
||||
controller: 'observer_alert_thresholds_api', action: 'create', format: 'json'}
|
||||
api_call_as_user(@observer, :post, @path, params)
|
||||
expect(response.code).to eq "400"
|
||||
end
|
||||
|
||||
it 'ignores improper params' do
|
||||
create_params = {something_sneaky: 'sneaky!', alert_type: 'assignment_grade_high', threshold: "88"}
|
||||
params = {user_id: @observer.to_param, student_id: @uol.user_id, observer_alert_threshold: create_params,
|
||||
controller: 'observer_alert_thresholds_api', action: 'create', format: 'json'}
|
||||
json = api_call_as_user(@observer, :post, @path, params)
|
||||
expect(response.code).to eq "200"
|
||||
expect(json['something_sneaky']).to eq nil
|
||||
end
|
||||
end
|
||||
|
||||
context '#update' do
|
||||
before :once do
|
||||
observer_alert_threshold_model(active_all: true, alert_type: 'assignment_grade_low', threshold: "88")
|
||||
@path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds/#{@observer_alert_threshold.id}"
|
||||
@params = {user_id: @observer.to_param, observer_alert_threshold_id: @observer_alert_threshold.to_param,
|
||||
controller: 'observer_alert_thresholds_api', action: 'update', format: 'json'}
|
||||
end
|
||||
|
||||
it 'updates the threshold' do
|
||||
update_params = {threshold: "50", alert_type: "assignment_missing",
|
||||
user_observation_link_id: @observation_link.id + 100}
|
||||
params = @params.merge({observer_alert_threshold: update_params})
|
||||
json = api_call_as_user(@observer, :put, @path, params)
|
||||
expect(json['alert_type']).to eq 'assignment_grade_low'
|
||||
expect(json['threshold']).to eq "50"
|
||||
expect(json['user_observation_link_id']).to eq @observation_link.id
|
||||
end
|
||||
|
||||
it 'errors without proper user_observation_link' do
|
||||
user = user_model
|
||||
path = "/api/v1/users/#{user.id}/observer_alert_thresholds/#{@observer_alert_threshold.id}"
|
||||
params = @params.merge({user_id: user.to_param, observer_alert_threshold: {threshold: "50"}})
|
||||
|
||||
api_call_as_user(user, :put, path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
end
|
||||
|
||||
context '#destroy' do
|
||||
before :once do
|
||||
observer_alert_threshold_model(active_all: true, alert_type: 'assignment_grade_low', threshold: "88")
|
||||
@path = "/api/v1/users/#{@observer.id}/observer_alert_thresholds/#{@observer_alert_threshold.id}"
|
||||
@params = {user_id: @observer.to_param, observer_alert_threshold_id: @observer_alert_threshold.to_param,
|
||||
controller: 'observer_alert_thresholds_api', action: 'destroy', format: 'json'}
|
||||
end
|
||||
|
||||
it 'destroys the threshold' do
|
||||
json = api_call_as_user(@observer, :delete, @path, @params)
|
||||
expect(json['id']).to eq @observer_alert_threshold.id
|
||||
|
||||
thresholds = @observation_link.observer_alert_thresholds.active.reload
|
||||
expect(thresholds.count).to eq 0
|
||||
end
|
||||
|
||||
it 'errors without proper user_observation_link' do
|
||||
user = user_model
|
||||
path = "/api/v1/users/#{user.id}/observer_alert_thresholds/#{@observer_alert_threshold.id}"
|
||||
params = @params.merge({user_id: user.to_param})
|
||||
|
||||
api_call_as_user(user, :delete, path, params)
|
||||
expect(response.code).to eq "401"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
module Factories
|
||||
def observer_alert_threshold_model(opts = {})
|
||||
@observee = opts[:observee] || course_with_student(opts).user
|
||||
@observer = opts[:observer] || user_model
|
||||
@observation_link = UserObservationLink.create!(user_id: @observee, observer_id: @observer)
|
||||
|
||||
attrs = default_attrs.merge(opts.slice(*valid_attrs_list))
|
||||
@observer_alert_threshold = @observation_link.observer_alert_thresholds.create(attrs)
|
||||
end
|
||||
|
||||
def default_attrs
|
||||
{
|
||||
alert_type: 'value for type',
|
||||
threshold: nil,
|
||||
workflow_state: 'active',
|
||||
}
|
||||
end
|
||||
|
||||
def valid_attrs_list
|
||||
[:alert_type, :threshold, :workflow_state]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,48 @@
|
|||
#
|
||||
# Copyright (C) 2018 - present Instructure, Inc.
|
||||
#
|
||||
# This file is part of Canvas.
|
||||
#
|
||||
# Canvas is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, version 3 of the License.
|
||||
#
|
||||
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require_relative '../../../spec_helper.rb'
|
||||
|
||||
class ObserverAlertThresholdApiHarness
|
||||
include Api::V1::ObserverAlertThreshold
|
||||
|
||||
def value_to_boolean(value)
|
||||
Canvas::Plugin.value_to_boolean(value)
|
||||
end
|
||||
|
||||
def session
|
||||
Object.new
|
||||
end
|
||||
end
|
||||
|
||||
describe "Api::V1::ObserverAlertThreshold" do
|
||||
subject(:api) { ObserverAlertThresholdApiHarness.new }
|
||||
|
||||
let(:observer_alert_threshold) { observer_alert_threshold_model(active_all: true) }
|
||||
|
||||
describe "#observer_alert_threshold_json" do
|
||||
let(:user) { user_model }
|
||||
let(:session) { Object.new }
|
||||
|
||||
it "returns json" do
|
||||
json = api.observer_alert_threshold_json(observer_alert_threshold, user, session)
|
||||
expect(json['alert_type']).to eq('value for type')
|
||||
expect(json['workflow_state']).to eq('active')
|
||||
expect(json['user_observation_link_id']).to eq @observation_link.id
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue