Skip to content

Commit

Permalink
Add originality report visibility settings
Browse files Browse the repository at this point in the history
Closes PLAT-2779

Test Plan:
- Create an assignment with a plagiarism detection tool
  associated. Set the 'Show originality report to students'
  to 'Never'.
- Create an originality report for a submission and
  verify it is not visible to the student on the submission
  details page or grades summary page. It should still be
  visible to the teacher.
- Edit the assignment and change the visibility option to
  'After the due date'. Also set the due date to a date/time
  in the past.
- Verify the originality report is now visible to the student in
  the submission details page and grade summary page (note that
  you may need to flush redis).
- Create a new assignment associated with a plagiarism detection
  tool and set the visibility option to 'After the assignment
  is graded'.
- Create a submission and an originality report.
- Verify that the student cannot view the originality report
  until the assignment has been graded by the teacher.
- Edit the assignment and change report visibility
  to Immediately. Verify that the student can still
  view the originality report.

Change-Id: I35a4e87275577b5b5d9cc0c1ce3501a5ae048a79
Reviewed-on: https://gerrit.instructure.com/123766
Reviewed-by: Andrew Butterfield <[email protected]>
QA-Review: August Thornton <[email protected]>
Tested-by: Jenkins
Product-Review: Jesse Poulos <[email protected]>
  • Loading branch information
westonkd committed Aug 30, 2017
1 parent 53c4757 commit cfd1295
Show file tree
Hide file tree
Showing 10 changed files with 237 additions and 9 deletions.
3 changes: 2 additions & 1 deletion app/coffeescripts/views/assignments/EditView.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ define [
parseInt(ENV.COURSE_ID),
@$secureParams.val(),
parseInt(ENV.SELECTED_CONFIG_TOOL_ID),
ENV.SELECTED_CONFIG_TOOL_TYPE)
ENV.SELECTED_CONFIG_TOOL_TYPE,
ENV.REPORT_VISIBILITY_SETTING)

@_attachEditorToDescription()
@addTinyMCEKeyboardShortcuts()
Expand Down
1 change: 1 addition & 0 deletions app/controllers/assignments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ def edit
selected_tool = @assignment.tool_settings_tool
hash[:SELECTED_CONFIG_TOOL_ID] = selected_tool ? selected_tool.id : nil
hash[:SELECTED_CONFIG_TOOL_TYPE] = selected_tool ? selected_tool.class.to_s : nil
hash[:REPORT_VISIBILITY_SETTING] = @assignment.turnitin_settings[:originality_report_visibility]

if @context.grading_periods?
hash[:active_grading_periods] = GradingPeriod.json_for(@context, @current_user)
Expand Down
19 changes: 14 additions & 5 deletions app/jsx/assignments/AssignmentConfigurationTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import PropTypes from 'prop-types'
import ReactDOM from 'react-dom'
import I18n from 'i18n!moderated_grading'
import 'compiled/jquery.rails_flash_notifications'
import OriginalityReportVisibilityPicker from './OriginalityReportVisibilityPicker'

const AssignmentConfigurationTools = React.createClass({
displayName: 'AssignmentConfigurationTools',
Expand All @@ -30,7 +31,8 @@ import 'compiled/jquery.rails_flash_notifications'
courseId: PropTypes.number.isRequired,
secureParams: PropTypes.string.isRequired,
selectedTool: PropTypes.number,
selectedToolType: PropTypes.string
selectedToolType: PropTypes.string,
visibilitySetting: PropTypes.string
},

componentWillMount() {
Expand All @@ -49,7 +51,8 @@ import 'compiled/jquery.rails_flash_notifications'
selectedToolValue: `${this.props.selectedToolType}_${this.props.selectedTool}`,
beforeExternalContentAlertClass: 'screenreader-only',
afterExternalContentAlertClass: 'screenreader-only',
iframeStyle: {}
iframeStyle: {},
visibilityEnabled: !!this.props.selectedTool
};
},

Expand Down Expand Up @@ -120,6 +123,7 @@ import 'compiled/jquery.rails_flash_notifications'
event.preventDefault();
this.setState({
selectedToolValue: event.target.value,
visibilityEnabled: event.target.value.toLowerCase().indexOf('none') === -1
}, () => this.setToolLaunchUrl());
},

Expand Down Expand Up @@ -156,7 +160,7 @@ import 'compiled/jquery.rails_flash_notifications'
ref={(c) => { this.similarityDetectionTool = c; }}
value={this.state.selectedToolValue}
>
<option title="Plagiarism Review Tool" data-launch="none">
<option title="Plagiarism Review Tool" data-launch="none" data-type="none">
None
</option>
{
Expand Down Expand Up @@ -244,20 +248,25 @@ import 'compiled/jquery.rails_flash_notifications'
{this.renderOptions()}
{this.renderToolType()}
{this.renderConfigTool()}
<OriginalityReportVisibilityPicker
isEnabled={ !!this.state.visibilityEnabled }
selectedOption={ this.props.visibilitySetting }
/>
</div>
</div>
</div>
)
}
});

const attach = function(element, courseId, secureParams, selectedTool, selectedToolType) {
const attach = function(element, courseId, secureParams, selectedTool, selectedToolType, visibilitySetting) {
const configTools = (
<AssignmentConfigurationTools
courseId ={courseId}
secureParams={secureParams}
selectedTool={selectedTool}
selectedToolType={selectedToolType}/>
selectedToolType={selectedToolType}
visibilitySetting={visibilitySetting} />
);
return ReactDOM.render(configTools, element);
};
Expand Down
77 changes: 77 additions & 0 deletions app/jsx/assignments/OriginalityReportVisibilityPicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (C) 2017 - 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/>.
*/

import React from 'react'
import PropTypes from 'prop-types'
import I18n from 'i18n!assignments'

export default class OriginalityReportVisibilityPicker extends React.Component {
static propTypes = {
isEnabled: PropTypes.bool.isRequired,
selectedOption: PropTypes.string
};

static defaultProps = {
selectedOption: null
};

constructor(props) {
super(props);
this.state = {
selectedOption: props.selectedOption
};
}

setSelectedOption = (e) => {
this.setState({selectedOption: e.target.value});
}

render() {
return (
<div>
<hr />
<label id="report_visibility_picker_label" htmlFor="report_visibility_picker_select">
{I18n.t('Show originality report to students')}
</label>
<div id="report_visibility_picker">
<select
id="report_visibility_picker_select"
name="report_visibility"
ref={(c) => { this.visibilityPicker = c; }}
disabled={!this.props.isEnabled}
value={this.state.selectedOption}
onChange={this.setSelectedOption}
>
<option title={I18n.t('Immediately')} value="immediate" >
{I18n.t('Immediately')}
</option>
<option title={I18n.t('After the assignment is graded')} value="after_grading">
{I18n.t('After the assignment is graded')}
</option>
<option title={I18n.t('After the due date')} value="after_due_date">
{I18n.t('After the due date')}
</option>
<option title={I18n.t('Never')} value="never">
{I18n.t('Never')}
</option>
</select>
</div>
</div>
);
}
}
3 changes: 3 additions & 0 deletions app/stylesheets/bundles/assignments_edit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ div.form-column-right, div.overrides-column-right {
}

#similarity_detection_tools .form-column-right {
#report_visibility_picker_label {
padding: 0px 0px 10px 17px !important;
}
padding-left: 4px;
iframe.tool_launch {
margin: 15px 0px 0px 0px;
Expand Down
5 changes: 5 additions & 0 deletions lib/api/v1/assignment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,11 @@ def apply_external_tool_settings(assignment, assignment_params)
if plagiarism_capable?(assignment_params)
tool = assignment_configuration_tool(assignment_params)
assignment.tool_settings_tool = tool
if assignment_params[:report_visibility].present?
settings = assignment.turnitin_settings
settings[:originality_report_visibility] = assignment_params[:report_visibility]
assignment.turnitin_settings = settings
end
end
end

Expand Down
14 changes: 14 additions & 0 deletions spec/apis/v1/assignments_api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,20 @@ def create_assignment_json(group, group_category)
expect(a.tool_settings_tool).to eq(tool)
end

it "does set the visibility settings" do
tool = @course.context_external_tools.create!(name: "a", url: "http://www.google.com", consumer_key: '12345', shared_secret: 'secret')
response = api_create_assignment_in_course(@course, {
'description' => 'description',
'similarityDetectionTool' => tool.id,
'configuration_tool_type' => 'ContextExternalTool',
'submission_type' => 'online',
'submission_types' => ['online_upload'],
'report_visibility' => 'after_grading'
})
a = Assignment.find response['id']
expect(a.turnitin_settings[:originality_report_visibility]).to eq('after_grading')
end

it "sets the configuration LTI 2 tool in account context" do
allow_any_instance_of(AssignmentConfigurationToolLookup).to receive(:create_subscription).and_return true
account = @course.account
Expand Down
6 changes: 6 additions & 0 deletions spec/controllers/assignments_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,12 @@ def course_assignment(course = nil)
expect(assigns[:js_env][:SELECTED_CONFIG_TOOL_TYPE]).to eq tool.class.to_s
end

it "bootstrap the assignment originality report visibility settings to js_env" do
user_session(@teacher)
get 'edit', params: {:course_id => @course.id, :id => @assignment.id}
expect(assigns[:js_env][:REPORT_VISIBILITY_SETTING]).to eq('immediate')
end

it "js_env DUE_DATE_REQUIRED_FOR_ACCOUNT is true when AssignmentUtil.due_date_required_for_account? == true" do
user_session(@teacher)
allow(AssignmentUtil).to receive(:due_date_required_for_account?).and_return(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ define([
ok(wrapper.find('option[data-launch="none"]').exists());
});

test('it renders empty string for tool type when no tool is selected', () => {
test('it renders "none" for tool type when no tool is selected', () => {
const wrapper = mount(
<AssignmentConfigurationTools.configTools
courseId={1}
Expand All @@ -147,7 +147,7 @@ define([
);
wrapper.setState({tools: toolDefinitions})
const toolType = wrapper.find('#configuration-tool-type').get(0);
equal(toolType.value, '');
equal(toolType.value, 'none');
});

test('it renders each tool', () => {
Expand All @@ -158,7 +158,7 @@ define([
/>
);
wrapper.setState({tools: toolDefinitions})
equal(wrapper.find('option').length, toolDefinitions.length + 1)
equal(wrapper.find('#similarity_detection_tool option').length, toolDefinitions.length + 1)
});

test('it builds the correct Launch URL for LTI 1 tools', () => {
Expand Down Expand Up @@ -299,4 +299,30 @@ define([
equal(wrapper.state().afterExternalContentAlertClass, 'screenreader-only')
deepEqual(wrapper.state().iframeStyle, {})
})

test('renders visibility options', () => {
const wrapper = mount(
<AssignmentConfigurationTools.configTools
courseId={1}
secureParams={secureParams}
selectedTool={5}
selectedToolType="ContextExternalTool"
/>
);
wrapper.setState({tools: toolDefinitions})
ok(wrapper.find('#report_visibility_picker'))
});

test('enables the visibility picker when a tool is selected', () => {
const wrapper = mount(
<AssignmentConfigurationTools.configTools
courseId={1}
secureParams={secureParams}
selectedTool={5}
selectedToolType="ContextExternalTool"
/>
);
wrapper.setState({tools: toolDefinitions})
ok(!wrapper.find('#report_visibility_picker').node.disabled)
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2017 - 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/>.
*/

import $ from 'jquery'
import React from 'react'
import { mount } from 'enzyme'
import OriginalityReportVisibilityPicker from 'jsx/assignments/OriginalityReportVisibilityPicker'

QUnit.module('OriginalityReportVisibilityPicker', {
setup () {}
});

test('it renders', () => {
const wrapper = mount(
<OriginalityReportVisibilityPicker
isEnabled={true}
selectedOption='immediate'
/>
);
ok(wrapper.exists());
});

test('it renders "immediate" option', () => {
const wrapper = mount(
<OriginalityReportVisibilityPicker
isEnabled={true}
selectedOption='immediate'
/>
);
ok(wrapper.find("option[value='immediate']"));
});

test('it renders "after_grading" option', () => {
const wrapper = mount(
<OriginalityReportVisibilityPicker
isEnabled={true}
selectedOption='immediate'
/>
);
ok(wrapper.find("option[value='after_grading']"));
});

test('it renders "after_due_date" option', () => {
const wrapper = mount(
<OriginalityReportVisibilityPicker
isEnabled={true}
selectedOption='immediate'
/>
);
ok(wrapper.find("option[value='after_due_date']"));
});

test('it renders "never" option', () => {
const wrapper = mount(
<OriginalityReportVisibilityPicker
isEnabled={true}
selectedOption='immediate'
/>
);
ok(wrapper.find("option[value='never']"));
});

test('it selects the "selectedOption"', () => {
const wrapper = mount(
<OriginalityReportVisibilityPicker
isEnabled={true}
selectedOption='after_due_date'
/>
);
ok(wrapper.find('#report_visibility_picker_select').node.value, 'after_due_date')
});

0 comments on commit cfd1295

Please sign in to comment.