add read_only to custom_gradebook_columns
Test Plan: 1 - Run the migrations and validate that the `read_only` column exists on the `custom_gradebook_columns` table, with a default of false 2 - Create a new CustomGradebookColumn through the API and validate that it accepts and persists the `read_only` parameter. Example curls: Create the column: curl -H "Authorization: Bearer <token>" \ http://localhost:3000/api/v1/courses/:id/custom_gradebook_columns \ -X POST \ -F "title=ReadOnly" \ -F "read_only=true" Validate the columns: curl -H "Authorization: Bearer <token>" \ http://localhost:3000/api/v1/courses/:id/custom_gradebook_columns/ 3 - Open the gradebook for a course and validate that you cannot edit the `read_only` columns in both the old and new gradebooks. (Tabbing should still work as normal.) 4 - Go to the Individual View. Under Global Settings, check Show Notes in Student Info. Under Content Selection, select a student. Confirm that you can only edit the custom columns that were not created as read_only. refs PFS-9913, PFS-9914, PFS-10003 Change-Id: I18005cc0eaf19202c00a5d79c2a04421b5d12a5c Reviewed-on: https://gerrit.instructure.com/139625 Reviewed-by: Keith T. Garner <kgarner@instructure.com> Reviewed-by: Jeremy Neander <jneander@instructure.com> Tested-by: Jenkins Product-Review: Ian Morris <ianm@instructure.com> QA-Review: Aiona Hernandez <ahernandez@instructure.com>
This commit is contained in:
parent
7aa3757cfa
commit
cbd207736b
|
@ -48,6 +48,10 @@ define [
|
|||
customColURL: ->
|
||||
ENV.GRADEBOOK_OPTIONS.custom_column_datum_url
|
||||
|
||||
disabled:(->
|
||||
@get('column.isLoading') || @get('column.read_only')
|
||||
).property('column', 'column.isLoading', 'column.read_only')
|
||||
|
||||
saveURL: (->
|
||||
@customColURL()
|
||||
.replace(/:id/, @get('column.id'))
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
value=value
|
||||
name=id
|
||||
id=id
|
||||
disabled=column.isLoading
|
||||
disabled=disabled
|
||||
class="span8"
|
||||
}}
|
||||
</div>
|
||||
|
|
|
@ -41,6 +41,8 @@ define [
|
|||
@column = Ember.Object.create
|
||||
id: '22'
|
||||
title: 'Notes'
|
||||
read_only: false
|
||||
is_loading: false
|
||||
@student = Ember.Object.create
|
||||
id: '45'
|
||||
@dataForStudent = [
|
||||
|
@ -69,6 +71,21 @@ define [
|
|||
test "saveUrl", ->
|
||||
equal @component.get('saveURL'), '/api/v1/custom_gradebook_columns/22/45'
|
||||
|
||||
test "disabled is true when column isLoading", ->
|
||||
@component.column.set('isLoading', true)
|
||||
@component.column.set('read_only', false)
|
||||
equal @component.get('disabled'), true
|
||||
|
||||
test "disabled is true when column is read_only", ->
|
||||
@component.column.set('isLoading', false)
|
||||
@component.column.set('read_only', true)
|
||||
equal @component.get('disabled'), true
|
||||
|
||||
test "disabled is false when column is not loading and not read_only", ->
|
||||
@component.column.set('isLoading', false)
|
||||
@component.column.set('read_only', false)
|
||||
equal @component.get('disabled'), false
|
||||
|
||||
test "focusOut", (assert) ->
|
||||
assert.expect(1)
|
||||
stub = @stub @component, 'boundSaveSuccess'
|
||||
|
|
|
@ -1323,15 +1323,20 @@ define [
|
|||
|
||||
customColumnDefinitions: ->
|
||||
@customColumns.map (c) ->
|
||||
id: "custom_col_#{c.id}"
|
||||
name: if c.teacher_notes then I18n.t('Notes') else htmlEscape c.title
|
||||
field: "custom_col_#{c.id}"
|
||||
width: 100
|
||||
cssClass: "meta-cell custom_column"
|
||||
resizable: true
|
||||
editor: LongTextEditor
|
||||
autoEdit: false
|
||||
maxLength: 255
|
||||
cssClasses = ["meta-cell", "custom_column"]
|
||||
cssClasses.push("cannot_edit") if c.read_only
|
||||
|
||||
{
|
||||
id: "custom_col_#{c.id}"
|
||||
name: if c.teacher_notes then I18n.t('Notes') else htmlEscape c.title
|
||||
field: "custom_col_#{c.id}"
|
||||
width: 100
|
||||
cssClass: cssClasses.join(" ")
|
||||
resizable: true
|
||||
editor: LongTextEditor
|
||||
autoEdit: false
|
||||
maxLength: 255
|
||||
}
|
||||
|
||||
initGrid: =>
|
||||
#this is used to figure out how wide to make each column
|
||||
|
|
|
@ -1679,6 +1679,8 @@ define [
|
|||
|
||||
# The target cell will enter editing mode
|
||||
onBeforeEditCell: (event, obj) =>
|
||||
if obj.column.type == 'custom_column' && @getCustomColumn(obj.column.customColumnId)?.read_only
|
||||
return false
|
||||
return true if obj.column.type != 'assignment'
|
||||
return false unless student = @student(obj.item.id)
|
||||
return false if student.isConcluded
|
||||
|
|
|
@ -50,6 +50,11 @@
|
|||
# "description": "won't be displayed if hidden is true",
|
||||
# "example": false,
|
||||
# "type": "boolean"
|
||||
# },
|
||||
# "read_only": {
|
||||
# "description": "won't be editable in the gradebook UI",
|
||||
# "example": true,
|
||||
# "type": "boolean"
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
|
@ -94,6 +99,8 @@ class CustomGradebookColumnsApiController < ApplicationController
|
|||
# @argument column[teacher_notes] [Boolean]
|
||||
# Set this if the column is created by a teacher. The gradebook only
|
||||
# supports one teacher_notes column.
|
||||
# @argument column[read_only] [Boolean]
|
||||
# Set this to prevent the column from being editable in the gradebook ui
|
||||
#
|
||||
# @returns CustomColumn
|
||||
def create
|
||||
|
@ -151,6 +158,6 @@ class CustomGradebookColumnsApiController < ApplicationController
|
|||
end
|
||||
|
||||
def column_params
|
||||
params.require(:column).permit(:title, :position, :teacher_notes, :hidden)
|
||||
params.require(:column).permit(:title, :position, :teacher_notes, :hidden, :read_only)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#
|
||||
# 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/>.
|
||||
|
||||
class AddReadonlyToCustomGradebookColumn < ActiveRecord::Migration[5.0]
|
||||
tag :predeploy
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_column :custom_gradebook_columns, :read_only, :boolean
|
||||
change_column_default :custom_gradebook_columns, :read_only, false
|
||||
DataFixup::BackfillNulls.run(CustomGradebookColumn, :read_only, default_value: false)
|
||||
change_column_null :custom_gradebook_columns, :read_only, false
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :custom_gradebook_columns, :read_only
|
||||
end
|
||||
end
|
|
@ -21,7 +21,7 @@ module Api::V1::CustomGradebookColumn
|
|||
|
||||
def custom_gradebook_column_json(column, user, session)
|
||||
json = api_json column, user, session, :only => %w(id title position
|
||||
teacher_notes)
|
||||
teacher_notes read_only)
|
||||
json[:hidden] = column.hidden?
|
||||
json
|
||||
end
|
||||
|
|
|
@ -97,7 +97,7 @@ describe CustomGradebookColumnsApiController, type: :request do
|
|||
"/api/v1/courses/#{@course.id}/custom_gradebook_columns",
|
||||
{course_id: @course.to_param, action: "create",
|
||||
controller: "custom_gradebook_columns_api", format: "json"},
|
||||
"column[title]" => "Blah blah blah", "column[position]" => 1
|
||||
"column[title]" => "Blah blah blah", "column[position]" => 1, "column[read_only]" => true
|
||||
expect(response).to be_success
|
||||
expect(CustomGradebookColumn.find(json["id"])).not_to be_nil
|
||||
end
|
||||
|
@ -122,9 +122,10 @@ describe CustomGradebookColumnsApiController, type: :request do
|
|||
"/api/v1/courses/#{@course.id}/custom_gradebook_columns/#{@col.id}",
|
||||
{course_id: @course.to_param, id: @col.to_param, action: "update",
|
||||
controller: "custom_gradebook_columns_api", format: "json"},
|
||||
"column[title]" => "Bar"
|
||||
"column[title]" => "Bar", "column[read_only]" => true
|
||||
expect(response).to be_success
|
||||
expect(json["title"]).to eq "Bar"
|
||||
expect(json["read_only"]).to eq(true)
|
||||
expect(@col.reload.title).to eq "Bar"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -399,6 +399,22 @@ test('It does not sort columns when gradebookColumnOrderSettings is undefined',
|
|||
notOk(this.makeColumnSortFn.called)
|
||||
})
|
||||
|
||||
QUnit.module('Gradebook#customColumnDefinitions', {
|
||||
setup() {
|
||||
this.gradebook = createGradebook()
|
||||
this.gradebook.customColumns = [
|
||||
{ id: '1', teacher_notes: false, hidden: false, title: 'Read Only', read_only: true },
|
||||
{ id: '2', teacher_notes: false, hidden: false, title: 'Not Read Only', read_only: false }
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
test('includes the cannot_edit class for read_only columns', function () {
|
||||
columns = this.gradebook.customColumnDefinitions()
|
||||
equal(columns[0].cssClass, "meta-cell custom_column cannot_edit")
|
||||
equal(columns[1].cssClass, "meta-cell custom_column")
|
||||
})
|
||||
|
||||
QUnit.module('Gradebook#fieldsToExcludeFromAssignments', {
|
||||
setup() {
|
||||
return (this.excludedFields = Gradebook.prototype.fieldsToExcludeFromAssignments)
|
||||
|
|
|
@ -4414,6 +4414,10 @@ QUnit.module('Gradebook Grid Events', () => {
|
|||
hooks.beforeEach(() => {
|
||||
gradebook = createGradebook();
|
||||
gradebook.initSubmissionStateMap();
|
||||
gradebook.gradebookContent.customColumns = [
|
||||
{ id: '1', teacher_notes: false, hidden: false, title: 'Read Only', read_only: true },
|
||||
{ id: '2', teacher_notes: false, hidden: false, title: 'Not Read Only', read_only: false }
|
||||
];
|
||||
gradebook.students = { 1101: { id: '1101', isConcluded: false } };
|
||||
eventObject = {
|
||||
column: { assignmentId: '2301', type: 'assignment' },
|
||||
|
@ -4452,6 +4456,11 @@ QUnit.module('Gradebook Grid Events', () => {
|
|||
eventObject.column = { type: 'custom_column' };
|
||||
strictEqual(gradebook.onBeforeEditCell(null, eventObject), true);
|
||||
});
|
||||
|
||||
test('returns false when the cell is read_only', () => {
|
||||
eventObject.column = { type: 'custom_column', customColumnId: '1' };
|
||||
strictEqual(gradebook.onBeforeEditCell(null, eventObject), false);
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.module('onColumnsResized', (hooks) => {
|
||||
|
|
|
@ -31,7 +31,7 @@ describe "Api::V1::CustomGradebookColumn" do
|
|||
|
||||
describe "custom_gradebook_column_json" do
|
||||
it "works" do
|
||||
json = @col.attributes.slice(*%w(id title position teacher_notes))
|
||||
json = @col.attributes.slice(*%w(id title position teacher_notes read_only))
|
||||
json["hidden"] = false
|
||||
expect(controller.custom_gradebook_column_json(@col, @teacher, nil)).to eq json
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue